web-dev-qa-db-fra.com

Quel algorithme de tri fonctionne le mieux sur la plupart des données triées?

Quel algorithme de tri fonctionne le mieux sur la plupart des données triées?

166
graphics

Basé sur la méthode très scientifique de surveillance gifs animés Je dirais que les types Insertion et Bulles sont de bons candidats.

251
Tom Ritter

Seulement quelques articles => INSERTION SORT

Les articles sont pour la plupart déjà triés => INSERTION SORT

Préoccupé par les pires scénarios => HEAP SORT

Intéressé par un bon résultat de cas moyen => QUICKSORT

Les articles sont tirés d'un univers dense => BUCKET SORT

Envie d'écrire le moins de code possible => INSERTION SORT

103
Jiaji Li

timsort

Timsort est "une fusion adaptative, stable et naturelle" avec " performances surnaturelles sur de nombreux types de tableaux partiellement ordonnés (inférieur à lg (N!) comparaisons nécessaires, et aussi peu que N-1) ". La sort() intégrée à Python utilise cet algorithme depuis un certain temps, avec apparemment de bons résultats. Il est spécialement conçu pour détecter et exploiter les sous-séquences partiellement triées dans l'entrée, qui se produisent souvent dans des jeux de données réels. Dans le monde réel, les comparaisons coûtent beaucoup plus cher que l’échange d’éléments dans une liste, puisqu’on échange généralement des pointeurs, ce qui fait très souvent de l’essentiel le choix de timsort. Toutefois, si vous savez que vos comparaisons sont toujours très économiques (écrire un programme jouet pour trier des entiers 32 bits, par exemple), il existe d’autres algorithmes susceptibles de donner de meilleurs résultats. Le moyen le plus simple de tirer parti de timsort est bien sûr d'utiliser Python, mais puisque Python est une source ouverte, vous pourrez également emprunter le code. Sinon, la description ci-dessus contient plus de détails que suffisants. écrire votre propre implémentation.

30
zaphod

Tri par insertion avec le comportement suivant:

  1. Pour chaque élément k dans les emplacements 1..n, vérifie d’abord si el[k] >= el[k-1]. Si c'est le cas, passez à l'élément suivant. (Évitez évidemment le premier élément.)
  2. Sinon, utilisez la recherche binaire dans les éléments 1..k-1 pour déterminer l'emplacement d'insertion, puis balayez les éléments. (Vous ne pouvez le faire que si k>TT est une valeur de seuil; avec petit k c’est exagéré.)

Cette méthode fait le moins de comparaisons possible.

19
Jason Cohen

Essayez le tri introspectif. http://en.wikipedia.org/wiki/Introsort

Il est basé sur le tri rapide, mais il évite le pire comportement que le tri rapide a pour des listes presque triées.

Le truc, c'est que cet algorithme de tri détecte les cas où le tri rapide passe en mode pire des cas et passe au tri par tas ou par fusion. Les partitions presque triées sont détectées par une méthode de partition non naïive et les petites partitions sont gérées à l'aide du tri par insertion.

Vous obtenez le meilleur de tous les principaux algorithmes de tri pour le coût d'un code plus complexe et plus complexe. Et vous pouvez être sûr que vous ne rencontrerez jamais le pire des cas. comportement, peu importe à quoi ressemblent vos données.

Si vous êtes un programmeur C++, vérifiez votre algorithme std :: sort. Il peut déjà utiliser le tri introspectif en interne.

11
Nils Pipenbrinck

Splaysort est une méthode de tri obscure basée sur splay arbres , un type d'arborescence binaire adaptative. Splaysort est utile non seulement pour les données partiellement triées, mais également pour les données partiellement triées de manière inversée, ou même pour toutes les données ayant un type d'ordre préexistant. C’est O(nlogn) dans le cas général, et O(n) dans le cas où les données sont triées d’une manière ou d’une autre (forward, reverse, orgue, etc.).

Son grand avantage par rapport au tri par insertion est qu'il ne revient pas au comportement O (n ^ 2) lorsque les données ne sont pas triées du tout. Vous n'avez donc pas besoin d'être absolument sûr que les données sont partiellement triées avant de les utiliser. .

Son inconvénient réside dans l'encombrement supplémentaire de la structure d'arborescence d'évolution dont il a besoin, ainsi que dans le temps nécessaire à la création et à la destruction de l'arborescence d'évolution. Toutefois, en fonction de la taille des données et de la quantité de tri préalable que vous attendez, les frais généraux peuvent en valoir la peine, car ils permettent d’accroître la vitesse.

Un article sur splaysort a été publié dans Software - Practice & Experience.

7
TimB

insertion ou sorte de coquille!

5
ninesided

Le smoothsort de Dijkstra est un excellent moyen de tri sur des données déjà triées. Il s’agit d’une variante d’axe de cadrage qui s’exécute dans le cas le plus défavorable avec O (n lg n) et O(n) dans le meilleur des cas. I a écrit une analyse de l’algorithme, dans Si vous êtes curieux de savoir comment cela fonctionne.

Natural mergesort est un autre très bon choix: il s’agit d’une variante bottom-up de mergesort qui traite l’entrée comme la concaténation de plusieurs plages triées différentes, puis utilise l’algorithme de fusion pour les associer. Vous répétez ce processus jusqu'à ce que toute la plage d'entrée soit triée. Ceci s'exécute dans O(n) fois si les données sont déjà triées et dans le pire des cas pour O (n lg n). C'est très élégant, bien qu'en pratique, il ne soit pas aussi bon que d'autres tris adaptatifs comme Timsort ou smoothsort.

5
templatetypedef

Si les éléments sont déjà triés ou s’il n’ya que peu d’éléments, ce serait un cas d’utilisation idéal pour le tri par insertion!

4
Roger

Le tri par insertion prend du temps O (n + le nombre d'inversions).

Une inversion est une paire (i, j) Telle que i < j && a[i] > a[j]. C'est-à-dire une paire en panne.

Une mesure de "presque trié" est le nombre d'inversions - on pourrait prendre "données presque triées" pour désigner des données avec peu d'inversions. Si l'on sait que le nombre d'inversions est linéaire (par exemple, vous venez d'ajouter des éléments O(1) à une liste triée), le tri par insertion prend O(n) temps.

3
Jonas Kölker

Je ne vais pas prétendre avoir toutes les réponses ici, car je pense que pour obtenir les réponses réelles, il peut être nécessaire de coder les algorithmes et de les profiler à l'aide d'échantillons de données représentatifs. Mais j'ai réfléchi à cette question toute la soirée et voici ce qui m’est arrivé jusqu’à présent, et quelques suppositions sur ce qui fonctionne le mieux là où.

Soit N le nombre total d’éléments, M le nombre de pièces en panne.

Le tri à bulles devra faire quelque chose comme 2 * M + 1 passe à travers tous les N articles. Si M est très petit (0, 1, 2?), Je pense que ce sera très difficile à battre.

Si M est petit (disons inférieur à log N), le tri par insertion aura des performances moyennes excellentes. Cependant, à moins d'un truc que je ne vois pas, il y aura une très mauvaise performance. (D'accord? Si le dernier élément de la commande vient en premier, vous devez alors insérer chaque élément, ce qui, selon moi, tue la performance.) Je suppose qu'il existe un algorithme de tri plus fiable pour cela. cas, mais je ne sais pas ce que c'est.

Si M est plus grand (égal ou supérieur à log N), le tri introspectif est certainement le meilleur.

Exception à tout cela: si vous savez à l'avance quels éléments ne sont pas triés, votre meilleur choix sera d'extraire ces éléments, de les trier selon un tri introspectif et de fusionner les deux listes triées en une liste triée. Si vous pouviez rapidement déterminer quels articles sont hors d'usage, ce serait également une bonne solution générale - mais je n'ai pas été en mesure de trouver un moyen simple de le faire.

Réflexions supplémentaires (pendant la nuit): Si M + 1 <N/M, vous pouvez alors parcourir la liste à la recherche d’une suite de N/M triée, puis étendre cette exécution dans un sens ou dans l’autre pour rechercher le point mort. -Items commandés. Cela prendra au plus 2N comparaisons. Vous pouvez ensuite trier les éléments non triés et procéder à une fusion triée des deux listes. Les comparaisons totales devraient moins que quelque chose comme 4N + M log2 (M), ce qui va battre toute routine de tri non spécialisée, je pense. (Même plus loin pensé: c'est plus compliqué que je pensais, mais je pense toujours que c'est raisonnablement possible.)

Une autre interprétation de la question est qu'il peut y avoir beaucoup de points en désordre, mais ils sont très proches de l'endroit où ils devraient figurer dans la liste. (Imaginez commencer avec une liste triée et échanger tous les autres éléments avec celui qui le suit.) Dans ce cas, je pense que le tri à bulle fonctionne très bien - je pense que le nombre de passages sera proportionnel au nombre de passages les plus éloignés. est. Le tri par insertion fonctionnera mal car chaque élément hors service déclenchera une insertion. Je soupçonne que le type introspectif ou quelque chose comme ça marchera bien aussi.

2
Sol

Comme tout le monde l'a dit, faites attention au naïf Quicksort - cela peut avoir une performance de O (N ^ 2) sur des données triées ou presque triées. Néanmoins, avec un algorithme approprié pour le choix du pivot (aléatoire ou médiane sur trois - voir Choisir un pivot pour Quicksort ), Quicksort fonctionnera toujours correctement.

En général, il est difficile de choisir des algorithmes tels que le tri par insertion pour déterminer quand les données sont suffisamment en désordre afin que Quicksort soit vraiment plus rapide.

2
Jonathan Leffler

Cette belle collection d’algorithmes de tri à cet effet dans les réponses semble manquer Gnome Sort , ce qui conviendrait également, et nécessite probablement le moins d’effort de mise en œuvre.

1
haraldkl

Si vous avez besoin d'une implémentation spécifique pour le tri des algorithmes, des structures de données ou tout ce qui a un lien avec ce qui précède, puis-je vous recommander l'excellent projet "Data Structures and Algorithms" sur CodePlex?

Il aura tout ce dont vous avez besoin sans réinventer la roue.

Juste mon petit grain de sel.

1
Maxime Rouiller

Le type à bulle est définitivement le gagnant. Le prochain sur le radar serait le type à insertion.

0
vCillusion

Le tri par bulles (ou, plus sûr encore, le tri par bulles bidirectionnel) est probablement idéal pour les listes généralement triées, bien que je parie qu'un tri par peigne modifié (avec une taille de jeu initiale beaucoup plus petite) serait un peu plus rapide lorsque la liste était vide. t tout aussi parfaitement triés. Le tri des peignes se dégrade en type à bulles.

0
Brian

cela dépend du cas d'utilisation. Si vous savez quels éléments sont modifiés, supprimer et insérer sera le meilleur des cas en ce qui me concerne.

0
Helin Wang

Le tri par insertion est le meilleur des cas O(n) sur une entrée triée. Et il est très proche de la plupart des entrées triées (mieux qu'un tri rapide).

0
jjnguy

méditer Essayez Heap. Je crois que c'est la plus cohérente des sortes O (n lg n).

0
Paul Nathan