Tri de la liste liée

LOGO  

Tri de la liste liée

 

Titre:
Tri de la liste liée
La langue:
C
Auteur:
Philip J. Erdelsky

Rendez-vous amoureux:
31 juillet 1998
Usage:
Domaine public; aucune restriction d’utilisation
Portabilité:
Tout compilateur C
Mots clés:
Liste liée, tri
Abstrait:
Fonction AC pour trier une liste liée en mémoire, en utilisant une fonction de comparaison arbitraire et un algorithme de fusion de bande, qui est O (n log n) dans tous les cas. La fonction est non récursive et re-entrant, et ne change que les liens.

Les listes liées et les routines de tri sont très courantes dans la programmation.

La fonction sort_linked_list () va trier virtuellement tout type de liste unidirectionnelle, en utilisant une fonction de comparaison fournie par le programme appelant. Il a les avantages suivants par rapport à qsort ():

  1. Il trie les éléments de taille variable.
  2. Il nécessite des comparaisons O (n log n), quel que soit l’ordre initial. Le moment de trier une liste est prévisible et cohérent. Cette performance est connue pour être optimale pour les sortes générales.
  3. L’algorithme est itératif, pas récursif, donc il n’y a pas de problème de dépassement de pile. L’exigence de la pile est prévisible, cohérente et petite.
  4. Il trie la liste liée en changeant les pointeurs, pas en déplaçant les éléments eux-mêmes.
  5. Il peut trier une liste trop grande pour tenir dans un tableau.

La fonction trie uniquement les listes liées individuellement. Si une liste est doublement liée, les pointeurs arrière peuvent être restaurés après le tri par quelques lignes de code.

Chaque élément d’une liste chaînée à trier doit contenir, en tant que premiers membres, un ou plusieurs pointeurs. L’un des pointeurs, qui doit être dans la même position relative dans chaque élément, est un pointeur vers l’élément suivant. Ce pointeur est NULL dans le dernier élément.

L’index est la position de ce pointeur dans chaque élément. C’est 0 pour le premier pointeur, 1 pour le second pointeur, etc.

Soit compare () une fonction de comparaison qui compare deux éléments comme suit:

     n = comparer (p, q, pointeur);

     void * p, * q; pointeurs vers deux éléments de liste

     void * pointeur; pointeur défini par l'utilisateur transmis à compare () par
                     linked_list_sort ()

     int n; résultat de la comparaison * p et * q
                       > 0 si * p doit être après * q dans l'ordre trié
                       <0 si * p doit être avant * q dans l'ordre trié
                        0 si l'ordre de * p et * q n'est pas pertinent

Laissez “first” être un pointeur sur le premier élément de la liste. Ensuite, l’appel de fonction suivant trie la liste et renvoie un pointeur vers le premier élément de la liste triée:

     first_sorted =
       sort_linked_list (premier, index, compare, pointeur, pcount);

Le quatrième argument (pointeur) est passé à compare () sans changement. L’exemple donné ici n’utilise pas le pointeur. Cependant, cela peut être une caractéristique inestimable si deux méthodes de comparaison ou plus partagent une quantité substantielle de code et ne diffèrent que par une ou plusieurs valeurs de paramètres.

Le dernier argument (pcount) est de type (unsigned long *). Si ce n’est pas NULL, alors * pcount est égal au nombre d’enregistrements dans la liste.

Il est permis de trier une liste vide. Si d’abord == NULL, la valeur retournée sera également NULL.

Par exemple, un élément peut contenir à la fois un nom et un nombre:

    élément struct
    {
      struct element * next_in_alphabetical_order;
      struct element * next_in_numerical_order;
      nom de caractère [9];
      nombre entier;
      / * autres membres, le cas échéant * /
    }

Initialement, les deux pointeurs dans chaque élément sont identiques, et la liste est dans un ordre arbitraire, où “first” est un pointeur sur le premier élément. Les deux appels de fonction suivants trient deux fois la liste:

    first_in_alphabetical_order =
      sort_linked_list (first, 0, compare_names, NULL);
    first_in_numerical_order =
      sort_linked_list (first, 1, compare_numbers, NULL);

Voici les fonctions de comparaison:

    int compare_names (struct élément * p, struct élément * q,
      void * pointeur)
    {
      retourne strcmp (p-> nom, q-> nom);
    }

    int compare_numbers (struct élément * p, struct élément * q,
      void * pointeur)
    {
      retour p-> numéro> q-> nombre? 1: -1;
      / * NOTE: retourner p-> nombre - q-> nombre suffira s'il y a
      pas de danger de débordement numérique * /
    }

Une version antérieure de ce type, publiée dans un journal technique, exigeait que le lien aller soit au début de chaque élément. Bien que cela rende le type un peu plus efficace, il est également difficile à utiliser avec des listes à liens multiples.

L’algorithme est assez simple. La liste chaînée (appelée “bande” par analogie aux vieilles bandes magnétiques) est d’abord divisée en deux bandes de même taille ou presque de la même taille. Ceci est fait en “écrivant” des éléments sur les deux bandes alternativement.

Les deux bandes sont ensuite fusionnées, élément par élément, en blocs triés contenant chacun deux éléments. Les blocs sont écrits alternativement sur deux autres bandes.

Les deux bandes sont ensuite fusionnées, bloc par bloc, en blocs triés de quatre éléments chacun, et les blocs sont écrits alternativement sur deux autres bandes.

Le processus se poursuit, en doublant la taille du bloc à chaque fois, jusqu’à ce que tous les éléments soient dans un seul bloc trié sur une bande. La fonction renvoie un pointeur sur le premier élément de cette bande.

Chaque fusion nécessite des comparaisons O (n), où n est le nombre d’éléments. Le nombre de fusions est O (log n). Par conséquent, le tri complet prend des comparaisons O (n log n).

La fonction sort_linked_list () est réentrante si la fonction de comparaison est réentrante.

Les amateurs seront heureux de savoir que cet algorithme ne peut pas être facilement codé dans Ada ou Pascal car il repose sur des typecasts.

La fonction sort_linked_list () peut être appelée facilement à partir d’un programme C ++ avec un minimum de vérification de type si le fichier d’en-tête LLMSORT.H est inclus. Il contient un modèle pour la génération en ligne d’un appel sur sort_linked_list (). Le format de l’appel est le suivant:

     #include "llmsort.h"

     first_sorted = sort_list (premier, compare, pointer, pcount);

     yourclass * d'abord;
     yourclass * first_sorted;
     void * pointeur;
     non signé long * pcount;

La fonction compare () est appelée comme suit:

     n = comparer (p, q, pointeur);
     const yourclass * p;
     const yourclass * q;
     void * pointeur;
     int n;

Ici “yourclass” est n’importe quelle classe que vous pouvez définir. Le compilateur vérifie la cohérence des types d’argument et génère l’appel approprié sur sort_linked_list ().

Code source au format texte:

 

Source: http://www.efgh.com/software/llmsort.htm

 

Leave a Reply

Your email address will not be published. Required fields are marked *