• Aucun résultat trouvé

Tri rapide (quicksort)

N/A
N/A
Protected

Academic year: 2022

Partager "Tri rapide (quicksort)"

Copied!
8
0
0

Texte intégral

(1)

Tri rapide (quicksort)

1 L'algorithme

1.1 Principe

SoitL une liste à trier.

- On choisit par exemple le premier élément de la liste (le pivot).

- On sépare la liste en deux autour du pivot, à sa gauche les éléments plus petits, à sa droite les éléments plus grands.

- Ensuite on trie indépendamment les deux sous-listes.

1.2 Premier programme

Avec des listes auxiliaires.

1.3 Tri rapide en place

Le programme précédent utilise des listes auxiliaires.

On va voir ici qu'on peut eectuer un 'tri en place', qui n'utilise que très peu de mémoire.

On vérie au passage que seulement

n−1

comparaisons sont eectuées par la fonction partition sur une liste de longueurn.

1.4 Que trier ?

L'algorithme ne s'applique pas qu'à des listes de nombres.

Il sut que l'ensemble soit muni d'une relation d'ordre total : chaînes de caractères pour l'ordre lexicographique par exemple.

1

(2)

def tri_rapide(L):

if L == []:

return([]) a = L[0]

L1 = [k for k in L[1:] if k <= a]

L2 = [k for k in L[1:] if k > a]

return(tri_rapide(L1) + [a] + tri_rapide(L2))

def partition(t):

n, pivot = len(t), t[0]

limite = 1

for indice in range(1, n):

if t[indice] < pivot:

t[indice], t[limite] = t[limite], t[indice]

limite += 1

t[0], t[limite - 1] = t[limite - 1], t[0]

'''La fonction partition sépare les éléments de t en fonction du pivot.

Invariants, vérifiés à l'entrée de la boucle : 1 <= limite <= indice

t[: limite] ne contient que des éléments inférieurs ou égaux au pivot t[0]

t[limite : indice] ne contient que des éléments supérieurs ou égaux au pivot.'''

1

(3)

# tri rapide en place

'''La fonction partition sépare les éléments de t[debut:fin] en deux à l'aide du pivot.

Invariants, vérifiés à l'entrée de la boucle : 1 + debut <= limite <= k

t[debut : limite] ne contient que des éléments inférieurs ou égaux au pivot t[debut]

t[limite : k] ne contient que des éléments supérieurs ou égaux au pivot.'''

def partition(t, debut, fin):

pivot = t[debut]

limite = 1 + debut

for k in range(1 + debut, fin):

if t[k] < pivot:

t[k], t[limite] = t[limite], t[k]

limite += 1

t[debut],t[limite - 1] = t[limite - 1],t[debut]

return limite - 1 # retourne la nouvelle # position du pivot

def tri_rapide_en_place(t, debut, fin):

if fin > 1 + debut:

pos_pivot = partition(t, debut, fin) tri_rapide_en_place(t, debut, pos_pivot) tri_rapide_en_place(t, 1 + pos_pivot, fin) def tri(L):

tri_rapide_en_place(L, 0, len(L))

1

(4)

2 Le tri rapide avec une pile

4

(5)

def partition(t, debut, fin):

pivot = t[debut]

limite = 1 + debut

for k in range(1 + debut, fin):

if t[k] < pivot:

t[k], t[limite] = t[limite], t[k]

limite += 1

t[debut], t[limite - 1] = t[limite - 1], t[debut]

return limite - 1 # retourne la nouvelle # position du pivot def tri_rapide_a_mains_nues(t):

n = len(t)

tache = [0,n] # intervalle à trier pile_des_taches = [tache]

while pile_des_taches != []:

tache = pile_des_taches.pop()

[debut, fin] = tache # intervalle à trier if fin > 1 + debut:

pos_pivot = partition(t, debut, fin)

pile_des_taches.append([debut, pos_pivot]) pile_des_taches.append([1 + pos_pivot, fin])

1

(6)

3 Complexité

3.1 Cas défavorable

NotonsC(n)le nombre de comparaisons à eectuer entre éléments de la liste.

Liste déjà triée ;C(n) =n−1 +C(n−1); d'où : C(n) =n(n−1)

2 donc, complexité enn2.

Dans ce cas, le tri rapide est moins ecace que le tri par insertion.

Il est possible de diminuer le risque en choisissant un pivot aléatoire.

3.2 Cas favorable

Le cas où à chaque étape, le tableau se sépare miraculeusement en deux tableaux de même longueur.

Quelles sont les valeurs denpossibles ? Réponse

n= 2q−1; dans ce cas, le nombre de comparaisons vérie : C(n) =n−1 + 2.C

n−1 2

Notonsuq =C(2q−1) ; alorsuq = 2q−2 + 2.uq−1. Par simple substitution, on obtient

uq =C(n) = 2q(q−2) + 2

En résumé : C(n)∼n.logn.

3.3 En moyenne

On peut montrer que le nombre moyen de comparaisonsCn sur un tableau de taillenvérie :

Cn =n−1 + 2 n

n−1

X

j=0

Cj

avecC0=C1= 0 ; on en tire :

Cn= 2(n+ 1)

n−1

X

j=1

j (j+ 1) (j+ 2) puis

Cn∼2n.lnn

4 Complément : complexité dans le cas général

On appelle hauteur d'un noeud la longueur du chemin de la racine à ce noeud.

On montre par récurrence surN que pour tout arbre binaire àN feuilles, la hauteur moyenne d'une feuillehmvérie :

log2(N)≤hm

Remarque préliminaire

En utilisant la convexité dex→x.log2(x):

∀x >0,∀y >0,(x+y).log2x+y

2 ≤x.log2x+y.log2y

6

(7)

Démonstration

PourN = 1ouN = 2, c'est clair.

SoitN ≥3 etAun arbre binaire àN feuilles.

Ses deux sous-arbres ontN1et N2 feuilles, avecN =N1+N2. D'après l'hypothèse de récurrence :

log2(N1)≤h1,log2(N2)≤h2 D'où :

hm= 1 +N1h1+N2h2

N ≥1 + 1

N (N1.log2(N1) +N2.log2(N2)) Donc

hm≥1 + 1

N.(N1+N2).log2N1+N2

2 = log2(N) Conséquence

PourN =n!:

hm≥log2(n!) Par ailleurs,

ln (n!)≥ ˆ n

1

ln (t) dt=n.ln (n)−n+ 1

On en déduit que tout algorithme de tri nécessite en moyenne au moinsC.n.ln (n)comparaisons.

5 Un algorithme de tri de complexité linéaire ?

Proposer un algorithme de complexité linéaire (enO(n)),

pour trier un tableau denentiers, pas nécessairement distincts, contenus dans[0,3∗n]. Est-ce en contradiction avec ce qui précède ?

7

(8)

import random as rd

N = 10 def tri(t):

n = len(t)

compteur = [0 for k in range(3*n + 1)]

for k in range(n):

compteur[t[k]] += 1 indice = 0

for i in range(3*n + 1):

for j in range(compteur[i]):

t[indice] = i indice += 1

t = [rd.randint(0, 3*N) for k in range(N)]

print(t) tri(t) print(t)

1

Références

Documents relatifs

Or pour que l’élément de rang i et l’élément de rang j soient comparés il faut que le pivot ne soit jamais choisi entre l’élément de rang i et de rang j avant le choix de i ou

DELOYER Maxime 1000. DELOYER

chaîne de caractères = suite d’octets Lecture fichier texte : lignes stockées dans une chaîne de caractères.. Lecture fichier binaire : données stockées dans une chaîne

Lecture fichier binaire : données stockées dans une chaîne de caractères... 3.2 str : chaîne d’octets (pas

• Le traitement de liste est souvent réalisé à l’aide de fonctions récursives (il n’existe pas d’équivalent fonctionnel direct des boucles). • Calcul de la longueur

[r]

Chaque comparaison générant deux possibilités, k comparaisons permettront de génerer au plus 2 k permutations distinctes.. • Le tri shell avec la suite

Le retrait d’un des prisonniers revient à rendre une case vide et les règles relatives à la position des grilles nous ramènent à un jeu de type taquin (mais de trois sur trois)..