Les algorithmes sphériques dans le vide sont excellents. Descendons cependant du ciel à la terre pécheresse et voyons comment toute cette beauté théorique se révélera en pratique.
L'analyse de la prochaine classe de tris se terminera par des tests pour les tris de classe. Aujourd'hui, nous allons exécuter (non pas dans le sens de jeter, mais dans le sens de lancer des tests) des échanges de tri. Des classes d'autres classes seront exécutées plus tard.
Dans la course d'aujourd'hui impliquée:
Groupe le plus faible
Ces algorithmes ne revendiquent rien en raison de la complexité temporelle déprimante. Nous les testons uniquement à titre de référence.

Sort idiot

Tri lent

Tri muet
C’est encore plus intéressant non seulement de savoir à quel point ils sont bons, mais à quel point ils sont mauvais en affaires, et lequel est le pire.
Groupe principal
Ici se sont réunis des triages d'échange à la O (
n 2 ). Tri nain (et son optimisation) + toutes sortes de variantes de tri à bulles.

Tri nain

Tri nain (optimisé)

Tri des bulles

Tri des cocktails

Tri pair-impair
C'est la partie la plus intéressante des mesures d'aujourd'hui. C'est parmi les représentants du groupe principal que la lutte la plus tenace est attendue.
Groupe le plus fort
Une des variétés de la bulle - triée par un peigne - a réussi à franchir la barrière O (
n 2 ) et à atteindre le O séculaire (
n log n ). Donc, dans notre compétition, le tri rapide a un rival digne. Essayez également le
k-sort nouvellement inventé , qui est une variante du tri rapide.

Trier la brosse à cheveux

Tri rapide

Tri K
Soit dit en passant, les plus forts ne sont pas seulement comparables entre eux. Sur certains ensembles de données, le groupe principal sera en forte concurrence.
Code source
Python Exchange Sortsdef stooge_rec(data, i = 0, j = None): if j is None: j = len(data) - 1 if data[j] < data[i]: data[i], data[j] = data[j], data[i] if j - i > 1: t = (j - i + 1) // 3 stooge_rec(data, i, j - t) stooge_rec(data, i + t, j) stooge_rec(data, i, j - t) return data def stooge(data): return stooge_rec(data, 0, len(data) - 1) def slow_rec(data, i, j): if i >= j: return data m = (i + j) // 2 slow_rec(data, i, m) slow_rec(data, m + 1, j) if data[m] > data[j]: data[m], data[j] = data[j], data[m] slow_rec(data, i, j - 1) return data def slow(data): return slow_rec(data, 0, len(data) - 1) def stupid(data): i, size = 1, len(data) while i < size: if data[i - 1] > data[i]: data[i - 1], data[i] = data[i], data[i - 1] i = 1 else: i += 1 return data def gnome(data): i, size = 1, len(data) while i < size: if data[i - 1] <= data[i]: i += 1 else: data[i - 1], data[i] = data[i], data[i - 1] if i > 1: i -= 1 return data def gnome_opt(data): i, j, size = 1, 2, len(data) while i < size: if data[i - 1] <= data[i]: i, j = j, j + 1 else: data[i - 1], data[i] = data[i], data[i - 1] i -= 1 if i == 0: i, j = j, j + 1 return data def bubble(data): changed = True while changed: changed = False for i in range(len(data) - 1): if data[i] > data[i+1]: data[i], data[i+1] = data[i+1], data[i] changed = True return data def shaker(data): up = range(len(data) - 1) while True: for indices in (up, reversed(up)): swapped = False for i in indices: if data[i] > data[i+1]: data[i], data[i+1] = data[i+1], data[i] swapped = True if not swapped: return data def odd_even(data): n = len(data) isSorted = 0 while isSorted == 0: isSorted = 1 for i in range(1, n - 1, 2): if data[i] > data[i + 1]: data[i], data[i + 1] = data[i + 1], data[i] isSorted = 0 for i in range(0, n - 1, 2): if data[i] > data[i + 1]: data[i], data[i + 1] = data[i + 1], data[i] isSorted = 0 return data def comb(data): gap = len(data) swaps = True while gap > 1 or swaps: gap = max(1, int(gap / 1.25))
Le temps
Le temps est mesuré partout en secondes avec une précision aux microsecondes.
Si un paquet de tableaux (sur dix, cent ou même un million de pièces) est immédiatement appliqué à l'algorithme, alors le temps total est indiqué.
Le fer est mon vieil ordinateur portable fidèle qui a connu des temps meilleurs. Donc, très probablement, tout fonctionnera pour vous beaucoup plus rapidement.
Le pire du pire
Traitez immédiatement avec des étrangers. Des tableaux pour les éléments 40/50/60 contenant des nombres aléatoires de 0 à 9 sont préparés pour eux.
| type = aléatoire, unique = Faux, min = 0, max = 9, nombre = 1 |
---|
taille |
---|
40 | 50 | 60 |
---|
Python | Php | Python | Php | Python | Php |
---|
 | 0,004 | 0,001 | 0,005 | 0,003 | 0,007 | 0,004 |
---|
 | 0,007 | 0,009 | 0,018 | 0,009 | 0,018 | 0,023 |
---|
 | 0,02 | 8.26647 | 0,053 | 20.8722 | 0,12901 | 45,9786 |
---|
Le tri stupide est un ordre de grandeur plus rapide que le tri stupide, et le tri stupide est un ordre de grandeur plus rapide que lent. Il n'y a plus rien à regarder.
Paysans moyens
Pour vérifier la moyenne, des packs de cent tableaux de 100 éléments chacun (numéros uniques de 100 à 999), ainsi que des packs de dix tableaux de 1000 éléments chacun (numéros uniques de 1000 à 9999) ont été générés.
Des tableaux aléatoires, des tableaux presque triés et des tableaux en ordre inverse sont préparés.
Poids moyen: aléatoire
| type = aléatoire, unique = Vrai |
---|
taille (min à max) × nombre |
---|
100 (100 à 999) × 100 | 1000 (1000 à 9999) × 10 |
---|
Python | Php | Python | Php |
---|
 | 0,14101 | 0,18901 | 1.59109 | 1.7251 |
---|
 | 0,20601 | 0,22301 | 2.33013 | 2.09712 |
---|
 | 0,15301 | 0,22901 | 1,6711 | 2.23613 |
---|
 | 0,21601 | 0,26402 | 2,55515 | 2,73116 |
---|
 | 0,16701 | 0,33402 | 1.7251 | 3.13218 |
---|
Autour des mêmes résultats pour tous. Les implémentations Python fonctionnent un peu plus rapidement que PHP.
Middles: Presque triés
| type = presque, unique = True |
---|
taille (min à max) × nombre |
---|
100 (100 à 999) × 100 | 1000 (1000 à 9999) × 10 |
---|
Python | Php | Python | Php |
---|
 | 0,009 | 0,005 | 0,009 | 0,005 |
---|
 | 0,009 | 0,014 | 0,01 | 0,014 |
---|
 | 0,01 | 0,01 | 0,011 | 0,008 |
---|
 | 0,011 | 0,008 | 0,013 | 0,008 |
---|
 | 0,011 | 0,017 | 0,013 | 0,017 |
---|
Tous ont les mêmes résultats, plus ou moins. De l'intéressant: la commande de données partielles des dizaines de fois améliore les performances de tous les algorithmes.
Milieu: marche arrière
| type = inverse, unique = Vrai |
---|
taille (min à max) × nombre |
---|
100 (100 à 999) × 100 | 1000 (1000 à 9999) × 10 |
---|
Python | Php | Python | Php |
---|
 | 0,26801 | 0,35902 | 3.10018 | 3.4292 |
---|
 | 0,39602 | 0,45303 | 4.49726 | 4.19524 |
---|
 | 0,22701 | 0,38402 | 2,48114 | 3,64421 |
---|
 | 0,30202 | 0,42603 | 3.34419 | 4.17524 |
---|
 | 0,30402 | 0,64404 | 3.36519 | 6.22036 |
---|
Il y a une conclusion intéressante - l'ordre inverse n'affecte pas tellement la vitesse, qui n'a chuté que 2 fois par rapport au nombre aléatoire.
Milieu: binaire
| type = aléatoire, unique = Faux, min = 0, max = 1 |
---|
taille × nombre |
---|
100 × 100 | 1000 × 10 |
---|
Python | Php | Python | Php |
---|
 | 0,073 | 0,094 | 0,81105 | 0,86905 |
---|
 | 0,10401 | 0,11301 | 1.16307 | 1.06606 |
---|
 | 0,08801 | 0,12901 | 0,86405 | 1.18207 |
---|
 | 0,11501 | 0,15001 | 1,30107 | 1,41608 |
---|
 | 0,11401 | 0,25801 | 1,31908 | 2.46314 |
---|
De plus ou moins intéressant: si au lieu des nombres de 100 à 9999 vous triez les zéros et les uns, les indicateurs de vitesse n'augmenteront pas beaucoup.
Champions
La principale intrigue ici est de savoir si le tri avec un peigne et le tri par k peuvent presser le jeûne du piédestal?
Champions: aléatoire
Pour le savoir, formons des paquets de tableaux aléatoires: 10 morceaux de 10 mille éléments et 10 morceaux de 100 mille éléments. Je voulais donner des millionnaires aux algorithmes d'entrée, mais l'ordinateur portable n'a pas tiré. Soit il n'y a pas assez de RAM, alors la profondeur de récursivité est trop grande.
| type = aléatoire, unique = Faux, nombre = 10 |
---|
taille (min à max) |
---|
10000 (de 10000 à 99999) | 100000 (de 100000 à 999999) |
---|
Python | Php | Python | Php |
---|
 | 0.80205 | 0,63104 | 10.4506 | 8.24647 |
---|
 | 0,47703 | 1,64009 | 6.65138 | 26,5435 |
---|
 | 0,90005 | 2.18613 | 15.8089 | 29.4867 |
---|
Le tri Python K est plus lent et PHP est plus rapide que le tri rapide.
Le tri du peigne par rapport au rapide semble solide, bien qu'il soit inférieur à lui dans tous les tests (et sur ceux-ci et les suivants) pour tous les ensembles de données.
Cependant, il existe des peignes et un avantage incontestable important. Il n'a pas de récursivité et donc, contrairement à ses collègues, il traite avec succès des tableaux de millions d'éléments.
Cas particuliers
Bien que les champions soient des centaines de fois plus rapides que les paysans moyens, sur certains ensembles de données spécifiques, les tris montrent plus simplement qu'ils ne sont pas faciles à coudre.
Cas particuliers: presque triés
Essayons des tableaux presque triés, prenons simplement une taille plus grande que celles qui ont été testées pour les paysans moyens.
Un package de 10 tableaux de 10 000 chacun et un package de 10 tableaux de 100 000 éléments chacun.
| type = presque, unique = Faux |
---|
taille (min à max) × nombre |
---|
10000 (de 10000 à 99999) × 10 | 100000 (de 100000 à 999999) × 10 |
---|
Python | Php | Python | Php |
---|
 | 0,43202 | 0,058 | 0,81705 | 0,58003 |
---|
 | 0,084 | 0,062 | 0,85805 | 0,54003 |
---|
 | 0,11601 | 0,12401 | 1,41908 | 1,36008 |
---|
 | 0.14001 | 0,11901 | 1.83411 | 1,41708 |
---|
 | 0,13801 | 0,23101 | 1,6491 | 2,56915 |
---|
 | ? | 122.088 | ? | ? |
---|
 | 0,71504 | 1.58909 | 9.78356 | 19.4731 |
---|
Le tri rapide n'est pas présent du tout - il n'y avait pas assez de RAM. Dans le même temps, les tableaux aléatoires avec 10/100 mille éléments sont traités par tri rapide avec un bang. k-sort a rencontré des problèmes similaires, n'a tiré que 10 millièmes en PHP. Les grands tableaux presque triés sont un cas dégénéré pour un tri rapide et ses modifications. En raison de cette disposition des éléments, la récursion divise le tableau en parties pour presque chaque paire d'éléments adjacents, ce qui conduit au nombre maximal possible d'appels de récursivité.
Soit dit en passant, la situation est similaire avec de grands tableaux en ordre inverse. Le même problème se pose que pour les éléments presque ordonnés - l'algorithme doit s'appeler pour chaque paire d'éléments adjacents.
Tri par un peigne, bien que cela fonctionne une fois et demie à deux fois plus lentement que rapide ou k (en général), mais il n'a pas les débordements de mémoire susmentionnés. Pas de récursivité - pas de problème.
Eh bien, nous notons que tous les paysans moyens ont dépassé ensemble les champions dans de grands tableaux presque triés. Puis le principe a fonctionné: "Aller tranquillement - vous allez continuer."
Cas particuliers: millions de roses écarlates de petits réseaux
Petits tableaux - l'élément des paysans moyens. Si vous avez besoin de traiter un grand nombre de petits ensembles de nombres, vous pouvez gagner du temps en prenant une sorte de bulle ou de gnome «primitif». Et utilisez le tri rapide et d'autres comme celui-ci pour les tâches plus importantes.
| type = aléatoire, unique = Vrai |
---|
taille (min à max) × nombre |
---|
5 (10 à 99) × 1 000 000 | 10 (10 à 99) × 1 000 000 |
---|
Python | Php | Python | Php |
---|
 | 11.77267 | 17,888 | 24.29039 | 33,6659 |
---|
 | 12.51872 | 18.165 | 29.33268 | 35.202 |
---|
 | 15.44188 | 17.861 | 30.06672 | 36,7911 |
---|
 | 14.18681 | 19,7831 | 31.65981 | 39,3533 |
---|
 | 13.63978 | 24.3374 | 28.41662 | 52.864 |
---|
 | 14.21881 | 21.1452 | 25.80548 | 32,5419 |
---|
 | 14.58683 | 28.5016 | 24.85942 | 50.3139 |
---|
 | 18.53806 | 30.7238 | 29.6647 | 58.2493 |
---|
Avec les tris d'échange, tout est clair. Maintenant, pour la partie vraiment intéressante - le tri par insertions.
Les références
Application Excel AlgoLab , avec laquelle vous pouvez visualiser étape par étape la visualisation de ces (et pas seulement de ces) sortes.
Tous les tableaux sous forme de JSON sont également disposés sur le
disque Google .
Wiki / Stupide / Stooge , Lent , Nain / Gnome , Bulle / Bulle , Shaker / Shaker , Impair / Pair , Peigne / Peigne , Rapide / RapideArticles de la série