ALGORITHMES DE TRI INTERNE - WordPress.com · 2020. 2. 13. · Tri ?IFT2015 H2020 ?UdeM ?Miklós...
Transcript of ALGORITHMES DE TRI INTERNE - WordPress.com · 2020. 2. 13. · Tri ?IFT2015 H2020 ?UdeM ?Miklós...
-
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös
ALGORITHMES DE TRI INTERNE
-
Clés comparables
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös ii
On a un fichier d’éléments avec clés comparables— on veut les ranger selon l’ordre les clés
Clés comparables en Java :
public interface Comparable{
int compareTo(T autre_objet);}
public interface Comparator{
int compare(T un_objet, T autre_objet);}
x.compareTo(y) est négatif si x précède y, ou positif si x suit y dans l’ordre«naturel» des éléments
-
Tri interne
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös iii
Tri interne : tout le fichier est en mémoire(représenté par un tableau ou une liste chaînée)
Tri externe : fichier stocké partiellement ou entièrement en mémoire externe(disque)— accès à mémoire externe est couteux. . .
Entrée : tableau A[] de données — on veut le trier
Solutions :
N tri par sélection (selection sort)N tri par insertion (insertion sort)N tri fusion (Mergesort)N tri par tas (Heapsort)N tri rapide (Quicksort)
-
Créer le désordre
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös iv
comment ordonner un tableau au hasard ?= comment créer une permutation uniformement distribuée
récurrence pour la permutation uniforme des éléments d’un ensemble A :un élément a ∈ A pour placer au premier + permutation de A \ {a}
SHUFFLE(A[0..n− 1]) // met les éléments de A dans un ordre aléatoireU1 for i← 0,1, . . . , n− 1 doU2 j ← i+ rnd(n− i) // rnd(m) entier pseudo-aléatoire sur 0..m− 1U3 échanger A[i]↔ A[j] //j ∈ {i, i+ 1, . . . , n− 1}
�on peut défaire un tri en temps linéaire
-
Tri par sélection
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös v
Algo TRI-SELECTION(A[0..n− 1])S1 for i← 0,1, . . . , n− 2 doS2 minidx← iS3 for j ← i+ 1, . . . , n− 1 doS4 if A[j] < A[minidx] then minidx← j
// maintenant A[minidx] = min{A[i], . . . , A[n]}S5 if i 6= minidx then échanger A[i]↔ A[minidx]
Complexité :
? comparaison d’éléments n(n−1)2 ∼ n2/2 toujours ;
? échange d’éléments [ligne S5] ≤ (n− 1) foisTemps de calcul : toujours quadratique�mais pas nécessairement une mauvaise idée si l’échange est beaucoup plus cherque la comparaison
-
Tri par insertion
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös vi
public void isort(double[] A){
for (int i=1; i
-
Tri par tas
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös vii
HEAPSORT(A[1..n]) // tri du tableau A[1..n]H1 for i← bn/2c, . . . ,1 do sink(A[i], i) // heapifyH2 while n > 1 doH3 échanger A[1]↔ A[n]H4 sink(A[1],1)H5 n← n− 1
Complexité : ∼ 2n lgn comparaisons et ∼ n lgn échanges au pire
Mémoire : tri en place (aucun tableau auxiliare nécessaire)
-
Tri fusion
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös viii
9 6 3 0 2 1 8 7 5 4
9 6 3 0 2 1 7 5 4
division 50-50% sans réarrangement
récursion
0 2 3 6 9 1
récursion
4 5 7 8
fusionner en O(n)
8
n/2 éléments n/2 éléments
0 1 2 3 4 5 6 7 8 9
Algo MERGESORT(A[0..n− 1], g, d) // premier appel avec g = 0, d = n// récursion pour trier le sous-tableau A[g..d− 1]
M1 if d− g < 2 then return // cas de base : tableau vide ou un seul élémentM2 m←
⌊(d+ g)/2
⌋// m est au milieu
M3 MERGESORT(A, g,m) // trier partie gaucheM4 MERGESORT(A,m, d) // trier partie droiteM5 FUSION(A, g,m, d) // fusion des résultats
-
Fusion «en place»
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös ix
FUSION(A, g,m, d) doit fusionner les sous-tableauxA[g..m−1] etA[m..d−1]avec m =
⌊(d+ g)/2
⌋, et placer le résultat dans A[g..d− 1]
solution : utiliser un tableau auxiliare aux[0..n − 1], et copier aux[g..d − 1] ←A[g..d− 1] pour la fusion
Algo FUSION(A[ ], g,m, d) // fusion «en place» pour A[g..m− 1] et A[m..d− 1]F1 for i← g, g + 1, . . . , d− 1 do aux[i]← A[i]F2 i← g ; j ← m ; k ← gF3 while i < m && j < d doF4 if aux[i] ≤ aux[j] then A[k]← aux[i] ; i← i+ 1; k ← k + 1F5 else A[k]← aux[j] ; j ← j + 1; k ← k + 1F6 while i < m do A[k]← aux[i] ; i← i+ 1; k ← k + 1F7 while j < d do A[k]← aux[j] ; j ← j + 1; k ← k + 1 // n’est pas nécessaire
� à noter que la boucle de la Ligne F7 n’est pas nécessaire car A[j..d − 1] =aux[k..d− 1]
-
Fusion — arrangement bitonique
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös x
4 6 8 9 1 2 5 7
4 6 8 9 7 5 2 1
A
aux
trié trié
bitonique
Algo FUSION(A[ ], g,m, d) // fusion «en place» pour A[g..m− 1] et A[m..d− 1]F1 for i← g, g + 1, . . . ,m− 1 do aux[i]← A[i]F2 for j ← m,m+ 1, . . . , d− 1 do aux[m+ d− 1− j]← A[j]F3 i← g ; j ← d− 1 ; k ← gF4 while k < d do // meilleure condition : i < mF5 if aux[i] ≤ aux[j] then A[k]← aux[i] ; i← i+ 1; k ← k + 1F6 else A[k]← aux[j] ; j ← j − 1; k ← k + 1
-
Mergesort — efficacité
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xi
Nombre de comparaisons : ∼ n lgn au pire
O(n)
O(n)
O(n)
O(n)
lg n niveaux de récurrences
Meilleur temps : ∼ 12n lgn comparaisons (déjà trié : fusion avec ∼ n/2 compa-raisons)Moyen temps : ∼ n lgn (fusion avec n− 2 comparaisons en moyenne)
Mémoire : tableau auxiliaire (n éléments)
-
Tri binaire
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xii
Clés : 0 ou 1
0 0 1 0 0 1 0 1 1 1
i j
échanger
TRI01(A[0..n− 1]) // tri binaireB1 i← 0 ; j ← n− 1B2 loopB3 while i < j && A[i] = 0 do i← i+ 1B4 while i < j && A[j] = 1 do j ← j − 1B5 if i < j then échanger A[i]↔ A[j]B6 else return
� tri en temps linéaire si seulement 2 clés
-
Tri rapide
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xiii
1. choisir un élément ( pivot ), le placer dans sa case finale i, mettre tous les élé-ments inférieurs en A[0..i−1] et tous les éléments supérieurs en A[i+ 1..n−1]
partition en O(n)
≤ p ≥ p
p
récursion récursion
aucune combinaison nécessaire
2. trier A[0..i− 1] et A[i+ 1..n− 1] (récurrence)
-
Partition
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xiv
� suivre la technique du tri binaire avec deux indices i, j pour balayer4 2 8 1 3 9 1 7 2 6 8 5pivot = 5
4 2 8 1 3 51 7 2 6 89
4 2 2 1 3 51 7 8 6 89
4 2 2 1 3 59 7 8 6 81
4 2 2 1 3 95 7 8 6 81
échanger
échanger
fin de balayer
remettre le pivot
i j
≤5
4 2 2 1 3 1 97 8 6 8
≥5
partition complète
-
Quicksort
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xv
Algo QUICKSORT(A[0..n− 1], g, d) // tri de A[g..d− 1]Q1 if d− g ≤ 1 then return // cas de baseQ2 i← PARTITION(A, g, d)Q3 QUICKSORT(A, g, i)Q4 QUICKSORT(A, i+ 1, d)
Algo PARTITION(A, g, d) // partition de A[g..d− 1]P1 chosir le pivot p← A[d− 1]P2 i← g − 1 ; j ← d− 1P3 loop // condition terminale à P6P4 do i← i+ 1 while A[i] < pP5 do j ← j − 1 while j > i et A[j] > pP6 if i ≥ j then sortir de la boucle (continuer à P8)P7 échanger A[i]↔ A[j]P8 échanger A[i]↔ A[d− 1] // mettre le pivot en placeP9 return i
-
Profondeur de la pile
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xvi
Il y a 2 appels récursifs, mais 1 est terminal→ on peut le faire en une boucle, et faire juste 1 appel récursif
Algo QUICKSORT_ITER(A[0..n− 1], g, d) // tri de A[g..d− 1]QI1 while d− g > 1 doQI2 i← PARTITION(A, g, d)QI3 QUICKSORT_ITER(A, g, i)QI4 g ← i+ 1 // boucler au lieu de l’appel récursif
? on peut également appeler QUICKSORT_ITER(A, i+1, d) et faire d← idans la boucle
? si on décide de faire l’appel récursif sur le plus petit des deux sous-tableaux(comparer i− g et d− i)⇒ profondeur ≤ 1 + blgnc sûrement
Usage de mémoire : logarithmique (mais non pas constante) au pire avec cet astuce⇒ tri en place
-
Tri hybride
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xvii
Génie algorithmique : tri par insertion est rapide quand n est petit
? Mergesort — approche hybride : utiliser insertion sort sur [g..d−1] quandle sous-tableau devient petit
Algo MERGESORT(A[0..n− 1], g, d) // premier appel avec g = 0, d = nM1 if d− g < seuil thenM2 for i← g + 1, g + 2, . . . , d− 1 doM3 x← A[i] ; j ← d− 1M4 while j > g && A[j − 1] > x do A[j]← A[j − 1] ; j ← j − 1M5 A[j]← xM6 return
// ... cas récursif comme usuel
? Quicksort — approche hybride : retourner de la récurrence immédiatementquand d− g < seuil+ lancer tri par insertion une fois à la toute fin sur le tableau entier
-
Tri rapide — performances
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xviii
Nombre de comparaisons quand le pivot est le i-ème élément :
C(n) = (n− 1) + C(i− 1) + C(n− i).
La récurrence dépend de l’indice i du pivot.
pivot i récurrence solution
Meilleur cas n/2 2 · C((n− 1)/2)
)+ (n− 1) ∼ n lgn
Pire cas 0, n− 1 C(n− 1) + (n− 1) ∼ n2/2Moyen cas aléatoire EC(n) = 2EC(i) + (n− 1) ∼ 2n lnn? le meilleur cas donne une récurrence essentiellement identique à celle de
mergesort? le pire cas arrive quand on a un tableau trié au début !? on examinera le cas moyen
-
Choix du pivot
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xix
Deux choix performent très bien en pratique : médiane ou aléatoire.
P1.1 k ← g + rnd(d− g) // pivot choisi au hasardP1.2 p← A[k]P1.3 A[k]← A[d− 1]P1.4 A[d− 1]← p
? ainsi, on a un algorithme randomisé : temps de calcul est une variablealéatoire
? distribution du temps de calcul est la même pour toute entrée de mêmetaille
? temps en espérance pour une entrée avec l’algo randomisé est le mêmeque l’espérance du temps de l’algo déterministe sur une entrée aléatoire(SHUFFLE)
-
Médiane de trois
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xx
choisir 3 éléments, prendre leur médiane comme pivot
P1.1 if d ≥ g + 2 thenP1.2 if A[g] > A[d− 2] then échanger A[g]↔ A[d− 2]P1.3 if A[d− 1] > A[d− 2] then échanger A[d− 1]↔ A[d− 2]P1.4 if A[g] > A[d− 1] then échanger A[g]↔ A[d− 1]P1.5 p← A[d− 1] // A[g] ≤ A[d− 1] ≤ A[d− 2]
et on se sert des sentinelles qui sont maintenant en place à A[g], A[d− 2] :
P2’ i← g; j ← d− 2P5’ do j ← j − 1 while A[j] > p
-
Tri rapide – analyse
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxi
Déf. Soit D(n) le nombre moyen de comparaisons avec un pivot aléatoire, où nest le nombre d’éléments dans un tableau A[· · · ].
Lemme. On a D(0) = D(1) = 0, et
D(n) = n− 1 +1
n
n−1∑i=0
(D(i) +D(n− 1− i)
)
= n− 1 +2
n
n−1∑i=0
D(i).
Preuve. Supposons que le pivot est le i-ème plus grand élément de A. Le pivotest comparé à (n−1) autre éléments pour la partition. Les deux partitions sont detailles (i − 1) et (n − 1 − i). Or, i prend les valeurs 1,2, . . . , n avec la mêmeprobabilité. �
-
Performance moyenne (cont.)
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxii
Par le lemme précédent,
nD(n)− (n− 1)D(n− 1) =(n(n− 1) + 2
n−1∑i=0
D(i))
−(
(n− 1)(n− 2) + 2n−2∑i=0
D(i))
= 2(n− 1) + 2D(n− 1).D’où on a
D(n)
n+ 1=D(n− 1)
n+
2n− 2n(n+ 1)
=D(n− 1)
n+
4
n+ 1−
2
n
=
(4
2+
4
3+
4
4+ · · ·+
4
n+ 1
)−(
2
1+
2
2+
2
3+ · · ·+
2
n
)
= 2
(1
1+
1
2+ · · ·+
1
n
)︸ ︷︷ ︸
nombre harmonique Hn
−4 +4
n+ 1
-
Performance moyenne (cont.2)
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxiii
Donc,
D(n) = 2(n+ 1)Hn − 4n
avec le n-ième nombre harmonique
Hn = 1 +1
2+
1
3+ · · ·
1
n= lnn+ γ +O(1/n) ∼ lnn
où γ = limn→∞(Hn − lnn) = 0.5772 · · · est la constante d’Euler.
Théorème. Le tri rapide avec pivotage aléatoire fait
D(n) ∼ 2n lnn ≈ 1.39n lgn
comparaisons en moyenne pour trier n éléments.
-
Le minimum de comparaisons dans un tri
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxiv
Méthode : imaginer l’arbre de décision de toutes exécutions possibles? nœuds internes : comparison entre 2 éléments? 2 enfants : branchement selon vrai ou faux dans la comparaison? nœuds externes : permutation finale (résultat du tri)
-
Arbre de décision : insertion sort, n = 4
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxv
A[0]
-
Minimum de comparaisons
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxvi
? l’arbre a au moins n! nœuds externes (au moins 1 par permutation)? la hauteur de l’arbre est le nombre maximal de comparaisons sur n éléments? or, pour un arbre binaire avec m nœuds externes,
hauteur ≥ lgm ≥ lg(n!) = lg 1 + lg 2 + · · ·+ lgn
formule de Stirling :
n! =√
2πn(n
e
)n︸ ︷︷ ︸
formule de Stirling
× exp(θn
12n
)︸ ︷︷ ︸
erreur de l’ordre 1/n
{0 < θn < 1}
alors
lg(n!) = n lgn− n lg e+O(logn) ∼ n lgn
Théorème. Tout algorithme déterministe de tri doit faire au moins ∼ n lgncomparaisons au pire pour trier n éléments.
-
Nos tris
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxvii
Méthode de tri interne comparaisons espace de travailtri par sélection (selection sort) ∼ n2/2 (toujours) O(1)tri par insertion (insertion sort) ∼ n2
2(pire), ∼ n2
4(moyen), ∼ n (meilleur) O(1)
tri fusion (Mergesort) ∼ n lgn (toujours) Θ(n)tri par tas (Heapsort) ∼ 2n lgn (pire), Θ(n logn) (toujours) O(1)tri rapide (Quicksort) ∼ 2n lnn (moyen), n2/2 (pire) O(logn)borne inférieure ∼ n lgn (pire)
Adaptation au tri de liste chaînée : tous sauf tri par tas
Théorème. Le tri fusion est asymptotiquement optimal.
-
Sélection / médiane : QuickSelect
Tri ? IFT2015 H2020 ? UdeM ? Miklós Csűrös xxviii
chercher k-ème plus petit élément dans A[0..n− 1]
Idée de clé : après avoir appellé i ← PARTITION(A,0, n), on trouve le k-èmeélément en A[0..i−1] si k < i ou en A[i+1..n−1] si k > i. En même temps,on réorganise le tableau pour que A[k] soit le k-ème plus petit élément.
Algo SELECTION(A[0..n− 1], g, d, k)S1 if d− g ≤ 2 then // cas de base : 1 ou 2 élémentsS2 if d = g + 2 et A[d− 1] < A[g] then échanger A[g]↔ A[d− 1] // 2 élémentsS3 return A[k]S4 i← PARTITION(A, g, d)S5 if k = i then return A[k] // on l’a trouvéS6 if k < i then return SELECTION(A, g, i, k) // continuer à la gaucheS7 if k > i then return SELECTION(A, i+ 1, d, k) // continuer à la droite