Algorithmie PC 2 : Tris corrigé 1 Tri par bulles

publicité
Algorithmie
PC 2 : Tris
corrigé
1
1.1
Tri par bulles
Principe du tri par Bulles (variante du tri par sélection)
On considère un tableau tab de n données sur lesquelles il existe une relation
d’ordre. On souhaite trier ce tableau dans l’ordre croissant.
Pour cela, on réalise autant de passes sur les données que nécessaire en
échangeant les éléments adjacents s’ils sont dans un mauvais ordre relatif :
parcourir tab[0], ..., tab[n-1] en intervertissant les éléments tab[j-1] et
tab[j] non ordonnés pour tout 1 ≤ j ≤ n − 1.
1.2
Écrire un algorithme mettant en œuvre la méthode décrite.
Algorithme 1 Tri par bulles
Données
tab
n
Début
changement=Vrai
Tant que changement = Vrai faire
changement = Faux
de i =1 a n-2 faire
Si tab[i-1] > tab[i] alors
tempo = tab[i-1]
tab[i-1] = tab[i]
tab[i] =tempo
rendre tab Fin
1
1.3
Tester l’algorithme sur le tableau tab=[10, 7, 8, 4, 5]
L’exécution de l’algorithme est résumé en table 1.
tab[0]
10
7
7
7
7
7
7
7
7
7
7
4
4
4
4
4
4
4
4
4
tab[1]
7
10
8
8
8
8
8
4
4
4
4
7
5
5
5
5
5
5
5
5
tab[2]
8
8
10
4
4
4
4
8
5
5
5
5
7
7
7
7
7
7
7
7
tab[3]
4
4
4
10
5
5
5
5
8
8
8
8
8
8
8
8
8
8
8
8
tab[4]
5
5
5
5
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10
boucle tant que
1
i
1
2
3
4
2
1
2
3
4
3
1
2
3
4
4
1
2
3
4
Table 1: Exécution du tri bulle avec tab=[10, 7, 8, 4, 5]
1.4
Expliquer pourquoi le tri par bulles est bien une méthode de tri ?
Combien de passes sont-elles nécessaires pour trier le tableau ?
C’est bien une méthode de tri (ouf) car à chaque passe un nouvel élément
sera trié et ne changera plus de place. Plus précisément :
• lors de la première passe, l’élément de plus grande valeur est échangé
avec chacun des éléments situés à sa droite (i.e. les éléments d’indices
supérieurs) jusqu’à ce qu’il se trouve à sa place définitive, (à l’extrémité
droite du tableau en tab[n-1]),
• à la seconde passe, c’est l’élément de seconde plus grande valeur qui est
mis à sa place définitive,
• et ainsi de suite . . .
Il y a donc au maximum n passes à effectuer.
2
1.5
Quel est la complextié de cet algorithme ?
Il y a au maximum n boucles “tant que” et dans chaque boucle “tant que”
un parcours de tous les éléments du tableau et des opérations en O(1). La
complexité est donc en O(n2 ).
1.6
Y a-t-il des améliorations possibles à notre algorithme ?
Comme on sait que à la fin de la passe i les i dernières positions du tableau
sont triés, il n’est pas nécessaire de les consulter. Cela ne changera pas la complexité théorique (en O(n2 )) mais réduira tout de même le nombre d’opérations
effectuées.
1.7
Pour quelles types de données cet algorithme est-il efficace ?
Pour des données presque (ou déjà) triées.
2
Tri rapide
Le tri rapide (quicksort pour les anglicistes) est certainement le tri le plus utilisé,
et ceci pour plusieurs raisons, en particulier :
• facile à implémenter,
• efficace pour de nombreux types de données,
• peu gourmand en ressources.
Cependant, il comporte aussi des défauts, en particulier il est récursif et
donc une petite erreur de programmation peut se révéler désastreuse et difficile
à corriger, il effectue un nombre quadratique d’opérations dans le pire des cas
(nlog(n) opérations en moyenne comme vous allez le calculer).
2.1
Algorithme
L’algorithme 2 est une implémentation du tri rapide. Lancer l’algorithme
sur le tableau précédent ([10, 7, 8, 4, 5]). Pourquoi est-ce une
méthode de tri ?
Les variables gauche et droite sont les bornes dans lesquelles le tableau sera
trié. Le principe de l’algorithme est, entre les bornes, de choisir un élément
(pivot) que l’on va placer à l’endroit qu’il occupera lorsque les données seront
triées. Pour cela, on s’arrange pour qu’à gauche de pivot tous les éléments soient
plus petit que lui et qu’à droite tous les éléments soient plus grand que lui.
Une fois ceci fait, on relance l’algorithme pour les parties à gauche et à droite
de pivot.
3
Algorithme 2 Tri rapide. Initialisé par gauche=0 et droite=n-1
Données
tab
gauche
droite
Début
Si droite > gauche alors
stop = Faux
i = gauche
j = droite-1
pivot = tab[droite]
Tant que stop = Faux faire
(1)
tant que tab[i] < pivot faire
i = i+1
(2)
tant que tab[j] > pivot faire
j = j-1
Si i≥j alors
stop = vrai
Sinon
(3)
tempo = tab[i]
tab[i] = tab[j]
tab[j] = tempo
(4)
i=i+1
j=j-1
(5) tempo = tab[i]
tab[i] = tab[droite]
tab[droite] = tempo
(6) triRapide(tab, gauche,i-1)
(7) triRapide(tab, i+1,droite)
rendre tab Fin
4
Plus précisément, à la fin de (1) et (2) i pointe sur la première occurrence du
tableau après gauche plus grande que pivot et j sur la plus grande occurrence
du tableau avant droite plus petite que pivot.
Si i<j, toute les valeurs n’ont pas été regardées et on peu échanger tab[i]
et tab[j] (étape (3)) pour agrandir notre recherche (après l’échange, tous les
éléments plus petit que i sont < que pivot et tous les éléments plus grand que j
sont > pivot. Avant l’échange tab[i]=>pivot et tab[j]<=pivot). On peut donc
réitérer les étapes (1) et (2).
Une fois que i>= j, tous les éléments entre gauche et droite ont été vus, et,
tous les éléments de gauche à i-1 sont plus petit ou égaux à pivot et tous les
éléments entre i et droite sont plus grand ou égaux à pivot. L’échange entre
tab[i] et tab[droite] (étape 5) nous assure donc que la place de la valeur pivot
restera inchangée à la suite du tri (c’est à dire que l’on peut trouver un tri du
tableau où la valeur de tab[i] sera pivot).
Il ne nous reste plus qu’à trier les bouts de tableaux restant, c’est à dire les
éléments entre gauche et i-1 (étape 6) et ceux entre i+1 et droite (étape 7).
2.2
Cette méthode de tri est-elle stable ?
Non, car la position finale du pivot ne peut être connue et donc il n’y a
aucune raison que la méthode soit stable.
2.3
Quelle est la complexité (au pire) de cet algorithme ?
À chaque étape, un élément est trié. Tri Rapide est donc lancé au maximum
n fois. La complexité de la boucle “tant que stop=Faux” incrémente deux
compteur i et j, et s’arrête lorsque i ≥ j. Le nombre d’opérations est donc de
l’ordre de O(n). La complexité finale de l’algorithme est donc en O(n2 ).
2.4
Complexité moyenne
La formule de récurrence de la complexité moyenne peut être construite
comme suit : C(N) = “opérations de la boucle tant que stop=Faux” + “moyenne
du nombre d’opérations effectué par les deux appels récursifs”
La première partie est linéaire, on peut donc la borner par p.N où p est une
constante quelque soit N.
Pour la deuxième partie, la taille des tableaux qui vont être passés aux appels
récursifs n’est pas connue, et dépend de la position finale du pivot. Si c’est la
position k du tableau qui est la position finale du pivot, le nombre d’opérations
effectués par ces appels est C(k-1) + C(N-k). Chaque case du tableau ayant
une probabilité 1/N d’êtreP
la position finale du tableau, donc le nombre moyen
d’opérations est : (1/N ) ∗ 1≤k≤N (C(k − 1) + C(N − k)).
5
L’équation que nous avons à résoudre est donc :
X
C(N ) = pN + 1/N
(C(k − 1) + C(N − k))
1≤k≤N
Avec comme conditions initiales C(1) = C(0) = 0.
C(N )
P
= pN + 1/N 1≤k≤N (C(k − 1) + C(N − k))
P
P
= pN + 1/N ∗ 1≤k≤N C(k − 1) + 1/N ∗ 1≤k≤N C(N − k)
P
= pN + 2/N ∗ 1≤k≤N C(k − 1)
P
On a donc N C(N ) − pN 2 = 2 1≤k≤N C(k − 1). Ainsi (N − 1)C(N − 1) −
P
p(N − 1)2 = 2 1≤k≤N −1 C(k − 1), et donc : N C(N ) − pN 2 = (N − 1)C(N −
1) − p(N − 1)2 + 2C(N − 1), et finalement :
N C(N ) = p(2N − 1) + (N + 1)C(N − 1)
en divisant l’équation ci-avant par N (N + 1) on obtient : C(N )/(N + 1) =
2p/(N + 1) − p/(N (N + 1)) + C(N − 1)/N = 2p/(N + 1)
P − p/(N (N + 1)) +
2p/(N
)
−
p/(N
(N
−
1))
+
C(N
−
2)/(N
−
1)
=
...
=
3≤k≤N 2/(k + 1) −
P
p/(k(k
+
1)).
3≤k≤N
P
P
On a ainsi C(N )/(N + 1) ≤ 2 1≤k≤N 1/k. Comme
1≤k≤N 1/k est
équivalent à ln(N ), on en conclut bien que C(N )/(N + 1) est en O(ln(N ))
et donc que C(N ) est en O(N ∗ ln(N )).
6
Téléchargement