• Aucun résultat trouvé

Tri rapide (quicksort)

Dans le document Notes de programmation (C) et d'algorithmique (Page 129-132)

Le coˆut moyen est donc infini !

Exercice 19 Consid´erez la fonction C suivante qui effectue une recherche ‘al´eatoire’ d’un ´

el´ement dans un tableau.

1 int rs (int x , int n , int t [ n ]){

2 s h o r t c h e c k [ n ]; 3 int i ; 4 for ( i =0; i < n ; i + + ) { 5 c h e c k [ i ] = 0 ; } 6 int c o u n t =0; 7 w h i l e ( c o u n t < n ){ 8 int i =(r a n d()% n ); 9 if ( t [ i ]== x ){ 10 r e t u r n i ;} 11 if (! c h e c k [ i ]){ 12 c h e c k [ i ] = 1 ; 13 c o u n t + + ; } } 14 r e t u r n -1;}

Calculez (de fa¸con exacte ou approch´ee) le nombre moyen d’appels `a la fonction rand dans les cas suivants :

1. Le tableau contient l’´el´ement cherch´e 1 fois. 2. Le tableau contient l’´el´ement cherch´e k fois. 3. Le tableau ne contient pas l’´el´ement cherch´e.

17.2 Tri rapide (quicksort)

On consid`ere un algorithme dit de tri rapide (quicksort, en anglais) [Hoa61].2

Algorithme de partition

Le tri rapide est bas´e sur une fonction de partition qui prend en entr´ee un ensemble fini de valeurs X et une valeur pivot v et g´en`ere l’ensemble X1 des valeurs dans X strictement inf´erieurs `a v et l’ensemble X2 des valeurs dans X sup´erieurs ou ´egales `a v. Supposons que X contienne n valeurs. Si X est repr´esent´e par une liste alors il est clair que l’on peut produire les deux listes qui repr´esentent les ensembles X1 et X2 en O(n). Si X est repr´esent´e par un tableau a alors il est remarquable que l’on peut g´en´erer X1 et X2 en temps O(n) et sans effectuer d’allocation de m´emoire (en anglais, on dit aussi que l’algorithme travaille in place). Supposons que les ´el´ements de l’ensemble `a partitionner sont m´emoris´es dans les cellules d’indice compris entre i et j avec i < j On it`ere :

2. Cet algorithme est dans une top 10 d’algorithmes du XX si`ecle (voir https://www.siam.org/pdf/news/ 637.pdf).

Algorithmes probabilistes 129

1. Tant que a[i] < v on incr´emente i. Si i ‘croise’ j on sort de l’it´eration. 2. Tant que v ≤ a[j] on d´ecr´emente j. Si j ‘croise’ i on sort de l’it´eration.

3. Si on arrive `a ce point, on doit avoir a[i] ≥ v et a[j] < v. On permute a[i] avec a[j] et on reprend l’it´eration (pas 1).

Il est facile de modifier l’algorithme pour qu’`a la fin de la partition il retourne l’indice `

a partir duquel on trouve les ´el´ements plus grands ou ´egaux que le pivot (et une valeur conventionnelle s’il y en a pas). Dans la suite, on appelle cet indice le point de partition.

Algorithme de tri

On consid`ere maintenant l’application de l’algorithme de partition au probl`eme du tri. On suppose que les donn´ees `a trier sont stock´ees dans un tableau a dans les positions comprises entre min et max et on prend a[max] comme pivot. Si min = max on a rien `a faire ! Sinon :

— soit k le point de partition par rapport au pivot,

— si k<max on ´echange a[k] avec a[max] ; on met donc le pivot au point de partition, — si n´ecessaire, on calcule r´ecursivement qsort(min,k-1) et qsort(k+1,max).

Complexit´e dans le pire des cas et en moyenne

Le pire des cas est quand toutes les partitions sont d´es´equilibr´ees. Par exemple, si le tableau est d´ej`a ordonn´e (SIC). Dans ce cas, le coˆut est quadratique. Pourtant, le qsort est un algorithme de choix pour effectuer le tri. Par exemple, il est dans la biblioth`eque standard de C. Le fait est qu’en moyenne l’algorithme a une complexit´e O(n log n) (qui est bien meilleure que quadratique !). Par ailleurs, l’op´eration de partition est efficace (en temps et en m´emoire). Il y a deux fa¸cons d’analyser le comportement moyen du tri rapide. La premi`ere fa¸con (qui est celle ´etudi´ee dans la suite) est de le transformer dans un algorithme probabiliste qui `

a chaque appel r´ecursif choisit le pivot de fa¸con al´eatoire. Dans cette approche on ne fait pas d’hypoth`ese sur la distribution des donn´ees en entr´ee. Ce qu’on montre est que pour toute entr´ee, en choisissant les pivots de fa¸con al´eatoire on aura un coˆut moyen en O(n log n). Une deuxi`eme fa¸con de proc´eder est de supposer une distribution uniforme des donn´ees. Dans ce cas, on peut garder la version d´eterministe de l’algorithme (par exemple celle dans laquelle le pivot est toujours l’´el´ement le plus `a droite) et montrer que le coˆut moyen (sur toutes les entr´ees) est O(n log n). L’analyse de cette deuxi`eme approche est similaire `a celle de la premi`ere et elle est omise.

Tri rapide : version probabiliste

La seule diff´erence dans la version probabiliste du tri rapide est que pour trier les posi-tions comprises entre min et max on commence par tirer un indice i tel que min ≤ i ≤ max avec probabilit´e uniforme et on permute a[i] avec a[max]. Le pivot est donc choisi avec une probabilit´e uniforme.

Analyse du tri rapide probabiliste

On suppose tous les ´el´ements `a trier diff´erents. Pour simplifier la notation on d´enote ces ´el´ements par 1, 2, · · · , n. Par exemple, 2 est le deuxi`eme plus petit ´el´ement. Au d´ebut du tri sa position est arbitraire mais `a la fin du tri on sait qu’il sera en deuxi`eme position

`

a partir de gauche. Comme souvent dans les algorithmes de tri, on consid`ere que le coˆut est proportionnel au nombre de comparaisons et on s’attache donc `a compter le nombre de comparaisons effectu´ees en moyenne par l’algorithme. Ce nombre d´epend du choix al´eatoire des pivots. On repr´esente un calcul par la suite des pivots choisis. Soit Ω l’ensemble de ces suites. On d´efinit une v.a.d. X qui associe `a chaque suite le nombre de comparaisons effectu´ees par le tri rapide. Le but est de calculer l’esp´erance E[X].

Remarque 18 Soient i, j ∈ {1, . . . , n} avec i < j deux ´el´ements `a trier. Dans toute ex´ecution, i et j sont compar´es au plus un fois. En effet, l’algorithme compare un pivot aux autres ´

el´ements d’une partition. Donc pour comparer i et j il faut que l’un des deux soit un pivot et l’autre se trouve dans la mˆeme partition. Par ailleurs, dans la suite du calcul le pivot ne sera plus compar´e `a un autre ´el´ement (`a la fin de la partition le pivot se trouve `a la bonne place).

On va maintenant utiliser une technique standard du calcul des probabilit´es : on exprime la v.a.d. X comme une somme de v.a.d. de Bernoulli dont on sait calculer l’esp´erance. Ensuite on utilise la lin´earit´e de l’esp´erance pour d´eriver l’esp´erance de X. Pour ω ∈ Ω une suite de comparaisons, on d´efinit :

Xi,j(ω) = 

1 si i et j sont compar´es dans ω 0 autrement.

On observe :

X = Σ1≤i<j≤nXi,j . Et par lin´earit´e :

E[X] = Σ1≤i<j≤nE[Xi,j] . Il reste donc `a calculer E[Xi,j].

D´efinition 15 (probabilit´e de comparaison) On note P (i, j, n) = E[Xi,j] la probabilit´e que i et j sont compar´es dans un tri rapide avec n ´el´ements, o`u 1 ≤ i < j ≤ n.

Une premi`ere remarque est que P (i, j, n) satisfait une relation de r´ecurrence.

Proposition 13 La fonction P (i, j, n) satisfait : P (1, 2, 2) = 1

P (i, j, n) = n2 +1n· ( Σk=1,...,(i−1) P (i − k, j − k, n − k) + Σk=(j+1),...,nP (i, j, k − 1) ) .

Preuve. Pour comparer i `a j, soit on prend le pivot dans {i, j} soit on le prend avant i ou

apr`es j. 2

Une deuxi`eme remarque (assez surprenante) est que P (i, j, n) ne d´epend pas de n.

Proposition 14

P (i, j, n) = 2 (j − i + 1) .

Algorithmes probabilistes 131

Preuve. Par r´ecurrence sur n. Pour n = 2 on a bien P (1, 2, 2) = 2−1+12 = 1. Plus en g´en´eral : P (i, i + 1, n) = 1. Pour n + 1 > 2 on a : P (i, j, n + 1) = n+12 +n+11 ( Σk=1,...,(i−1) P (i − k, j − k, n + 1 − k) + Σk=(j+1),...,n+1P (i, j, k − 1) ) = n+12 +n+11 ( Σk=1,...,(i−1) j−i+12 + Σk=(j+1),...,n+1 j−i+12 ) = n+12 +n+11 2(n−j+i)j−i+1 = j−i+12 . 2 Proposition 15 E[X] est O(n log n).

Preuve. On calcule :

E[X] = Σi=1,...,(n−1)Σj=i+1,...,n(j−i+1)2 = 2 · (Σi=1,...,n−1k=1,...,(n−i)(k+1)1 )) ≤ 2 · (Σi=1,...,n−1k=1,...,n1k)) . On approxime la somme par un int´egral pour obtenir :

Σx=2,...,m

Dans le document Notes de programmation (C) et d'algorithmique (Page 129-132)