Les algorithmes de tri génériques prennent généralement un ensemble de données à trier et une fonction de comparaison qui peut comparer deux éléments individuels. Si le comparateur est une relation d'ordre¹, la sortie de l'algorithme est une liste / tableau trié.
Je me demande si les algorithmes de tri se fait fonctionner avec un comparateur qui n'est pas une relation d'ordre (en particulier un qui renvoie un résultat aléatoire sur chaque comparaison). Par «travail», je veux dire ici qu'ils continuent de renvoyer une permutation de leur entrée et de fonctionner à leur complexité temporelle typiquement citée (par opposition à se dégrader toujours dans le pire des cas, ou à entrer dans une boucle infinie, ou des éléments manquants). L'ordre des résultats ne serait cependant pas défini. Encore mieux, la commande résultante serait une distribution uniforme lorsque le comparateur est un jeu de pièces.
D'après mon calcul mental approximatif, il semble qu'un tri par fusion serait bien avec cela et maintiendrait le même coût d'exécution et produirait un ordre aléatoire équitable. Je pense que quelque chose comme un tri rapide dégénérerait cependant, ne serait peut-être pas terminé et ne serait pas juste.
Quels autres algorithmes de tri (autres que le tri par fusion) fonctionneraient comme décrit avec un comparateur aléatoire?
Pour référence, un comparateur est une relation d'ordre s'il est une fonction propre (déterministe) et satisfait les axiomes d'une relation d'ordre:
- il est déterministe:
compare(a,b)
pour un particuliera
etb
renvoie toujours le même résultat. - c'est transitif:
compare(a,b) and compare(b,c) implies compare( a,c )
- c'est antisymétrique
compare(a,b) and compare(b,a) implies a == b
- il est déterministe:
(Supposons que tous les éléments d'entrée soient distincts, donc la réflexivité n'est pas un problème.)
Un comparateur aléatoire viole toutes ces règles. Il existe cependant des comparateurs qui ne sont pas des relations d'ordre mais qui ne sont pas aléatoires (par exemple, ils peuvent violer peut-être une seule règle et uniquement pour des éléments particuliers de l'ensemble).
la source
Réponses:
Donc, fondamentalement, vous voulez savoir s'il existe un algorithme de tri qui ne se dégraderait pas de son cas moyen si on lui donnait une fonction de comparaison similaire à:
... où Random.Next () est une méthode qui produira un entier généré de façon aléatoire entre une limite inférieure et supérieure incluse incluse.
La réponse est en fait que la plupart des algorithmes de tri de base fonctionneront selon leur cas moyen, car ils obéissent à au moins l'une des deux conditions suivantes:
Par exemple, SelectionSort parcourt la sous-liste des éléments non triés, trouve l'élément "le moins" et / ou "le plus grand" (en comparant chacun au plus grand jusqu'à présent), le place dans sa position correcte et répète. Par conséquent, même avec un comparateur non déterministe, à la fin de chaque itération, l'algorithme aura trouvé une valeur qu'il pense être la plus petite ou la plus grande, l'échange avec l'élément dans la position qu'il essaie de déterminer, et ne considère jamais cet élément à nouveau, donc il obéit à la condition 2. Cependant, un A et un B peuvent être comparés plusieurs fois au cours de ce processus (comme l'exemple le plus extrême, considérez plusieurs passes de SelectionSort sur un tableau qui est trié dans l'ordre inverse) donc il viole la condition 1 .
MergeSort obéit à la condition 1 mais pas à la condition 2; lorsque les sous-tableaux sont fusionnés, les éléments du même sous-tableau (à gauche ou à droite) ne sont pas comparés les uns aux autres car il a déjà été déterminé que les éléments de ce côté du tableau sont en ordre entre eux; l'algorithme compare uniquement l'élément le moins non fusionné de chaque sous-tableau à l'autre pour déterminer celui qui est le moins important et devrait aller ensuite dans la liste fusionnée. Cela signifie que deux objets uniques A et B seront comparés l'un à l'autre au maximum une fois, mais l'index "final" d'un élément donné dans la collection complète n'est pas connu tant que l'algorithme n'est pas terminé.
InsertionSort n'obéit qu'à la condition 1 également, même si sa stratégie globale et sa complexité ressemblent davantage à SelectionSort. Chaque élément non trié est comparé aux éléments triés, le plus grand en premier, jusqu'à ce qu'il en trouve un de moins que l'élément examiné. l'élément est inséré à ce point, puis l'élément suivant est pris en compte. Le résultat est que l'ordre relatif de tout A et B est déterminé par une comparaison, et que d'autres comparaisons entre A et B ne sont jamais effectuées, mais la position finale d'un élément ne peut être connue que lorsque tous les éléments sont pris en compte.
QuickSort obéit aux deuxConditions. A chaque niveau, un pivot est choisi et agencé de telle sorte que le côté "gauche" contient des éléments inférieurs au pivot et le côté "droit" contient des éléments supérieurs au pivot. Le résultat de ce niveau est QuickSort (gauche) + pivot + QuickSort (droite) ce qui signifie essentiellement que la position de l'élément pivot est connue (un index supérieur à la longueur du côté gauche), le pivot n'est jamais comparé à aucun autre élément après qu'il a été choisi comme pivot (il peut avoir été comparé aux éléments de pivot précédents, mais ces éléments sont également connus et ne sont inclus dans aucun sous-réseau), ET les A et B qui se retrouvent sur les côtés opposés du pivot ne sont jamais par rapport. Dans la plupart des implémentations de QuickSort pur, le scénario de base est un élément, auquel cas son index actuel est son index final et aucune autre comparaison n'est effectuée.
Le seul type comparatif auquel je peux penser qui n'obéirait à aucune de ces conditions est un BubbleSort non optimisé. Si le tri n'accepte pas que les X éléments les plus importants soient à leur place après l'exécution de X passes et / ou utilise une passe de "double vérification" pour vérifier que la liste est triée, le tri ne sera considéré comme "terminé" que lorsque le comparateur aléatoire est retourné -1 ou 0 pour tous les deux éléments adjacents de la liste pendant une passe et donc aucun swap ont été réalisées (un événement qui, si vraiment aléatoire, qui se produirait avec une probabilité ; pour une relativement petite liste de 25 éléments, c'est une chance sur 2000, alors que pour 100 éléments la probabilité est de 3,7 * 10 -18(2/3)N−1 ). Au fur et à mesure que la valeur absolue maximale du résultat du comparateur augmente, la probabilité pour une comparaison de retourner un résultat négatif ou nul diminue vers 0,5, ce qui rend la chance de terminer l'algorithme beaucoup moins probable (la chance de 99 pièces fait basculer toutes les têtes d'atterrissage , qui est essentiellement ce que cela se résume à, est de 1 sur 1,2 * 10 30 )
MODIFIER LONGTEMPS PLUS TARD: Il y a quelques "sortes" conçues spécifiquement comme exemples de ce qu'il ne faut pas faire qui incorporent un comparateur aléatoire; peut-être le plus célèbre est BogoSort. "Étant donné une liste, si la liste n'est pas en ordre, mélangez la liste et vérifiez à nouveau". Théoriquement, il finira par atteindre la bonne permutation des valeurs, tout comme le "BubbleSort non optimisé" ci-dessus, mais le cas moyen est le temps factoriel (N! / 2), et en raison du problème d'anniversaire (après suffisamment de permutations aléatoires, vous devenir plus susceptibles de rencontrer des permutations en double que des permutations uniques), il existe une possibilité non nulle que l'algorithme ne se termine jamais officiellement, l'algorithme est illimité dans le temps.
la source
Tout algorithme qui compare deux fois les deux mêmes éléments n'est pas un algorithme très intelligent, et en particulier un tel algorithme fonctionnerait moins bien que les algorithmes de tri les plus courants (fusion-tri, tri rapide, bulle-tri, insertion-tri). Tout algorithme qui compare des paires d'éléments au plus une fois a le même coût d'exécution (moyen) quel que soit le comportement de la fonction de comparaison, s'il est supérieur ou inférieur à des résultats également probables . Sinon, vous pouvez au moins garantir que l'algorithme de tri n'est pas pire que le temps d'exécution le plus défavorable, qui est inférieur àO(n2)
Edit: Le problème est plus intéressant que je le pensais, alors voici un autre commentaire:
Ce serait amusant de calculer les temps de fonctionnement moyens pour les différents autres algorithmes étant donné cette fonction de comparaison uniforme.
la source
Mergesort avec un comparateur aléatoire juste n'est pas juste. Je n'ai pas de preuve, mais j'ai des preuves empiriques TRÈS solides. (Juste signifie uniformément distribué.)
la source
Une réponse très connexe est trouvée dans All Sorts of Permutations (Functional Pearl) par Christiansen, Danilenko et Dylus. Ils exécutent un algorithme de tri dans la monade de liste , qui simule essentiellement le non-déterminisme, renvoyant toutes les permutations d'une liste d'entrée donnée. La propriété intéressante est que chaque permutation est retournée exactement une fois.
Citant le résumé:
la source