• Aucun résultat trouvé

4 Tris Dans tout le TP, on suppose que l'on dispose d'une liste

N/A
N/A
Protected

Academic year: 2022

Partager "4 Tris Dans tout le TP, on suppose que l'on dispose d'une liste"

Copied!
6
0
0

Texte intégral

(1)

BCPST2

9 5

0 4 Tris

Dans tout le TP, on suppose que l'on dispose d'une listeLconstituée de nombres (entiers ou ottants) dont on souhaite ordonner ses éléments par ordre croissant. On notenla longueur de cette liste.

Nous allons étudier diérents algorithmes de tris.

Solution: On remarquera que les fonctions de tris n'ont pas de return.

En eet, ces fonctions sont à eets de bords, c'est-à-dire qu'elle modie la liste L passée en argument et que cette modication est eective en dehors de la fonction.

Ce comportement qui peut être destabilisant au début est un comportement normal, qui évite les recopie inutile de liste et permet au langage d'être ecace.

1 re Partie : LE TRI PAR SELECTION

Principe : Le tri par sélection est l'un des tris les plus instinctifs.

Il consiste à trouver la position du plus grand élément ; le plus grand élément est alors échangé avec le dernier élément de la liste. Puis, on recommence ces opérations sur les(n−1)premiers éléments de la liste, et ainsi de suite ... jusqu'à ce qu'il n'y ait plus qu'un élément à trier ; celui-ci est alors le plus petit élément de la liste.

Exemple :

©

Par exemple, si L=[6,2,8,5,4,1], alors on obtient successivement :

(les cases en gris correspondent aux éléments bien positionnés)

6 2 8 5 4 1 on échange 1 et 8

6 2 1 5 4 8 on échange 4 et 6

4 2 1 5 6 8 le 5 est à sa place

4 2 1 5 6 8 on échange 4 et 1

1 2 4 5 6 8 le 2 est à sa place 1 2 4 5 6 8 la liste est triée

1) Écrire une fonction rg_max(L) qui prend en argument une liste L et qui renvoie la position dans la liste L du plus grand élément.

Solution:

def rg_max ( L ) : M = L [ 0 ] r = 0

f o r i in range ( len ( L ) ) : i f M< L [ i ] :

M = L [ i ] return r r =i

2) En utilisant la fonction précédente, écrire une fonction tri_selection(L) qui trie la liste L selon la méthode de tri par sélection.

Solution:

def tri_selection ( L ) : n = len ( L )

f o r i in range ( n − 1 ,0 , − 1) : #i n t e r v a l l e [ 1 , n [ à l ' envers r = rg_max ( L [ 0 : i +1])

L [ r ] , L [ i ] = L [ i ] , L [ r ]

(2)

2 e Partie : LE TRI PAR INSERTION

Principe : Le tri par insertion est un autre algorithme naïf , que la plupart des personnes utilisent naturellement pour trier des cartes (prendre les cartes mélangées une à une sur la table, et former une main en insérant chaque carte à sa place).

Au début, on considère que la liste constituée du seul premier élément est trié ; puis on trie les deux premiers éléments ; ensuite on met le troisième élément à sa place parmi les deux premiers, et ainsi de suite ...

De manière générale, au moment où l'on considère lek-ième élément, les éléments qui le précèdent sont tous déjà triés. Il faut donc trouver le rang où cet élément doit être inséré en le comparant aux autres, puis décaler les éléments an de pouvoir eectuer l'insertion.

Exemple :

©

Par exemple, si L=[6,2,8,5,4,1], alors on obtient successivement :

(les cases en gris correspondent aux éléments déjà traités)

6 2 8 5 4 1

2 6 8 5 4 1 on insère le 2 à sa place 2 6 8 5 4 1 on insère le 8 à sa place 2 5 6 8 4 1 on insère le 5 à sa place 2 4 5 6 8 1 on insère le 4 à sa place

1 2 4 5 6 8 on insère le 1 à sa place, et la liste est triée

Programmation :

Écrire une fonction tri_insertion(L) qui trie la liste L selon la méthode de tri par insertion.

Solution:

def insere ( L , i , j ) :

# i n s e r e l ' é lement de rang i à l a p o s i t i o n j , i c i on suppose j<i a = L . pop ( i ) #e n l è ve l ' é l ément d ' i n d i c e i et l e s t r o c k e dans a L . insert ( j , a )

def tri_insertion ( L ) : n = len ( L )

f o r i in range ( n ) :

j=0 while L [ i ] > L [ j ] and j<i : j +=1

insere ( L , i , j )

(3)

3 e Partie : LE TRI BULLE

Principe : Le tri bulle consiste à regarder les diérentes valeurs adjacentes d'une liste, et à les permuter si le premier des deux éléments est supérieur au second.

Plus précisément, les deux premiers éléments de la liste sont comparés : si le premier est supérieur au second, une permutation est eectuée.

Ensuite sont comparés et éventuellement permutés les deuxième et troisième éléments, ..., jusqu'aux élémentsn−1etn. Une fois cette étape achevée, le dernier élément du vecteur est le plus grand.

On recommence l'opération sur lesn−1éléments restants, et ainsi de suite. On s'arrête lorsqu'il n'y a plus qu'un seul élément.

Cet algorithme porte le nom de tri bulle, car le plus grand élément remonte petit à petit vers le haut, comme une bulle ! Exemple :

©

si L=[6,2,8,5,4,1], alors on obtient successivement :

(les cases en gris correspondent aux éléments qui sont comparés et éventuellement échangés à l'étape suivante, et les cases en bleu aux éléments bien positionnés)

6 2 8 5 4 1 on échange 6 et 2

2 6 8 5 4 1 on ne fait rien

2 6 8 5 4 1 on échange 8 et 5

2 6 5 8 4 1 on échange 8 et 4

2 6 5 4 8 1 on échange 8 et 1

2 6 5 4 1 8 après un premier parcours, le 8 est remonté ... ... ...

2 5 4 1 6 8 après un deuxième parcours, le 6 est remonté ... ... ...

2 4 1 5 6 8 après un troisième parcours, le 5 est remonté ... ... ...

2 1 4 5 6 8 après un quatrième parcours, le 4 est remonté ... ... ...

1 2 4 5 6 8 après un cinquième parcours, le 2 est remonté Programmation :

Écrire une fonction tri_bulle(L) qui trie la liste L selon la méthode de tri bulle.

Solution:

def tri_bulle ( L ) : n = len ( L )

f o r i in range ( n −1) : f o r j in range ( n − i − 1) :

i f L [ j]>L [ j +1]:

L [ j ] , L [ j+1] = L [ j +1] , L [ j ]

(4)

4 e Partie : LE TRI RAPIDE

Principe : Le tri rapide (ou quicksort en anglais) est un algorithme très ecace, de type dichotomique.

La méthode consiste à choisir un élément au hasard dans la liste, appelé pivot. Ensuite on permute les éléments de telle sorte que tous ceux qui sont inférieurs ou égaux au pivot soient à sa gauche et que tous ceux qui sont strictement supérieurs au pivot soient à sa droite. Cette opération s'appelle le partitionnement. Le pivot est alors à sa place dénitive.

Puis on recommence sur chacune des deux sous-listes, et ainsi de suite ... jusqu'à obtenir des sous-listes vides ou réduites à un élément.

Exemple :

©

Par exemple, si L=[8,2,6,5,4,1,9,3,0,7], alors on obtient successivement :

(les cases en bleu correspondent aux pivots choisis pour passer à la ligne suivante et les cases en gris aux éléments bien positionnés)

8 2 6 5 4 1 9 3 0 7 on choisit 6 comme pivot

le 6 est à sa place dénitive

2 5 4 1 3 0 6 8 9 7 on recommence avec les deux sous-listes obtenues on choisit 4 et 9 comme pivots

2 1 3 0 4 5 6 8 7 9 et ainsi de suite ...

1 0 2 3 4 5 6 7 8 9

0 1 2 3 4 5 6 7 8 9

0 1 2 3 4 5 6 7 8 9 la liste est triée

Programmation :

Écrire une fonction tri_rapide(L) qui trie la liste L selon la méthode de tri rapide.

Solution:

def partitionne ( L , rg_pivot ) :

# Au dé but on met l e pivot au rang 0 , on l e metttra à sa p l a c e à l a f i n .

# Les p e t i t s é l é ments sont à gauche , l e u r i n d i c e e s t donné par i m i n i

# Les grands à d r o i t e , l e u r i n d i c e e s t donné par imaxi

# Quand imin=imaxi , tous l e s é l é ments auront é t é mis en p l a c e

#( s a u f l e pivot ) n = len ( L )

pivot = L [ rg_pivot ]

L [ 0 ] , L [ rg_pivot ]= L [ rg_pivot ] , L [ 0 ] imini = 1

imaxi = n−1

while imini <= imaxi : i f L [ imini ] < pivot :

imini += 1

# On l a i s s e l e s p e t i t s é l é ments à l e u r s p l a c e s et on l e s compte . e l s e :

L [ imini ] , L [ imaxi]= L [ imaxi ] , L [ imini ] imaxi −= 1

# Les grands é l é ments sont mis à d r o i t e

#et on garde en mé moire l e rang

# pour c o n t i n u e r à r e m p l i r plus tard .

L [ 0 ] , L [ imini −1]= L [ imini −1] , L [ 0 ] # on remet l e pivot à sa p o s i t i o n return imini − 1

def tri_rapide ( L ) : n = len ( L )

i f len ( L ) > 1 :

rg = random . randint (0 , n−1) r = partitionne ( L , rg )

M = tri_rapide ( L [ : r ] ) +[L [ r ]]+ tri_rapide ( L [ r + 1 : ] ) e l s e :

M = [ x f o r x in L ]

return M

(5)

5 e Partie : Comparaison des diérentes méthodes

La fonction time() du module time renvoie le temps en secondes écoulé depuis le 1er janvier 1970 à 00 : 00 : 00.

Ainsi, la fonction suivante permet de connaître la vitesse d'exécution de la fonction fct_tri pour trier la liste L.

def duree ( fct_tri , L ) : debut=time ( ) fct_tri ( L ) fin=time ( )

return ( fin−debut )

1) Écrire une fonction liste(n) qui crée une liste de longueur n, constituée d'entiers choisis aléatoirement dansJ0 ; 10nK.

Solution:

def liste ( n ) :

return [ random . randint (0 , 10 ∗ n ) f o r i in range ( n ) ]

2) Écrire une fonction tps_moyen(fct_tri,n) qui crée 5 listes de longueur n à l'aide de la fonction précédente, calcule le temps nécessaire pour trier ces listes avec la fonction fct_tri et qui renvoie le temps moyen obtenu.

Solution:

def tps_moyen ( fct_tri , n ) : tps = 0

f o r i in range ( 5 ) : L = liste ( n )

tps += duree ( fct_tri , L ) tps = tps /5

return tps

3) Appliquer la fonction précédente aux quatre fonctions de tris du TP, et remplir le tableau suivant des diérents temps moyens obtenus :

listes de longueur 50 100 500 1000 2000 5000

tri par sélection tri par insertion tri bulle tri rapide

4) Pour une liste de longueurn, on noteT(n)le temps moyen obtenu précédemment pour trier la liste.

Tracer, pour chaque fonction de tris,ln(T(n))en fonction deln(n). Que peut-on en déduire ?

Solution:

methode = [ tri_bulle , tri_selection , tri_insertion , tri_rapide , tri_rapide_bis ]

def comparaison ( ) :

val =[10 , 100 , 500 , 1000 ,5000]

f o r f in methode :

T = [ tps_moyen ( f , n ) f o r n in val ]

graph = plt . plot ( [ log ( x ) f o r x in val ] , [ log ( t ) f o r t in T ] ) p r i n t ( f . func_name , x , ' é l é ments ' , T )

plt . setp ( graph , label= f . func_name ) plt . legend ( loc= ' upper l e f t ' )

plt . show ( )

(6)

3 4 5 6 7 8 9 10 10

8 6 4 2 0

2 tri_bulle

tri_selection tri_insertion tri_rapide

On peut montrer que les trois premiers tris sont en O(n

2

) , c'est-à-dire que le temps T

n

d'exécution pour une liste de longueur n est proportionnel à n

2

: T

n

= αn

2

ainsi

ln(T

n

) = 2 ln(n) + ln(α) Ceci explique la droite de pente 2 .

En ce qui concerne le tri rapide, celui-ci est en O(n ln(n)) : T

n

= αn ln(n) ainsi : ln(T

n

) = ln(n) + ln(ln(n)) + ln(α)

Ce qui explique la droite de pente 1 , le terme en ln(ln(n)) n'étant pas visible sur le graphique.

On remarque en particulier que le tri bulle est le plus mauvais des tris.

Références

Documents relatifs

Si f, fonction réelle de la variable réelle, est dérivable et bornée et si sa dérivée admet une limite finie en +∞ alors cette limite

Dans un premier temps, nous allons voir que nous pouvons quelque peu simplifier la situation proposée (le travail ci-dessous n’est en rien obligatoire mais il nous donne l’occasion de

Remarquons que l’on a en fait montré que la restriction de u à toute droite vectorielle est une homothétie... Le résultat

Dans le programme, pour cette question, j’ai rajouté en « Feuil2 » une action permettant de définir toutes les listes pour une profondeur (longueur) donnée, et de tester, pour

(d) Le prix actuel ´ etant 1, 42, quelle valeur donner ` a p pour que la recette augmente de 0,

Fonctionnement d'une pile La structure de pile permet de retrouver les éléments dans l'ordre inverse de 1 Une structure de file permet de retrouver les éléments dans l'ordre où

b) Sur un tas binaire, écrivez l'algorithme d'un traitement récursif propMax(i) permettant d'assurer qu'à partir de l'indice i chaque élément du tableau est

• Les piles sont utilisées pour implanter les appels de procédures (cf. pile système). • En particulier, les procédures récursives gèrent une pile