Article de reference

Shellsort

2 ) (worst known worst case gap sequence) O(''n'' log 2 ''n'') (best known worst case gap sequence) {{Cite book |last=Pratt |first=Vaughan Ronald |author-link=Vaughan Ronald Pra...

Échange de paires d'éléments lors des étapes successives du tri Shellsort avec des écarts de 5, 3, 1

Le tri Shell , également appelé tri de Shell ou méthode de Shell , est un tri par comparaison en place . Il peut être considéré comme une généralisation du tri par échange ( tri à bulles ) ou du tri par insertion ( tri par insertion ). La méthode commence par trier les paires d'éléments éloignés les uns des autres, puis réduit progressivement l'écart entre les éléments à comparer. En commençant par des éléments éloignés, elle permet de repositionner plus rapidement certains éléments mal placés qu'un simple échange entre plus proches voisins. Le temps d'exécution du tri Shell dépend fortement de la séquence d'écart utilisée. Pour de nombreuses variantes pratiques, la détermination de leur complexité temporelle reste un problème ouvert .

L'algorithme a été publié pour la première fois par Donald Shell en 1959 et n'a rien à voir avec les coquillages.

tri par insertion qui permet l'échange d'éléments éloignés les uns des autres. L'idée est d'organiser la liste d'éléments de sorte que, quel que soit leur emplacement initial, le tri de chaque h -ième élément produise une liste triée. On dit alors que la liste est h -triée. On peut aussi la concevoir comme h listes entrelacées, chacune triée individuellement. Commencer avec des valeurs élevées de h permet aux éléments de se déplacer sur de longues distances dans la liste originale, réduisant ainsi rapidement le désordre et allégeant le travail des étapes de tri h suivantes. Si la liste est ensuite triée par k pour un entier k plus petit , elle reste h -triée. Un tri final avec h = 1 garantit que la liste est entièrement triée à la fin, mais une séquence décroissante judicieusement choisie pour les valeurs de h réduit considérablement le travail à effectuer lors de cette dernière étape.

En termes simples, cela signifie que si nous avons un tableau de 1024 nombres, notre premier intervalle ( h ) pourrait être de 512. Nous parcourons ensuite la liste en comparant chaque élément de la première moitié à celui de la seconde moitié. Notre deuxième intervalle ( k ) est de 256, ce qui divise le tableau en quatre sections (de 0 à 768). Nous nous assurons que les premiers éléments de chaque section sont triés les uns par rapport aux autres, puis les seconds, et ainsi de suite. En pratique, la séquence des intervalles peut être quelconque, mais le dernier intervalle est toujours de 1 pour terminer le tri (ce qui revient à un tri par insertion classique).

Un exemple d'exécution de Shellsort avec des écarts de 5, 3 et 1 est présenté ci-dessous.

au tri par insertion , le tri Shellsort n'est pas stable car les insertions avec intervalles déplacent des éléments identiques les uns devant les autres, ce qui entraîne une perte de leur ordre initial. C'est un algorithme de tri adaptatif : son exécution est plus rapide lorsque les données d'entrée sont partiellement triées.

Exemple

Voici un exemple en C# utilisant la séquence d'espacement de Marcin Ciura, avec un tri par insertion interne.

OEISTerme général ( k ≥ 1 )fissures dans le bétonComplexité temporelle dans le pire des casAuteur et année de publication
Shell , 1959
Frank & Lazarus, 1960
Hibbard , 1963
Papernov et Stasevitch, 1965
3- nombres réguliers)Pratt , 1971
Knuth , 1973, basé sur Pratt , 1971
Incerpi & Sedgewick , 1985, Knuth
Sedgewick, 1982
Sedgewick, 1986
Gonnet et réseaux de tri et a la même complexité de porte asymptotique que le trieur bitonique de Batcher .

Gonnet et Baeza-Yates ont observé que Shellsort effectue en moyenne le moins de comparaisons lorsque les rapports entre les intervalles successifs sont approximativement égaux à 2,2 . C'est pourquoi leur séquence avec un rapport de 2,2 et celle de Tokuda avec un rapport de 2,25 s'avèrent efficaces. Cependant, la raison de cette efficacité reste inconnue. Sedgewick recommande d'utiliser des intervalles dont le plus grand commun diviseur est faible ou qui sont premiers entre eux deux à deux . L'utilisation d'intervalles impairs semble être bénéfique : des gains de vitesse d'environ 25 % ont été observés en pratique par rapport au code original de Shell. L'utilisation d'intervalles qui ne sont pas des multiples de 2, 3 ou 5 semble réduire davantage les temps d'exécution : des gains de vitesse d'environ 35 % par rapport au code original de Shell semblent possibles. L'utilisation d'intervalles composés uniquement de nombres premiers (se terminant par 1) semble produire des gains de vitesse d'environ 40 % par rapport au code original.

La séquence de Tokuda, définie par la formule simple , où , , peut être recommandée pour les applications pratiques.

Si la taille maximale des données d'entrée est faible, comme cela peut se produire lorsque Shellsort est utilisé sur de petits sous-tableaux par un autre algorithme de tri récursif tel que quicksort ou merge sort , il est possible de tabuler une séquence optimale pour chaque taille d'entrée. Pour N = 128 et N = 1000, Ciura a constaté empiriquement que les séquences (1, 4, 9, 24, 85) et (1, 4, 10, 23, 57, 156, 409, 995) effectuaient en moyenne le moins de comparaisons, respectivement.

Complexité computationnelle

La propriété suivante est vérifiée : après un tri h₂ d'un tableau trié h₁, ce tableau reste trié h₁. [21] Tout tableau trié h₁ et h₂ est également trié (a₁h₁ + a₂h₂ ) , pour tous entiers non négatifs . La complexité dans le pire des cas de Shellsort est donc liée au problème de Frobenius : pour des entiers h₁, ..., hₙ donnés, de PGCD = 1 , le nombre de Frobenius g(h₁ , ... , hₙ ) est le plus grand entier qui ne peut être représenté sous la forme a₁h₁ + ... + aₙhₙ, avec des entiers non négatifs a₁, ..., aₙ . À l' aide des formules connues pour les nombres de Frobenius , on peut déterminer la complexité dans le pire des cas de Shellsort pour plusieurs classes de séquences à intervalles. Les résultats obtenus sont présentés dans le tableau ci-dessus .

Mark Allen Weiss a prouvé que Shellsort s'exécute en O ( N log N ) temps lorsque le tableau d'entrée est en ordre inverse.

Concernant le nombre moyen d'opérations, aucun des résultats démontrés ne concerne une séquence d'intervalles pratique. Pour des intervalles qui sont des puissances de deux, Espelid a calculé cette moyenne comme suit : Knuth a déterminé que la complexité moyenne du tri d'un tableau de N éléments avec deux intervalles ( h , 1) est de : . Il s'ensuit qu'un tri Shell en deux passes avec h = Θ( N <sup>1/3</sup> ) effectue en moyenne O ( N <sup>5/3</sup> ) comparaisons/inversions/temps d'exécution. Yao a trouvé la complexité moyenne d'un tri Shell en trois passes. Son résultat a été affiné par Janson et Knuth : le nombre moyen de comparaisons/inversions/temps d'exécution effectués lors d'un tri Shell avec trois intervalles ( ch , cg , 1), où h et g sont premiers entre eux, est de : lors de la première passe, lors de la deuxième passe et lors de la troisième passe. ψ ( h , g ) dans la dernière formule est une fonction complexe asymptotiquement égale à . En particulier, lorsque h = Θ( N 7/15 ) et g = Θ( N 1/5 ), le temps moyen de tri est O ( N 23/15 ).

D'après des expériences, on suppose que l'algorithme Shellsort avec la séquence d'espacement de Hibbard s'exécute en temps moyen O ( N⁵ /⁴ ) , et que la séquence de Gonnet et Baeza-Yates nécessite en moyenne 0,41 N ln N (ln ln N + 1/6) déplacements d'éléments . Les approximations du nombre moyen d'opérations proposées précédemment pour d'autres séquences deviennent inapplicables lorsque les tableaux triés contiennent des millions d'éléments.

Le graphique ci-dessous montre le nombre moyen de comparaisons d'éléments utilisées par diverses séquences d'intervalles, divisé par la limite inférieure théorique , c'est-à-dire log 2 N !. La séquence de Ciuria 1, 4, 10, 23, 57, 132, 301, 701 (étiquetée Ci01) a été étendue selon la formule .

En appliquant la théorie de la complexité de Kolmogorov , Jiang, Li et Vitányi ont démontré la borne inférieure suivante pour l'ordre du nombre moyen d'opérations par temps d'exécution dans un tri Shell à p passes : Ω( pN ) = 1 + 1/ p lorsque p log₂N et Ω( pN ) lorsque p > log₂N . Par conséquent, le tri Shell a la possibilité de s'exécuter en un temps moyen qui croît asymptotiquement comme N log N uniquement lorsqu'on utilise des séquences d'intervalles dont le nombre d'intervalles croît proportionnellement au logarithme de la taille du tableau. On ignore cependant si le tri Shell peut atteindre cet ordre asymptotique de complexité en moyenne, qui est optimal pour les tris par comparaison. Vitányi a amélioré cette borne inférieure pour tout nombre de passes, en l' établissant à Ω(pN) = 1. Ce résultat implique par exemple la borne inférieure de Jiang-Li-Vitányi pour toutes les séquences d'incréments à p passes et améliore cette borne inférieure pour des séquences d'incréments particulières. En fait, toutes les bornes (inférieures et supérieures) actuellement connues pour le cas moyen sont précisément égales à cette borne inférieure. Par exemple, cela donne le nouveau résultat que la borne supérieure de Janson-Knuth est égale à la borne inférieure résultante pour la séquence d'incréments utilisée, montrant que le tri Shell à trois passes pour cette séquence d'incréments utilise un temps d'exécution de comparaisons/inversions. La formule nous permet de rechercher des séquences d'incréments qui donnent des bornes inférieures inconnues ; par exemple, une séquence d'incréments pour quatre passes dont la borne inférieure est supérieure à celle de la séquence d'incréments . La borne inférieure devient alors

La complexité dans le pire des cas de toute version de Shellsort est d'ordre supérieur : Plaxton, Poonen et Suel ont montré qu'elle croît au moins aussi rapidement que . Robert Cypher a prouvé une borne inférieure plus forte : lorsque pour tout .

Applications

Shellsort effectue davantage d'opérations et présente un taux d'échecs de cache plus élevé que quicksort . Cependant, comme il peut être implémenté avec peu de code et n'utilise pas la pile d'appels , certaines implémentations de la fonction qsort de la bibliothèque standard C destinées aux systèmes embarqués l'utilisent à la place de quicksort. Shellsort est, par exemple, utilisé dans la bibliothèque uClibc . Pour des raisons similaires, Shellsort était auparavant utilisé dans le noyau Linux .

Shellsort peut également servir de sous-algorithme de tri introspectif , pour trier des sous-tableaux courts et éviter un ralentissement lorsque la profondeur de récursion dépasse une limite donnée. Ce principe est employé, par exemple, dans le compresseur bzip2 .

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index