Manipulations fondamentales sur les listes chaînées

Compréhension des structures de liste chaînée

Prenons un exemple de liste chaînée : let liste = [1, 2, 3, 4]

Dans cette structure, liste.val vaut 1, et liste.next correspond au nœud contenant [2, 3, 4] où liste.next.val vaut 2.

Construction d'une liste chaînée à partir d'un vecteur

Convertir les éléments d'un vecteur en une liste chaînée peut se faire de deux manières :

À partir d'un vecteur de pointeurs de nœuds

std::vector<listnode> noeuds;
ListNode* premier = noeuds[0];
ListNode* courant = premier;

for (int idx = 1; idx < noeuds.size(); idx++) {
    courant->suivant = noeuds[idx];
    courant = courant->suivant;
}
</listnode>

À partir d'un vecteur de valeurs

ListNode* tete = new ListNode(valeurs[0]);
ListNode* iterateur = tete;
for (int idx = 1; idx < valeurs.size(); idx++) {
    iterateur->suivant = new ListNode(valeurs[idx]);
    iterateur = iterateur->suivant;
}
return tete;

Conversion d'une liste chaînée en vecteur

std::vector<int> elements;
ListNode* noeudCourant = teteListe;
while (noeudCourant) {
    elements.push_back(noeudCourant->valeur);
    noeudCourant = noeudCourant->suivant;
}

Tri par sélection avec une liste chaînée

for (int passe = 0; passe < compteur - 1; passe++) {
    noeudPremier = tete;
    noeudSecond = noeudPremier->suivant;
    
    while (noeudSecond) {
        if (noeudPremier->valeur > noeudSecond->valeur) {
            int tempo = noeudSecond->valeur;
            noeudSecond->valeur = noeudPremier->valeur;
            noeudPremier->valeur = tempo;
        }
        noeudPremier = noeudSecond;
        if (noeudSecond->suivant) 
            noeudSecond = noeudSecond->suivant;
        else 
            break;
    }
}

Suppression des doublons consécutifs

while (courant->suivant) {
    if (courant->valeur == courant->suivant->valeur) {
        courant->suivant = courant->suivant->suivant;
    } else {
        courant = courant->suivant;
    }
}

Utilisation d'un nœud factice (sentinelle)

ListNode* sentinelle = new ListNode(0, teteListe);
// ... traitement ...
return sentinelle->suivant;

Vérificatino d'un palindrome

On peut stocker les valeurs dans un vecteur, créer une copie inversée, puis comparer les deux vecteurs.

Détection d'intersection de deux listes

En utilisant deux pointeurs parcourant alternativement les deux listes, ils finiront par se rencontrer au point d'intersection si elle existe.

Fusion de deux listes triées

// Fonction de découpe au milieu avec pointeurs rapide et lent
ListNode* decouperListe(ListNode* depart) {
    ListNode* lent = depart;
    ListNode* rapide = depart->suivant;
    
    while (rapide && rapide->suivant) {
        lent = lent->suivant;
        rapide = rapide->suivant->suivant;
    }
    
    ListNode* milieu = lent->suivant;
    lent->suivant = nullptr;
    return milieu;
}

// Fusion de deux listes triées
ListNode* fusionner(ListNode* listeA, ListNode* listeB) {
    ListNode* fauxNoeud = new ListNode();
    ListNode* pointeur = fauxNoeud;
    
    while (listeA && listeB) {
        if (listeA->valeur < listeB->valeur) {
            pointeur->suivant = listeA;
            listeA = listeA->suivant;
        } else {
            pointeur->suivant = listeB;
            listeB = listeB->suivant;
        }
        pointeur = pointeur->suivant;
    }
    
    pointeur->suivant = listeA ? listeA : listeB;
    ListNode* resultat = fauxNoeud->suivant;
    delete fauxNoeud;
    return resultat;
}

// Tri fusion récursif
ListNode* triListe(ListNode* tete) {
    if (!tete || !tete->suivant) return tete;
    
    ListNode* premierePartie = tete;
    ListNode* deuxiemePartie = decouperListe(tete);
    
    premierePartie = triListe(premierePartie);
    deuxiemePartie = triListe(deuxiemePartie);
    
    return fusionner(premierePartie, deuxiemePartie);
}

Insertion dans une liste circulaire triée

Noeud* parcours = tete;
while (parcours->suivant != tete) {
    if (parcours->valeur > parcours->suivant->valeur) {
        if (valeurInsertion <= parcours->suivant->valeur) break;
        if (valeurInsertion >= parcours->valeur) break;
    }
    if (parcours->valeur <= valeurInsertion && 
        parcours->suivant->valeur >= valeurInsertion) {
        break;
    }
    parcours = parcours->suivant;
}
parcours->suivant = new Noeud(valeurInsertion, parcours->suivant);

Étiquettes: liste chaînée structure de données algorithme de tri pointeurs programmation C++

Publié le 17 juillet à 18h33