Quels sont les cas d'utilisation où un algorithme de tri particulier est préféré aux autres - tri par fusion vs QuickSort vs heapsort vs 'intro sort', etc.?
Existe-t-il un guide recommandé pour leur utilisation en fonction de la taille, du type de structure de données, de la mémoire et du cache disponibles et des performances du processeur?
Réponses:
Tout d'abord, une définition, car c'est assez important: un tri stable est celui qui garantit de ne pas réorganiser les éléments avec des clés identiques.
Recommandations:
Tri rapide: lorsque vous n'avez pas besoin d'un tri stable et que les performances moyennes des cas sont plus importantes que les pires performances. Un tri rapide est O (N log N) en moyenne, O (N ^ 2) dans le pire des cas. Une bonne implémentation utilise le stockage auxiliaire O (log N) sous la forme d'espace de pile pour la récursivité.
Tri par fusion: lorsque vous avez besoin d'un tri stable, O (N log N), il s'agit de votre seule option. Le seul inconvénient est qu'il utilise l'espace auxiliaire O (N) et a une constante légèrement plus grande qu'un tri rapide. Il existe des types de fusion sur place, mais AFAIK ils ne sont pas tous stables ou pires que O (N log N). Même les tris O (N log N) en place ont une constante tellement plus grande que l'ancien tri de fusion simple qu'ils sont plus des curiosités théoriques que des algorithmes utiles.
Tri en tas: lorsque vous n'avez pas besoin d'un tri stable et que vous vous souciez plus des performances des pires cas que des performances moyennes des cas. Il est garanti qu'il est O (N log N) et utilise l'espace auxiliaire O (1), ce qui signifie que vous ne manquerez pas inopinément d'espace de tas ou de pile sur de très grandes entrées.
Introsort: Il s'agit d'un tri rapide qui passe à un tri de tas après une certaine profondeur de récursivité pour contourner le pire des cas O (N ^ 2) du tri rapide. C'est presque toujours mieux qu'un simple tri rapide, car vous obtenez le cas moyen d'un tri rapide, avec des performances garanties O (N log N). La seule raison d'utiliser un tri de tas au lieu de cela est probablement dans les systèmes à forte contrainte de mémoire où l'espace de pile O (log N) est pratiquement significatif.
Tri par insertion : lorsque N est garanti petit, y compris comme cas de base d'un tri rapide ou d'un tri par fusion. Bien que ce soit O (N ^ 2), il a une très petite constante et est un tri stable.
Tri par bulles, tri par sélection : lorsque vous faites quelque chose de rapide et de sale et pour une raison quelconque, vous ne pouvez pas simplement utiliser l'algorithme de tri de la bibliothèque standard. Le seul avantage de ceux-ci par rapport au tri par insertion est d'être légèrement plus facile à mettre en œuvre.
Tris sans comparaison: dans certaines conditions assez limitées, il est possible de briser la barrière O (N log N) et de trier en O (N). Voici quelques cas où cela vaut la peine d'essayer:
Tri par comptage: lorsque vous triez des entiers avec une plage limitée.
Tri par radix: lorsque log (N) est nettement plus grand que K, où K est le nombre de chiffres de base.
Tri par compartiment: lorsque vous pouvez garantir que votre entrée est distribuée à peu près uniformément.
la source
Quicksort est généralement le plus rapide en moyenne, mais il a des comportements assez désagréables dans le pire des cas. Donc, si vous devez garantir qu'aucune mauvaise donnée ne vous donne
O(N^2)
, vous devez l'éviter.Le tri par fusion utilise de la mémoire supplémentaire, mais est particulièrement adapté au tri externe (c'est-à-dire aux fichiers volumineux qui ne rentrent pas dans la mémoire).
Le tri en tas peut trier sur place et n'a pas le pire comportement quadratique, mais il est en moyenne plus lent que le tri rapide dans la plupart des cas.
Là où seuls des entiers dans une plage restreinte sont impliqués, vous pouvez utiliser une sorte de tri de base pour le rendre très rapide.
Dans 99% des cas, vous serez d'accord avec les types de bibliothèques, qui sont généralement basés sur un tri rapide.
la source
La page Wikipédia sur les algorithmes de tri propose un excellent tableau de comparaison.
http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms
la source
Ce que les liens fournis vers des comparaisons / animations ne prennent pas en compte, c'est lorsque la quantité de données dépasse la mémoire disponible - à quel point le nombre de passages sur les données, c'est-à-dire les coûts d'E / S, domine le temps d'exécution. Si vous avez besoin de faire cela, lisez sur le "tri externe" qui couvre généralement les variantes des tris de fusion et de tas.
http://corte.si/posts/code/visualisingsorting/index.html et http://corte.si/posts/code/timsort/index.html ont également quelques images sympas comparant divers algorithmes de tri.
la source
@dsimcha a écrit: Tri de comptage: lorsque vous triez des entiers avec une plage limitée
Je changerais cela en:
Tri par comptage: Lorsque vous triez des entiers positifs (0 - Integer.MAX_VALUE-2 en raison du casier).
Vous pouvez toujours obtenir les valeurs max et min comme heuristique d'efficacité en temps linéaire.
Vous avez également besoin d'au moins n espace supplémentaire pour le tableau intermédiaire et il est évidemment stable.
(même si cela permet en fait MAX_VALUE-2) voir: Les tableaux Java ont-ils une taille maximale?
J'expliquerais également que la complexité du tri de base est O (wn) pour n clés qui sont des entiers de taille de mot w. Parfois, w est présenté comme une constante, ce qui rendrait le tri de base meilleur (pour n suffisamment grand) que les meilleurs algorithmes de tri basés sur des comparaisons, qui effectuent tous des comparaisons O (n log n) pour trier n clés. Cependant, en général, w ne peut pas être considéré comme une constante: si toutes les n clés sont distinctes, alors w doit être au moins log n pour qu'une machine à accès aléatoire puisse les stocker en mémoire, ce qui donne au mieux une complexité temporelle O (n log n). (de wikipedia)
la source