Mes collègues m'ont ramené à l'époque universitaire à une discussion sur les algorithmes de tri ce matin. Nous avons évoqué nos favoris comme StupidSort , et l'un de nous était certain d'avoir déjà vu un algorithme de tri qui s'appelait O(n!)
. Cela m'a permis de commencer à chercher les "pires" algorithmes de tri que j'ai pu trouver.
Nous avons postulé qu'un type complètement aléatoire serait assez mauvais (c.-à-d. Randomiser les éléments - est-il en ordre? Non? Randomize à nouveau), et j'ai regardé autour de moi pour découvrir qu'il s'appelait apparemment BogoSort, ou Monkey Sort, ou parfois juste un tri aléatoire .
Monkey Sort semble avoir la pire performance de O(∞)
, une meilleure performance de O(n)
et une performance moyenne de O(n·n!)
.
Existe-t-il des algorithmes nommés dont les performances moyennes sont inférieures à celles de O(n·n!)
? Ou sont-ils simplement plus ridicules que Monkey Sort en général?
Depuis la page des algorithmes ésotériques de David Morgan-Mar : Tri par conception intelligente
Introduction
Le type de conception intelligente est un algorithme de tri basé sur la théorie de la conception intelligente.
Description de l'algorithme
La probabilité que la liste d’entrée originale soit dans l’ordre exact est de 1/(n!). Il y a une si petite probabilité que cela soit clairement absurde de dire que cela est arrivé par hasard. Il a donc dû être consciemment placé dans cet ordre par une trieuse intelligente. Par conséquent, il est prudent de supposer que le tri est déjà optimal de manière à transcender notre compréhension naïve des mortels de "l'ordre croissant". Toute tentative visant à modifier cet ordre afin de se conformer à nos propres idées préconçues le rendrait en réalité moins ordonné.
Analyse
Cet algorithme est constant dans le temps et trie la liste sur place, ne nécessitant aucune mémoire supplémentaire. En fait, il n’a même pas besoin de ces technologies informatiques suspectes. Louez la trieuse!
Commentaires
Gary Rogers écrit:
Rendre le tri constant dans le temps nie le pouvoir de The Sorter. La trieuse existe en dehors du temps, elle est donc intemporelle. Demander du temps pour valider le tri diminue le rôle de la trieuse. Ainsi ... cette sorte particulière est imparfaite et ne peut être attribuée à 'The Sorter'.
Hérésie!
Il y a de nombreuses années, j'ai inventé (mais jamais réellement mis en œuvre) MiracleSort.
Start with an array in memory.
loop:
Check to see whether it's sorted.
Yes? We're done.
No? Wait a while and check again.
end loop
Finalement, les particules alpha retournant des bits dans les puces de mémoire devraient permettre un tri réussi.
Pour plus de fiabilité, copiez le tableau dans un emplacement blindé et comparez les tableaux potentiellement triés par rapport à l'original.
Alors, comment vérifiez-vous le tableau potentiellement trié par rapport à l'original? Vous venez de trier chaque tableau et de vérifier si elles correspondent. MiracleSort est l'algorithme évident à utiliser pour cette étape.
EDIT: Strictement parlant, il ne s'agit pas d'un algorithme, car sa terminaison n'est pas garantie. Est-ce que "pas un algorithme" est qualifié de "pire algorithme"?
Un algorithme de tri qui suppose que l'interprétation de la mécanique quantique dans de nombreux mondes est correcte:
A la fin de l'algorithme, la liste sera triée dans le seul univers restant debout. Cet algorithme prend le pire cas O(N) et le cas moyen O(1) temps. En fait, le nombre moyen de comparaisons effectuées est de 2: il y a 50% de chances que l'univers soit détruit sur le deuxième élément, 25% de chance qu'il soit détruit le troisième, et ainsi de suite.
Je suis surpris que personne n'ait encore parlé de Sleepsort ... Ou est-ce que je ne l'ai pas remarqué? En tous cas:
#!/bin/bash
function f() {
sleep "$1"
echo "$1"
}
while [ -n "$1" ]
do
f "$1" &
shift
done
wait
exemple d'utilisation:
./sleepsort.sh 5 3 6 3 6 3 1 4 7
./sleepsort.sh 8864569 7
En termes de performances, c'est terrible (surtout le deuxième exemple). Attendre près de trois mois et demi pour trier deux nombres est un peu mauvais.
Jingle Sort, comme décrit ici .
Vous donnez chaque valeur de votre liste à un enfant différent à Noël. Les enfants, étant des êtres humains affreux, vont comparer la valeur de leurs dons et se trier en conséquence.
Un conférencier m'a suggéré une fois de générer un tableau aléatoire, en vérifiant si celui-ci était trié, puis en vérifiant si les données étaient identiques au tableau à trier.
Meilleur cas O(N) (premier bébé!) Le pire des cas O (Jamais)
Si vous maintenez l'algorithme significatif, O(n!)
est la pire limite supérieure que vous puissiez obtenir.
Étant donné que la vérification de chaque possibilité de permutation d'un ensemble à trier prend des étapes n!
, Vous ne pouvez pas faire pire.
Si vous faites plus d’étapes que cela, alors l’algorithme n’a pas de véritable utilité. Sans parler de l'algorithme de tri simple suivant avec O(infinity)
:
list = someList
while (list not sorted):
doNothing
Vous devriez faire des recherches dans le domaine passionnant de algorithmes de Pessimal et analyse de simplexité . Ces auteurs travaillent sur le problème du développement d'une sorte avec un meilleur cas pessimal (le meilleur cas de votre bogosort est Omega (n), alors que ralentir (voir document) a une complexité temporelle dans le meilleur des cas non polynomial).
Bogobogosort. Oui c'est une chose. à Bogobogosort, vous Bogosort le premier élément. Vérifiez pour voir si cet élément est trié. Être un élément, ce sera. Ensuite, vous ajoutez le deuxième élément et Bogosort ces deux jusqu'à ce qu'il soit trié. Ensuite, vous ajoutez un élément supplémentaire, puis Bogosort. Continuez à ajouter des éléments et Bogosorting jusqu'à ce que tous les éléments soient enfin terminés. Cela a été conçu pour ne jamais réussir avec une liste considérable avant la mort de chaleur de l'univers.
Voici 2 sortes je suis venu avec mon colocataire à l'université
1) Vérifiez l'ordre 2) Peut-être un miracle s'est-il passé, allez à 1
et
1) vérifiez si tout est en ordre, sinon 2) mettez chaque élément dans un paquet et renvoyez-le à un serveur distant. Certains de ces paquets vont revenir dans un ordre différent, passez à 1
Il y a une sorte qui s'appelle bogobogosort. Tout d'abord, il vérifie les 2 premiers éléments et les corrige. Ensuite, il vérifie les 3 premiers, les corrige, etc. Si la liste est hors d'usage à tout moment, elle redémarre en modifiant à nouveau les 2 premiers. Bogosort standard a une complexité moyenne de O (N!), Cet algorithme a une complexité moyenne de O (N! 1! 2! 3! ... N!) Edit: Pour vous donner une idée de la taille de ce nombre, pour 20 éléments, cet algorithme prend en moyenne 3,93,0093 * 10 ^ 158 ans, bien au-dessus de la mort de chaleur proposée de l'univers (si cela se produit) de 10 ^ 100 ans, alors que le tri par fusion prend environ 0, 00004 secondes, le tri à bulle .0000016 secondes, et bogosort prend 308 ans, 139 jours, 19 heures, 35 minutes, 22,306 secondes, en supposant qu'une année correspond à 365,242 jours et qu'un ordinateur effectue 250 000 000 d'opérations d'entier 32 bits par seconde. Edit2: Cet algorithme n’est pas aussi lent que le tri miracle "algorithm", qui, probablement, obtiendra l’ordinateur aspiré dans le trou noir avant de trier avec succès 20 éléments, mais si c’était le cas, j’estimerais une complexité moyenne. de 2 ^ (32 (le nombre de bits dans un entier de 32 bits) N) (le nombre d'éléments) (un nombre <= 10 ^ 40 ans, car la gravité accélère le déplacement alpha des puces, et il y a 2 ^ N états, ce qui correspond à 2 ^ 640 * 10 ^ 40, ou environ 5,773 * 10 ^ 216.762162762 ans, bien que si la liste était triée au début, sa complexité serait uniquement de O (N), plus rapide que le tri par fusion, ce qui n’est que N log N même dans le pire des cas Edit3: Cet algorithme est en réalité plus lent que le tri miracle car la taille devient très grande, disons 1000, car mon algorithme aurait une durée d’exécution de 2,83 * 10 ^ 1175546 ans, L'algorithme de tri miracle aurait une durée d'exécution de 1,156 * 10 ^ 9657 ans.
Il y a toujours le Bogobogosort (Bogoception!). Il exécute Bogosort sur des sous-ensembles de plus en plus volumineux de la liste, puis recommence depuis le début si la liste n'est jamais triée.
for (int n=1; n<sizeof(list); ++n) {
while (!isInOrder(list, 0, n)) {
shuffle(list, 0, n);
}
if (!isInOrder(list, 0, n+1)) { n=0; }
}
1 Mettez vos objets à trier sur des fiches2 Jetez-les dans les airs par une journée venteuse, à un mille de votre maison.
2 Jetez-les dans un feu de joie et confirmez qu'ils sont complètement détruits.
3 Vérifiez le bon ordre dans le sol de votre cuisine.
4 Répétez l'opération si l'ordre n'est pas correct.
Le meilleur scénario est O ()
Edit ci-dessus, basé sur une observation astucieuse de KennyTM.
Non seulement il peut implémenter n'importe quelle valeur concevable O(x) inférieure à l'infini, mais le temps pris est parfaitement correct (si vous pouvez attendre aussi longtemps).
Rien ne peut être pire que l'infini.
Segments de π
Supposons que π contienne toutes les combinaisons de nombres finis possibles. Voir question math.stackexchange
Le tri Bozo est un algorithme associé qui vérifie si la liste est triée et, dans le cas contraire, permute deux éléments de manière aléatoire. Il a les mêmes performances dans les cas les meilleurs et les moins favorables, mais je m'attendrais intuitivement à ce que la moyenne des cas soit plus longue que celle de Bogosort. Il est difficile de trouver (ou de produire) des données sur les performances de cet algorithme.
Une pire performance de O (performance) pourrait même ne pas en faire un algorithme selon quelques-uns .
Un algorithme est juste une série d'étapes et vous pouvez toujours faire pire en le peaufinant un peu pour obtenir la sortie souhaitée en plus d'étapes que par le passé. On pourrait délibérément mettre la connaissance du nombre d'étapes prises dans l'algorithme et le faire terminer et produire la sortie correcte uniquement après X
nombre d'étapes effectuées. Ce X
pourrait très bien être de l’ordre de O (n2) ou O (nn!) ou quel que soit l'algorithme désiré. Cela augmenterait efficacement les limites de son scénario optimal et moyen.
Mais votre pire scénario ne peut pas être dépassé :)
Recursive Bogosort (probably still O(n!){
if (list not sorted)
list1 = first half of list.
list 2 = second half of list.
Recursive bogosort (list1);
Recursive bogosort (list2);
list = list1 + list2
while(list not sorted)
shuffle(list);
}
Mon algorithme de tri lent préféré est le tri stooge:
void stooges(long *begin, long *end) {
if( (end-begin) <= 1 ) return;
if( begin[0] < end[-1] ) swap(begin, end-1);
if( (end-begin) > 1 ) {
int one_third = (end-begin)/3;
stooges(begin, end-one_third);
stooges(begin+one_third, end);
stooges(begin, end-one_third);
}
}
Le cas le plus complexe est O(n^(log(3) / log(1.5))) = O(n^2.7095...)
.
Un autre algorithme de tri lent est en réalité nommé ralentissement!
void slow(long *start, long *end) {
if( (end-start) <= 1 ) return;
long *middle = start + (end-start)/2;
slow(start, middle);
slow(middle, end);
if( middle[-1] > end[-1] ) swap(middle-1, end-1);
slow(start, end-1);
}
Celui-ci prend O(n ^ (log n))
dans le meilleur des cas ... même plus lent que stoogesort.
Cette page est une lecture intéressante sur le sujet: http://home.tiac.net/~cri_d/cri/2001/badsort.html
Mon préféré est le sillysort de Tom Duff:
/*
* The time complexity of this thing is O(n^(a log n))
* for some constant a. This is a multiply and surrender
* algorithm: one that continues multiplying subproblems
* as long as possible until their solution can no longer
* be postponed.
*/
void sillysort(int a[], int i, int j){
int t, m;
for(;i!=j;--j){
m=(i+j)/2;
sillysort(a, i, m);
sillysort(a, m+1, j);
if(a[m]>a[j]){ t=a[m]; a[m]=a[j]; a[j]=t; }
}
}
Double bogosort
Bogosort deux fois et comparez les résultats (juste pour être sûr qu'il soit bien trié) sinon recommencez
L'une des tâches sur lesquelles je travaillais consiste à choisir deux points aléatoires et, s'ils sont dans le mauvais ordre, à inverser toute la sous-gamme entre eux. J'ai trouvé l'algorithme sur http://richardhartersworld.com/cri_d/cri/2001/badsort.html , qui indique que le cas moyen se situe probablement quelque part autour de O (n ^ 3) ou O ( n ^ 2 log n) (il n'est pas vraiment sûr).
Je pense qu’il serait peut-être possible de le faire plus efficacement, car je pense qu’il serait possible de faire l’opération d’inversion dans O(1) temps.
En fait, je viens de me rendre compte que faire cela ferait tout ce que je dirais peut-être parce que je venais de réaliser que la structure de données que je pensais envisageait l'accès aux éléments aléatoires en O (log n) et en déterminant s'il fallait inverser en O (n ).
Vous pouvez ralentir n'importe quel algorithme de tri en exécutant votre étape "Est-il trié" de manière aléatoire? Quelque chose comme:
Randomsubsetsort.
Étant donné un tableau de n éléments, choisissez chaque élément avec la probabilité 1/n, randomisez ces éléments et vérifiez si le tableau est trié. Répéter jusqu'à trié.
Le temps attendu est laissé comme exercice au lecteur.
Oui, SimpleSort, en théorie, il fonctionne dans O(-1)
, bien que ce soit équivalent à O(...9999)
, ce qui équivaut à O (- 1), qui ça arrive est aussi équivalent à O (). Voici mon exemple d'implémentation:
/* element sizes are uneeded, they are assumed */
void
simplesort (const void* begin, const void* end)
{
for (;;);
}