Comment se présente cet algorithme de tri Θ (n³) et non (n²)?


52

Je viens juste de commencer un cours sur les structures de données et les algorithmes et mon assistant enseignant nous a donné le pseudo-code suivant pour trier un tableau d'entiers:

void F3() {
    for (int i = 1; i < n; i++) {
        if (A[i-1] > A[i]) {
            swap(i-1, i)
            i = 0
        }
    }
}

Cela peut ne pas être clair, mais ici n est la taille du tableau Aque nous essayons de trier.

Dans tous les cas, l'assistant d'enseignement expliqué à la classe que cet algorithme est en Θ(n3) temps (pire cas, je crois), mais peu importe combien de fois je vais à travers avec un tableau inverse triées, il semble pour moi que ce devrait être Θ(n2) et non Θ(n3) .

Est-ce que quelqu'un pourrait m'expliquer pourquoi c'est et non ?Θ(n3)Θ(n2)


Vous pouvez être intéressé par une approche structurée de l'analyse ; essayez de trouver une preuve vous-même!
Raphaël

Il suffit de le mettre en œuvre et de mesurer pour vous convaincre. Un tableau contenant 10 000 éléments inversés devrait prendre plusieurs minutes, et un tableau contenant 20 000 éléments inversés devrait prendre environ huit fois plus de temps.
gnasher729

@ gnasher729 Vous n'avez pas tort, mais ma solution est différente: si vous essayez de prouver que vous êtes lié à , vous échouerez invariablement, ce qui vous dira quelque chose qui cloche. (Bien sûr, on peut faire les deux Traçage / montage est nettement plus rapide pour rejeter l' hypothèse, mais. Moins fiable Tant que vous faites une sorte d'analyse formelle / structurée, pas de mal.. En se fondant sur des parcelles est là où commence trouble.)O(n2)
Raphael

1
à cause de la i = 0déclaration
njzk2

Réponses:


60

Cet algorithme peut être ré-écrit comme ceci

  1. Scannez Ajusqu'à trouver une inversion .
  2. Si vous en trouvez un, échangez et recommencez.
  3. S'il n'y en a pas, terminez.

Maintenant, il peut y avoir au plus inversions et vous avez besoin d’un balayage linéaire pour les trouver - le pire temps d’exécution est donc . Un bel exemple d’enseignement en décrivant l’approche de correspondance de motifs à laquelle beaucoup succombent!Θ(n3)(n2)Θ(n2)Θ(n3)

Nota bene: Il faut être prudent: certaines inversions apparaissent tôt, d'autres tard, il n'est donc pas anodin que les coûts s'additionnent comme indiqué (pour la limite inférieure). Vous devez également observer que les échanges ne introduisent jamais de nouvelles inversions. Une analyse plus détaillée du cas avec le tableau inversement trié donnera alors quelque chose comme le cas quadratique de la formule de Gauss.

Comme @ gnasher729 le commente avec justesse, il est facile de voir le temps d'exécution dans le pire des cas est en analysant le temps d'exécution lors du tri de l'entrée (bien que cette entrée ne soit probablement pas le pire des cas).[ 1 , 2 , , n , 2 n , 2 n - 1 , , n + 1 ]Ω(n3)[1,2,,n,2n,2n1,,n+1]

Faites attention: ne supposez pas qu'un tableau trié en sens inverse sera nécessairement l'entrée dans le pire des cas pour tous les algorithmes de tri. Cela dépend de l'algorithme. Il existe certains algorithmes de tri dans lesquels un tableau trié en sens inverse n'est pas le pire des cas et peut même être proche du meilleur des cas.


14
Si vous prenez un tableau où la première moitié est composée des nombres 1 à n / 2 en ordre croissant, et la seconde moitié est n à n / 2 + 1 en ordre inversé, il est évident que vous avez besoin d'au moins n / 2. étapes pour trouver chaque inversion, et il y en aura environ (n / 2) ^ 2/2. Et ce n'est probablement pas le pire des cas.
gnasher729

@AnthonyRossello C'est un résultat standard (en combinatoire des permutations). En bref, comptez le nombre d'inversions dans le tableau trié inversement (est-il évident que ce soit le cas le plus défavorable?); c'est une somme de Gauss.
Raphaël

Il ne faut pas oublier que, quoi qu'il en soit, les sommes partielles de sont toujours , c'est simplement le coefficient qui diminue rapidement: (notez le coefficient assez grand ). Le problème est que ne se soucie pas des coefficients. Θ ( n α + 1 ) Σ n k = 0 k α ~ 1Θ(nα)Θ(nα+1)1k=0nkα1α+1nα+1 Θ1α+1Θ
Yo '19

2
@yo 'Et cela concerne la réponse (ou la question) comment?
Raphaël

7

Une autre façon de penser à cela est ce que idevient la valeur maximale de avant qu’elle ne soit réinitialisée. En fin de compte, il est ainsi plus facile de raisonner sur l’effet de l’ordre de tri précédent Asur le temps d’exécution de l’algorithme.

En particulier, notez que lorsque vous idéfinissez sa nouvelle valeur maximale, appelons-le N, le tableau [A[0], ..., A[N-1]]est trié par ordre croissant.

Alors que se passe-t-il lorsque nous ajoutons l'élément A[N]au mélange?

Les mathématiques:

Eh bien, disons que ça va à la position . Ensuite, nous avons besoin de itérations de boucle (notées ) pour le déplacer à la place de , itérations pour le déplacer à la position , et en général: N pas N - 1 N + ( N - 1 ) N - 2pNNstepsN1N+(N1)N2

stepsN(pN)=N+(N1)+(N2)++(pN+1)=12(N(N+1)pN(pN+1))

Pour un tableau trié au hasard, prend la distribution uniforme sur pour chaque , avec: { 0 , 1 , , N } NpN{0,1,,N}N

E(stepsN(pN))=a=1NP(pN=a)stepsN(a)=a=1N1N12(N(N+1)a(a+1))=12(N(N+1)13(N+1)(N+2))=13(N21)=Θ(N2)

la somme peut être montrée en utilisant la formule de Faulhaber ou le lien Wolfram Alpha en bas.

Pour un tableau inversement trié, pour tout , et on obtient:NpN=0N

stepsN(pN)=12N(N+1)

exactement, en prenant strictement plus longtemps que toute autre valeur de .pN

Pour un tableau déjà trié, et , les termes d'ordre inférieur devenant pertinents.pN=NstepsN(pN)=0

Temps total:

Pour obtenir le temps total, nous résumons les étapes sur toute la . (Si nous faisions très attention, nous résumerions les swaps ainsi que les itérations de boucle et nous nous occuperions des conditions de début et de fin, mais il est assez facile de voir qu'elles ne contribuent pas à la complexité dans la plupart des cas) .N

Et encore une fois, en utilisant la linéarité des attentes et la formule de Faulhaber:

Expected Total Steps=E(N=1nstepsN(pN))=N=1nE(stepsN(pN))=Θ(n3)

Bien sûr, si pour quelque raison que ce soit n’est pas (par exemple, la distribution des tableaux que nous examinons est déjà très proche d’être triée), cela n’est pas toujours nécessaire. être le cas. Mais il faut des distributions très spécifiques sur pour y parvenir!Θ ( N 2 ) p NstepsN(pN)Θ(N2)pN

Lecture pertinente:


@ Raphael - merci pour les améliorations suggérées, j'ai ajouté un peu plus de détails. Eh bien, les variables aléatoires sont les (de , l'ensemble des ordres de ), de sorte que les attentes sont définies techniquement sur Ω ΩpiΩAΩ
David E

Différent ; Je voulais dire celui de Landau. Ω
Raphaël

3

Avertissement:

Ce n'est pas une preuve (il semblerait que certaines personnes pensent que je l'ai posté comme si c'était le cas). Il ne s’agit que d’une petite expérience que le PO pourrait effectuer pour résoudre ses doutes quant à la mission:

quel que soit le nombre de fois où je le traverse avec un tableau trié en sens inverse, il me semble que ce devrait être et non .Θ ( n 3 )Θ(n2)Θ(n3)

Avec un code aussi simple, la différence entre et ne devrait pas être difficile à repérer et, dans de nombreux cas pratiques, il s'agit d'une approche utile pour vérifier les intuitions ou ajuster les attentes.Θ ( n 3 )Θ(n2)Θ(n3)


@Raphael a déjà répondu à votre question, mais juste pour le plaisir, montage de ce programme de sortie en utilisant ce script gnuplot a rapporté des valeurs exposant de et et a produit les parcelles suivantes ( la première est l'échelle normale et la seconde est l'échelle log-log):2,99796166833222 2,99223727692339f(x)=axb+cx2.997961668332222.99223727692339

Ordinaire journal

J'espère que cela aide¨


2
Vous pouvez adapter n'importe quelle fonction à ces valeurs. Voir aussi ici .
Raphaël

3
@Raphael Si vous ne voulez pas croquer de cette façon, alors non, vous ne pouvez adapter aucune fonction (par exemple, vous ne pourrez pas adapter une fonction constante à une précision raisonnable). Ce n'est pas une preuve, mais il existe déjà une réponse qui fournit un croquis. En ce qui concerne l’utilité, je peux citer votre propre message que vous avez lié: "Je dois admettre que c’est une approche très utile qui est parfois même sous-utilisée". De plus, l’opérateur a dit qu’il pensait que ce devait être plutôt que , alors pourquoi ne pas expérimenter et voir si son intuition était correcte? Cont. Θ ( n 3 )Θ(n2)Θ(n3)
dtldarek

2
Cela fournit la preuve que l'algorithme est mais la question demande pourquoi . C'est demander une explication du phénomène, pas une confirmation. Θ(n3)
David Richerby

2
@DavidRicherby Cela signifie-t-il que cette réponse n'est pas utile?
dtldarek

3
@Magicsowon C'est un site de questions et réponses, pas un forum. Nous cherchons des réponses à la question, pas une discussion à ce sujet.
David Richerby le

3

Supposons que vous avez un tableau.

array a[10] = {10,8,9,6,7,4,5,2,3,0,1}

Votre algorithme fait ce qui suit

Scan(1) - Swap (10,8) => {8,10,9,6,7,4,5,2,3,0,1}  //keep looking at "10"
Scan(2) - Swap (10,9) => {8,9,10,6,7,4,5,2,3,0,1}
...
Scan(10) - Swap(10,1) => {8,9,6,7,4,5,2,3,0,1,10}

Fondamentalement, il déplace l'élément le plus élevé à la fin du tableau et, ce faisant, il recommence à chaque analyse de manière efficace en effectuant des O(n^2)mouvements .. uniquement pour cet élément. Cependant, comme il y a n éléments , nous devrons répéter cette nfois. Ce n'est pas une preuve formelle, mais cela aide à comprendre de manière "non formelle" pourquoi le temps est en cours d'exécution O(n^3).


4
Qu'est-ce que cela ajoute aux autres réponses? Une explication de ce que fait l'algorithme a déjà été donnée, et votre raisonnement pour l'exécution est, au mieux, incomplet. (Le pire des cas ne se comporte pas de manière linéaire!)
Raphael

2
Parfois, il est utile d’expliquer la même idée de plusieurs manières (avec le formalisme; avec un exemple simple pour "pomper l’intuition"), en particulier lorsque la personne qui pose la question est nouvelle sur le terrain. Cela me semble donc ajouter que cela est présenté de manière à aider l’intuition.
DW

Depuis que j'ai eu une réponse à mon commentaire dans un drapeau (ne faites pas ça!): "Le pire des cas ne se comporte pas de manière linéaire!" - Je parle des propriétés algébriques de l'opérateur du cas le plus défavorable. Grosso modo, vous utilisez WorstCase (1 + ... + n) "=" WorstCase (1) + ... + WorstCase (n) mais cette identité ne tient pas.
Raphaël

1
Je suis nouveau dans ce domaine et fournir une explication avec un exemple concret et explicite m'a certainement aidé à avoir une intuition sur le problème. Maintenant, la solution acceptée a plus de sens pour moi.
vaer-k

0

La logique semble trier les éléments du tableau dans un ordre croissant.

Supposons que le plus petit nombre se trouve à la fin du tableau (a [n]). Pour qu'il trouve sa place - (n + (n-1) + (n-2) + ... 3 + 2 + 1) opérations sont nécessaires. = O (n2).

Pour un seul élément du tableau, O (n2) est obligatoire. Donc, pour tous les éléments, c’est O (n3).


5
Qu'est-ce que cela ajoute aux autres réponses? Une explication de ce que fait l'algorithme a déjà été donnée, et votre raisonnement pour l'exécution est, au mieux, incomplet. (Le pire des cas ne se comporte pas de manière linéaire!)
Raphael

Grande explication. Cela donne une perspective différente, plus intuitive, du problème, qui n’est pas expliquée dans d’autres réponses. (Sans parler de très court et facile à comprendre.)
2501

1
@ 2501 Non, c'est faux. Essayez d'utiliser cette "intuition" sur l'algorithme de Dijkstra et vous obtiendrez un temps d'exécution quadratique (en nombre de nœuds), ce qui est faux.
Raphaël

@ Raphaël Non, c'est vrai, comme expliqué dans la réponse. Cette explication fonctionne pour cet algorithme, pas pour les autres. Bien que cela puisse être faux pour eux, cette affirmation ne prouve pas que c'est faux pour celui-ci.
2501

@ Raphaël Je n'ai pas compris l'explication de la réponse acceptée. J'ai donc résolu le problème et essayé de l'expliquer en termes simples, sans aucun terme technique. Alors, ceci est destiné aux membres comme moi qui ne comprenaient pas la réponse acceptée.
mk ..
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.