Tri par sélection Tri par insertion Tri fusion Tri rapide Principe : Comme une photo de classe, la liste est lue
afin de repérer le plus petit élément qui est placé en début de liste. Ici tri en place et stable (>)
Principe du jeu de cartes : Pour une sous-liste déjà triée, on compare l’élément à trier (clé) aux valeurs précédentes. Ici tri en place et stable (>)
Principe du diviser pour régner : on divise la liste par deux jusqu’à obtenir une liste de longueur unitaire (ou nulle) facile à classer. On utilise une autre fonction pour trier des sous listes triées. Ici tri pas en place et non stable.
Principe « diviser pour régner » : On prend un pivot 𝑝 (1e élément) et on crée une liste dont les éléments sont inférieurs à 𝑝 et une autre liste dont les éléments sont supérieurs (ou égale) à 𝑝. Par récursivité, on aboutit au cas trivial. Ici tri qui n’est pas en place et pas stable def selection(L):
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
def insertion(L):
for i in range(1,len(L)):
j=i-1 cle=L[i]
while cle<L[j] and j>=0:
j=j-1
L[j+2:i+1]=L[j+1:i]
L[j+1]=cle return L
def fusion1(L1,L2):
n1,n2=len(L1)-1,len(L2)-1 L=[]
i1,i2=0,0
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 i2>n2 :
return L+L1[i1:]
else :
return L+L2[i2:]
def fusion2(L):
if len(L)==0 : return L else :
L1=fusion2(L[:len(L)//2]) L2=fusion2(L[len(L)//2:]) return fusion1(L1,L2)
def rapide(L):
if len(L)==0 or len(L)==1:
return L else : L1=[]
L2=[]
for i in range(1,len(L)):
if L[i]<L[0]:
L1.append(L[i]) else :
L2.append(L[i])
return rapide(L1)+[L[0]]+rapide(L2)
Terminaison :
Evidente car il s’agit de deux boucles for
Terminaison :
𝑗 est le variant de boucle amenant à la terminaison de la boucle while
Terminaison :
- La 1e fonction présente un variant de boucle qui augmente forcément jusqu’à atteindre l’index max d’une des deux listes - La 2e fonction converge également vers la
situation triviale
Terminaison :
La boucle for se termine forcément et les appels récursifs convergent vers les deux situations triviales
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]
- Terminaison : La dernière itération conduit à la comparaison des deux derniers éléments (inévitablement les plus grands de 𝐿)
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 la prochaine recherche conduit nécessairement à rajouter 𝐿[𝑖] ≥ 𝐿[𝑖 − 1]
- Terminaison : Le dernier élément est comparé aux éléments déjà triés
Correction :
Le cas trivial 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 une liste 𝐿 = [𝐿1] + [𝐿2] . Tous les éléments de 𝐿1 sont plus petits que tous les éléments de 𝐿2
𝑓𝑢𝑠𝑖𝑜𝑛2(𝐿) => 𝑓𝑢𝑠𝑖𝑜𝑛2(𝐿1, 𝐿2) Ce qui conduit effectivement à une liste trié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 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) Complexité :
Dans tous les cas, le nombre de comparaison est : 𝑇(𝑛) = (𝑛 − 1) + (𝑛 − 2) + ⋯ 1 =𝑛(𝑛 − 1)
2 𝑇(𝑛) = 𝑂(𝑛2)
Complexité (unité de cout est la comparaison) : - Dans le pire des cas (liste inversée) :
𝑇(𝑛) =𝑛(𝑛 − 1) 2 = 𝑂(𝑛2) - Dans le meilleur des cas (liste déjà triée) :
𝑇(𝑛) = 𝑂(𝑛)
C’est cette linéarité qui fait l’efficacité de cette méthode pour une liste presque triée.
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.
Complexité :
- Pire cas (liste triée et pivot au départ) : 𝐿1 vide, donc 𝑛 − 1 + 𝑛 − 2+. .1 appels et 𝑇(𝑛) = 𝑂(𝑛2)
- Meilleur cas : 𝐿1 et 𝐿2 sont (quasi) de même taille : donc log2(𝑛) appels amenant à chaque étape 𝑛 comparaisons (en ordre de grandeur):
𝑇(𝑛) ≈ 𝑛𝑙𝑜𝑔2(𝑛)