• Aucun résultat trouvé

Un algorithme de tri d’une liste est dit stable s’il conserve la position relative dans la liste des quantités qui sont égales pour la relation d’ordre

N/A
N/A
Protected

Academic year: 2022

Partager "Un algorithme de tri d’une liste est dit stable s’il conserve la position relative dans la liste des quantités qui sont égales pour la relation d’ordre"

Copied!
4
0
0

Texte intégral

(1)

Tri I- Introduction

On parle de tri lorsque l’on veut classer des structures de données avec une relation d’ordre.

Le tri de séquences de données est courant :

- Trier par valeurs croissantes, décroissantes (pour ensuite faire un calcul de médiane)

- Trier par ordre lexicographique (exemple du dictionnaire…ce qui facilite la recherche)

- Trier des grandeurs qui ont une relation d’ordre entre elles (par exemple dans les algorithmes de compression de données, tri des tuples par clé primaire dans une base de données afin de gagner du temps lors d’une phase de recherche…)

Il existe la méthode sort() permettant de trier une liste.

liste= [0,1,2,3,7,8,9,4,5,6]

liste.sort()

print(liste)#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

liste=["alban","thomas","andré","willy"]

liste.sort()

print(liste)#['alban', 'andré', 'thomas', 'willy']

Cependant, nous allons voir qu’il est instructif de connaître différentes méthodes de tri afin de pouvoir effectuer des opérations de tri avec une relation d’ordre quelconque.

L’algorithme est dit en place s’il modifie directement la structure de données sans en créer une nouvelle (typiquement une liste sous python) : cette technique limite la complexité spatiale (coût constant).

Un algorithme de tri d’une liste est dit stable s’il conserve la position relative dans la liste des quantités qui sont égales pour la relation d’ordre.

II- Tri par sélection

a) Principe

Comme pour une photo de classe on va chercher le minimum de la partie de la liste non triée.

Exemple :

5 7 3 1 9

1 7 3 5 9

1 3 7 5 9

1 3 5 7 9

b) Algorithme itératif

def tri_selection(L):

"""algorithme en place"""

for i in range(len(L)-1):

index_min = i

for j in range(i+1, len(L)):

if L[index_min] > L[j]:

index_min = j

L[i],L[index_min] = L[index_min],L[i]

return L c) Complexité

La complexité temporelle (dans le meilleur ou le pire des cas) mesurée par le nombre de comparaisons est :

𝑇(𝑛) = (𝑛 − 1) + (𝑛 − 2) + ⋯ + 2 + 1 =𝑛(𝑛 − 1) 2 ≈ 𝑂(𝑛2) d) Terminaison

La terminaison est évidente car on utilise deux boucles for (si on a bien vérifié l’absence de dépassement d’indice)

e) Correction

La propriété 𝐿[: 𝑖] est une liste triée est l’invariant de boucles : - Initialisation : évident en entrée de boucle lorsque 𝑖 = 0

- Continuité : Si 𝐿[: 𝑖] est bien triée alors la prochaine recherche conduit nécessairement à rajouter 𝐿[𝑖] ≥ 𝐿[𝑖 − 1]

- La dernière itération conduit à la comparaison des deux derniers éléments (inévitablement les plus grands de 𝐿)

Commenté [AM1]: Dans toute la suite, nous allons écrire des fonctions qui vont chercher à trier des listes.

Lors du passage d’une liste en paramètres ou arguments d’une fonction, ce passage se fait par référence, : il n’y a pas de variable locale associée et la liste est modifiée en place (les listes sont muables, ce qui n’est pas le cas avec une entier par exemple).

Cependant, nous utiliserons des return afin d’obtenir directement la liste modifiée

Commenté [AM2]:

Commenté [AM3]: https://www.youtube.com/watch?v

=jKEoj-sKvVQ

https://www.youtube.com/watch?v=ROalU379l3U Rappels :

1+2+3+4+5+6+7+8+9+10 = 11 *5 =>n(n+1)/2 1+2+3+4+5+6+7+8+9 = 11*5-10 =>n(n+1)/2-n=n(n-1)/2

Commenté [AM4]: Cette inégalité stricte assure un algorithme de tri stable

(2)

III- Tri par insertion a) Principe

C’est le principe du jeu de carte : le joueur classe chaque carte à fur et à mesure en les comparant à celles déjà triées. Exemple :

5 7 3 1 9

5 7 3 1 9

3 5 7 1 9

1 3 5 7 9

Ici le placement de 3 de fait en 2 déplacements unitaires, le déplacement de 1 en 3.

b) Algorithme itératif

def tri_insertion(L):

for i in range(1,len(L)):

cle=L[i]

j=i-1

while j>=0 and cle<L[j]:

j=j-1

L[j+2:i+1]=L[j+1:i]

L[j+1]=cle return L

c) Complexité

Si on compte le nombre de comparaisons, on peut distinguer 2 cas - le pire des cas (celui d’une liste triée en ordre décroissant) :

𝑇(𝑛) = 1 + 2 + 3 + ⋯ + 𝑛 − 1 =𝑛

2(𝑛 + 1) − 𝑛 =𝑛

2(𝑛 − 1) = 𝑂(𝑛2) - le meilleur cas (celui d’une liste déjà trié) :

𝑇(𝑛) = 𝑛 − 1 = 𝑂(𝑛) d) Terminaison

La terminaison est évidente pour la boucle for. Pour la boucle while, 𝑗 est le variant de boucle amenant à un arrêt inévitable (dans le pire cas).

e) Correction

La propriété 𝐿[: 𝑖] est une liste triée est l’invariant de boucles : - Initialisation : évident en entrée de boucle lorsque 𝑖 = 1 - Continuité : Si 𝐿[: 𝑖] est bien triée alors 2 cas :

→ 𝐿[𝑖] ≥ 𝐿[𝑖 − 1] la clé reste à la même place : 𝐿[: 𝑖 + 1] est triée

→ 𝐿[𝑖] < 𝐿[𝑖 − 1] et la clé est insérée à la bonne place : : 𝐿[: 𝑖 + 1]

est triée

- Terminaison : Le dernier élément est comparé aux éléments déjà triés

IV- Tri par fusion a) Principe

C’est le principe de diviser pour régner : une liste initiale de longueur 𝑛 = 2𝑝 (avec 𝑝 entier) est alors divisée 𝑘 = 𝑙𝑜𝑔2(𝑛) fois jusqu’à obtenir des listes de longueur unité alors très faciles à comparer entre elles. Cet algorithme repose ensuite sur une fonction 𝑓𝑢𝑠𝑖𝑜𝑛1() qui fusionne deux listes triées.

5 7 3 1 9

3 1 9

5 7

1 9

5 7 3 1 9

5 7 1 9

1 3 9

5 7

1

𝑑𝑖𝑣𝑖𝑠𝑒𝑟

𝑓𝑢𝑠𝑖𝑜𝑛𝑛𝑒𝑟

Principe de l’algorithme de fusion lors de la dernière étape : on part d’une liste

vide et on parcourt les deux

listes en plaçant l’élément le plus

petit

1 3

1 3 5

1 3 5 7

1 3 5 7 9

3

3

Commenté [AM5]: https://www.youtube.com/watch?v

=VHsxXqlzhd4

https://www.youtube.com/watch?v=ROalU379l3U

Commenté [AM6]: https://www.youtube.com/watch?v

=OEmlVnH3aUg&t=662s

(3)

b) Algorithme def fusion1(L1,L2):

i1,i2=0,0

n1,n2=len(L1)-1,len(L2)-1 L=[]

while i1<=n1 and i2<=n2:

if L1[i1]<L2[i2]:

L.append(L1[i1]) i1=i1+1

else :

L.append(L2[i2]) i2=i2+1

if i1 == n1+1 : return L+L2[i2:]

else :

return L+L1[i1:]

def fusion2(L):

if len(L)==1:

return L else :

L1=fusion2(L[:len(L)//2]) L2=fusion2(L[len(L)//2:]) return fusion1(L1,L2)

c) Complexité

On peut remarquer que l’on a 𝑙𝑜𝑔2(𝑛) niveaux et sur chaque niveau, on va comparer typiquement 𝑛 valeurs : 𝑇(𝑛) = 𝑛𝑙𝑜𝑔2(𝑛) la complexité est quasi- linéaire.

d) Terminaison

La boucle while de la fonction 𝑓𝑢𝑠𝑖𝑜𝑛1 se termine car elle présente un variant de boucle. La fonction 𝑓𝑢𝑠𝑖𝑜𝑛2 se termine aussi car les différents appels aboutissent à la condition triviale d’une liste à un élément.

e) Correction

Le cas trivial conduit d’une liste à un élément renvoie cet élément : ce qui est juste.

Supposons cet algorithme vrai pour toute liste de longueur 𝑛. Si on considère deux listes 𝐿1 et 𝐿2 de longueur 𝑛 et donc triables et une liste 𝐿 = [𝐿1] + [𝐿2] . Tous les éléments de 𝐿1 sont plus petits que tous les éléments de 𝐿2

𝑓𝑢𝑠𝑖𝑜𝑛2(𝐿) => 𝑓𝑢𝑠𝑖𝑜𝑛1(𝐿1, 𝐿2) Ce qui conduit effectivement à une liste triée.

V- Tri rapide a) Principe

C’est un tri récursif basé également sur la méthode « diviser pour régner ». Le principe est le suivant :

- On choisit un pivot 𝑝 dans le tableau (par exemple le 1e élément) - On enlève le pivot et on segmente le tableau en deux sous tableaux. Un

tableau contenant les éléments strictement plus petits que 𝑝 et les autres éléments supérieurs à 𝑝 dans un second tableau

- On recommence récursivement sur les tableaux obtenus jusqu’au cas trivial et on recombine

b) Algorithme def quicksort(L):

if L == []:

return []

else:

pivot = L[0]

L1 = []

L2 = []

for x in L[1:]:

if x<pivot:

L1.append(x) else:

L2.append(x)

return quicksort(L1)+[pivot]+quicksort(L2)

5 7 3 1 9

Pivot « 5 »

3 1 7 9

Pivots « 3 » et « 7 »

5

3 7

1 9

Cas trivial : on dépile

3 7

1 3 5 7 9

Réassemblage

1 9

Commenté [AM7]: L’algorithme proposé n’est pas en place car la liste triée est une nouvelle liste

Commenté [AM8]: Cet algorithme est stable car si 𝐿1[𝑖1] < 𝐿2[𝑖2] et que 𝐿2[𝑖2] = 𝐿2[𝑖2+ 1] alors 𝐿2[𝑖2] puis 𝐿2[𝑖2+ 1] seront placés successivement

Commenté [AM9]: https://www.youtube.com/watch?v

=ROalU379l3U

(4)

c) Complexité

Le « coût » temporel de l’algorithme de tri est principalement donné par des opérations de comparaisons sur les éléments à trier.

- Dans le pire des cas, un des deux segments est vide à chaque appel de la fonction de tri. Cela arrive lorsque le tableau est déjà trié.

𝐿 = [0,1,2,3,4,5,6,7] → 𝑛 = 8 → 7𝑐𝑜𝑚𝑝𝑎𝑟𝑎𝑖𝑠𝑜𝑛𝑠 𝑛 = 7 → 6𝑐𝑜𝑚𝑝𝑎𝑟𝑎𝑖𝑠𝑜𝑛𝑠 𝑛 = 6 → 5 𝑐𝑜𝑚𝑝𝑎𝑟𝑎𝑖𝑠𝑜𝑛𝑠

:

𝑛 = 2 → 1 𝑐𝑜𝑚𝑝𝑎𝑟𝑎𝑖𝑠𝑜𝑛 Dans ce cas, on a 1 + 2 + 3 + ⋯ + 𝑛 − 1 =𝑛(𝑛−1)

2 comparaisons et donc : 𝑇(𝑛) = 𝑂(𝑛2)

Donc 𝑇(𝑛) = 𝑂(𝑛2)

▪ Dans le meilleur des cas, à chaque appel, la division donne deux sous listes de même taille :

𝑇(𝑛) = (𝑛 − 1) + 2𝑇 (𝑛 − 1 2 )

De manière analogue au tri fusion, on a approximativement log2(𝑛) appels et 𝑛 comparaisons à chaque étape : 𝑇(𝑛) ≈ 𝑂(𝑛𝑙𝑜𝑔2(𝑛))

Enfin, on pourra noter l’importance du choix du pivot, par exemple dans une liste déjà triée, un pivot choisi au centre de la liste ne conduit pas au pire cas.

d) Terminaison

Cet algorithme récursif se termine car la variable de contrôle est la longueur de la liste et elle diminue strictement à chaque appel (car le pivot est enlevé à chaque appel) aboutissant au cas de base d’une liste vide

e) Correction Par récurrence :

- Si 𝑙𝑒𝑛(𝐿) = 𝑛 = 0,1 alors la liste est bien triée

- Supposons cet algorithme vrai pour toute liste de longueur 𝑛.

- Si on considère deux listes 𝐿1 et 𝐿2 de longueur 𝑛 et donc triables et une une liste 𝐿 = [𝐿1] + [𝑝] + [𝐿2] où 𝑝 est une liste à un élément pour lequel tous les éléments de 𝐿1 sont plus petit et tous les éléments de 𝐿2 sont plus grands. Alors l’algorithme de tri rapide de pivot 𝑝 conduit à :

𝑡𝑟𝑖(𝐿) = 𝑡𝑟𝑖(𝐿1) + [𝑝] + 𝑡𝑟𝑖(𝐿2) Ce qui conduit effectivement à une liste triée.

VI- Bilan

Tri par sélection Tri par

insertion Tri par fusion Tri rapide Avantage : il n’y

a que 𝑛 − 1 permutations

Avantage : Très efficace lorsque le tableau est déjà presque trié

Avantage : toujours la même complexité

Avantage : expérimentalement meilleur que le tri fusion

coût quadratique dans tous les cas

Meilleur cas 𝑂(𝑛)

Pire cas 𝑂(𝑛2)

𝑇(𝑛)

= 𝑂(𝑛𝑙𝑜𝑔2(𝑛)) Meilleur cas ; 𝑇(𝑛) = 𝑂(𝑛𝑙𝑜𝑔2(𝑛)) Pire cas : 𝑂(𝑛2)

Commenté [AM10]: Certains algorithmes de tri rapide prennent pour « pivot » le dernier élément, la valeur moyenne du premier et du dernier, ou un positionnement aléatoire dans le tableau. Pour se placer dans le meilleur des cas pour chaque segment de tableau, il faut prendre pour pivot la valeur médiane du tableau de valeurs. Le problème est que cette recherche de pivot idéal a aussi un « coût ».

Commenté [AM11]: On pourrait penser que le tri par fusion est la meilleure méthode de tri. Cependant, la situation du pire cas arrive rarement et c’est l’algorithme du tri rapide qui actuellement utilisé pour des grandes listes. Le tri par insertion est quant à lui très utilisé pour des listes de petites tailles (presque déjà triées). C’est le cas de la méthode sort sur python qui utilise les deux méthodes en fonction de la taille de la liste.

Références

Documents relatifs

Domaine : Droit international Documents : décisions de justice Dates de couverture : À partir de 1812 Oxford Legal Research Library Type : base de données bibliographique Editeur

Capillaria corvorum (Rudolphi 1819) Coloeus monedula Corvus corone Capillaria erinacei (Rudolphi 1819) Erinaceus europaeus Capillaria exigua (F. Dujardin 1845) Erinaceus

[r]

Les Annabac Hatier proposent des sujets de bac blanc pour vous entraîner, un espace d’entraide dans toutes les matières, une sélection des meilleurs sites Web, matière par

Complexité dans le meilleurs cas : Modèle de complexité peu utile Complexité en moyenne : à partir d’une répartition probabiliste des tailles de données, tente d’évaluer le

La liste finale est établie via la flèche pour fonctionnalités aditionelles (1) dans l’option de menu Gestion du cabinet - Bibliothèque, puis l’option Liste de patients (2).

• Idée : trouver le plus petit et le placer en premier puis trouver le plus petit parmi les éléments non placés et le placer en.

complexité temporel en fonction d'un paramètre n passé à l'algorithme on se concentre sur des grands n en utilisant la représentation au de haine et on s'intéresse au pire des