Vous êtes sur la page 1sur 48

Chapitre8

Les algorithmes de
TRI
ASD et programmation procédurale en langage C
LNIG1

Salma KSIBI
Dr. Ing. en Informatique
Introduction
Tri par Sélection
Tri par Insertion
Tri à Bulles
Tri Rapide

mai 2012 A. Lotfi


0 Introduction

0.1 Définition

« trier » signifie « répartir en plusieurs classes selon certains


critères ».
De manière plus restrictive, le terme de « tri » en
algorithmique est très souvent attaché au processus de
classement d'un ensemble d'éléments dans un ordre donné.
Par exemple, trier N entiers dans l'ordre croissant, ou N noms
dans l'ordre alphabétique. Tout ensemble muni d'un ordre
total peut fournir une suite d'éléments à trier.
Le tri est sans doute le problème fondamental de
l’algorithmique
1. plus de 25% des CPU cycles sont dans les tris
2. le tri est fondamental à beaucoup d’autres problèmes, par
exemple recherche binaire.
0 Introduction

0.2 Utilité

Ainsi donc, après le tri, beaucoup de problèmes


deviennent faciles à résoudre. Par exemple :
1. Unicité d’éléments: après le tri tester les éléments
adjacents
2. Une fois le tri fait, on peut déterminer le kème plus
grand élément en O(1)
0 Introduction

0.3 Présentation du problème

Le tri consiste à réarranger une permutation of n objets


de telle manière que :

Tri Croissant
Tri Déroissant

Comment trier ? Il existe plusieurs manières de faire le


tri
1 Tri par Sélection

1.1 Principe

Répéter
1. chercher le plus grand (le plus petit) élément => Sélection
2. le mettre à la fin (au début)

1 i n
t
Les i-1 petits éléments Le plus petit élément
triés du reste
1 Tri par Sélection
1 Tri par Sélection

1.2 Exemple

On veut trier les éléments:


42, 20, 17, 13, 28, 14, 23 et 15

i=1 i=2 i=3 i=4 i=5 i=6 i=7

42 13 13 13 13 13 13 13

20 20 14 14 14 14 14 14

17 17 17 15 15 15 15 15

13 42 42 42 17 17 17 17

28 28 28 28 28 20 20 20

14 14 20 20 20 28 23 23

23 23 23 23 23 23 28 28

15 15 15 17 42 42 42 42
1 Tri par Sélection

1.3 Algorithme
Procédure TriSelection(t : Tableau[] d’entiers, nbElements :
entier)
Variables
i, k, indMin : entiers;
temp : entier;
Début
Pour i <- 0 à nbElements-1 pas 1 faire
/* recherche du numéro du minimum */
indMin <- i;
Pour k <- i+1 à nbElements pas 1 faire
si (t[k] < t[indMin]) alors
indMin <- k;
Fin Si
Fin Pour
/* échange des valeurs entre la case courante et le minimum */
temp <- t[i];
t[i] <- t[indMin];
t[indMin] <- temp;
Fin Pour
Fin
1 Tri par Sélection

1.4 Implémentation : Exercice

Ecrire un programme C qui lit un tableau d’entiers


et le trie en utilisant la méthode du tri par sélection.

On prend pour l’exemple le tableau suivant :


1 Tri par Sélection

1.4 Implémentation : Correction


#include <stdio.h>
void tri_selection(int tab[], int n)
{ int i, j, min_indis; int temp;
for (i = 0; i < n; i++) {
min_indis = i;
for (j = i+1; j < n; j++)
if (tab[j] < tab[min_indis])
{ min_indis = j;
temp=tab[i];
tab[i]=tab[min_indis];
tab[min_indis]=temp;}}
void affiche(int tab[], int size) {
int i; for (i=0; i < size; i++)
printf("%d \n", tab[i]); }
int main() {
int tab[6]= {9, 7, 3, 5, 4,2};
int n = 6;
printf("tableau avant le tri : \n");
affiche(tab,n);
tri_selection(tab,n);
printf("\n tableau après le tri par sélection : \n"); affiche(tab, n); return 0;}
1 Tri par Sélection

1.5 Complexité

Le pire des cas, le plus mauvais cas et le cas moyen sont pareils
(pourquoi?)
Pour trouver le plus petit éléments, (n-1) itérations sont
nécessaires, pour le 2ème plus petit élément, (n-2) itérations sont
effectuées, .… Pour trouver le dernier plus petit élément, 0
itérations sont effectuées. Le nombre d’itérations que l’algorithme
effectue est donc:
𝑛 𝑛−1 𝑛 𝑛
𝑖= = − = 𝑂(𝑛 )
2 2 2
Si par contre, nous prenons comme mesure d’évaluations le
nombre de mouvement de données, alors l’algorithme en effectue
n-1, car il y a exactement un échange par itération.
2 Tri par Insertion

2.1 Principe

Insertion du prochain élément dans la partie qui est déjà triée


précédemment
La partie de départ qui est triée est le premier élément
Il se pourrait qu’on a à déplacer plusieurs éléments pour
l’insertion

1 i n
t
Les i-1 premiers Eléments à Les éléments
éléments déjà triés insérer non triés
2 Tri par Insertion
2 Tri par Insertion

2.2 Exemple

On veut trier les éléments:


42, 20, 17, 13, 28, 14, 23 et 15

i=1 i=2 i=3 i=4 i=5 i=6 i=7

42 20 17 13 13 13 13 13

20 42 20 17 17 14 14 14

17 17 42 20 20 17 17 15

13 13 13 42 28 20 20 17

28 28 28 28 42 28 23 20

14 14 14 14 14 42 28 23

23 23 23 23 23 23 42 28

15 15 15 15 15 15 15 42
2 Tri par Insertion

2.3 Implémentation

Procedure TriInsertion(Tableau entier [],


nbElements : entier)
Variables
i, j : entiers;
temp : entier;
Début
Pour i <- 1 à nbElements pas 1 faire
temp <- t[i];
j <- i-1;
Tant que (j >= 0 et t[j] > temp) faire
t[j+1] <- t[j];
j <- j - 1;
Fin tant que
t[j+1] <- temp;
Fin pour
Fin
2 Tri par Insertion

2.4 Implémentation : Exercice

Ecrire un programme en C qui trie dans un ordre croissant


les éléments d’un tableau d’entiers en utilisant le tri par
insertion.
2 Tri par Insertion

2.4 Implémentation : Correction

#include <stdio.h>
void tri_insertion(int tableau[], int taille) {
int i, j, temp;
for (i = 1; i < taille; i++) {
temp = tableau[i];
j = i - 1;
while (j >= 0 && tableau[j] > temp) {
tableau[j + 1] = tableau[j];
j--;
}
tableau[j + 1] = temp;
}
}
void afficher_tableau(int tableau[], int taille) {
printf("Tableau trié : ");
for (int i = 0; i < taille; i++) {
printf("%d ", tableau[i]);
}
printf("\n");
}
2 Tri par Insertion

2.4 Implémentation : Correction

int main() {
int tableau[] = {12, 5, 9, 3, 7};
int taille = sizeof(tableau) / sizeof(tableau[0]);

printf("Tableau non trié : ");


for (int i = 0; i < taille; i++) {
printf("%d ", tableau[i]);
}
printf("\n");

tri_insertion(tableau, taille);

afficher_tableau(tableau, taille);

return 0;
}
2 Tri par Insertion

2.5 Complexité

Comme nous n’avons pas nécessairement à scanner toute la


partie déjà triée, le pire cas, le meilleur cas et le cas moyen peuvent
différer entre eux.
Meilleur des cas: Chaque élément est inséré à la fin de la partie
triée. Dans ce cas, nous n’avons à déplacer aucun élément.
Comme nous avons à insérer (n-1) éléments, chacun générant
seulement une comparaison, la complexité est en O(n).
Pire des cas: Chaque élément est inséré au début de la partie trié.
Dans ce cas, tous les éléments de la partie triée doivent être
déplacés à chaque itération. La ième itération génère (i-1)
comparaisons et échanges de valeurs:

𝑖 − 1 = 𝑛(𝑛 − 1)/2 = 𝑂(𝑛 )


2 Tri par Insertion

2.5 Complexité

Note: C’est le même nombre de comparaison avec le tri par


sélection, mais effectue plus d’échanges de valeurs. Si les valeurs
à échanger sont importantes, ce nombre peut ralentir cet algorithme
d’une manière significative.
Cas moyen : Si on se donne une permutation aléatoire de nombre,
la probabilité d’insérer l’élément à la kème position parmi les
positions (0,1,2, …, i-1) est 1/i. Par conséquent, le nombre moyen
de comparaisons à la ième itération est:
𝑘−1 1 1 𝑖 𝑖−1 𝑖−1
= 𝑘= × =
𝑖 𝑖 𝑖 2 2
En sommant sur i, on obtient:
𝑖−1 1 𝑛 𝑛−1 𝑛
= = + 𝑂(𝑛)
2 2 2 4
3 Tri par Bulles

3.1 Principe

La stratégie de cet algorithme est :


1. Parcourir le tableau en comparant deux à deux les éléments
successifs, permuter s'ils ne sont pas dans l'ordre
2. Répéter tant que des permutations sont effectuées.
Le plus petit remonte en
surface

1 i n
t
Les i-1 premiers Les éléments
éléments déjà triés Niveau 0 non triés
3 Tri par Bulles
3 Tri par Bulles

3.2 Exemple

Même exemple

i=1 i=2

k=8 k=7 k=6 k=5 k=4 k=3 k=2 k=8 k=7 k=6 k=5 k=4 k=3

42 42 42 42 42 42 42 13 13 13 13 13 13 13

20 20 20 20 20 20 13 42 42 42 42 42 42 14

17 17 17 17 17 13 20 20 20 20 20 20 14 42

13 13 13 13 13 17 17 17 17 17 17 14 20 20

28 28 28 14 14 14 14 14 14 14 14 17 17 17

14 14 14 28 28 28 28 28 28 15 15 15 15 15

23 15 15 15 15 15 15 15 15 28 28 28 28 28

15 23 23 23 23 23 23 23 23 23 23 23 23 23
3 Tri par Bulles

3.2 Exemple

Même exemple

i=3 i=4

k=8 k=7 k=6 k=5 k=4 k=8 k=7 k=6 k=5

13 13 13 13 13 13 13 13 13 13 13

14 14 14 14 14 14 14 14 14 14 14

42 42 42 42 42 15 15 15 15 15 15

20 20 20 20 15 42 42 42 42 42 17

17 17 17 15 20 20 20 20 20 17 42

15 15 15 17 17 17 17 17 17 20 20

28 23 23 23 23 23 23 23 23 23 23

23 28 28 28 28 28 28 28 28 28 28
3 Tri par Bulles

3.2 Exemple

Même exemple

i=5 i=6 i=7

k=8 k=7 k=6 k=8 k=7 k=8

13 13 13 13 13 13 13 13 13
14 14 14 14 14 14 14 14 14
15 15 15 15 15 15 15 15 15
17 17 17 17 17 17 17 17 17
42 42 42 20 20 20 20 20 20
20 20 20 42 42 42 23 23 23
23 23 23 23 23 23 42 42 28
28 28 28 28 28 28 28 28 42
3 Tri à Bulles
3.3 Algorithme
Procédure TriBulles(t[] :entier, nbElements :
entier)
Variables
i, j : entiers;
temp : entier;
Début
Pour i<- 0 à nbElements-1 pas 1 faire
Pour j<- nbElements à i+1 pas -1 faire
Si t[j]<t[j-1] alors
temp <- t[j]
t[j] <- t[j-1]
t[j-1] <- temp
Fin si
Fin Pour
Fin Pour
Fin
3 Tri à Bulles
3.4 Implémentation :Exercice 1

1. Ecrire la procédure tri_bulle(int tab[], int taille)


2. Faire l’appel de tri-bulle dans la fonction principale main
3. Exécuter le programme sur le tableau T : [2, -1, 0, -4]
3 Tri à Bulles
3.5 Implémentation : Correction

#include <stdio.h>
void TriBulles(int t[], int nbElements) {
int i, j, temp;
for (i = 0; i < nbElements - 1; i++)
{
for (j = nbElements - 1; j > i; j--) {
if (t[j] < t[j - 1]) {
// Échanger les éléments si ils sont dans le mauvais ordre
temp = t[j];
t[j] = t[j - 1];
t[j - 1] = temp;
}}}
}
3 Tri à Bulles
3.5 Implémentation : Correction

int main()
{
int tableau[] = {2, -1, 0, -4};
int taille = 4;
printf("Tableau non trié : ");
for (int i = 0; i < taille; i++)
{
printf("%d \n ", tableau[i]); }
TriBulles(tableau, taille);
printf("Tableau trié : ");
for (int i = 0; i < taille; i++)
{
printf("%d \n ", tableau[i]);
}
return 0;
}
3 Tri à Bulles
3.5 Implémentation : Correction (2ème méthode)

#include <stdio.h>
void tri_bulle(int tab[], int taille) {
int i, j, temp;
for (i = 0; i < taille - 1; i++) {
for (j = 0; j < taille - i - 1; j++) {
if (tab[j] > tab[j + 1]) {
temp = tab[j];
tab[j] = tab[j + 1];
tab[j + 1] = temp;
}
}
}
}
3 Tri à Bulles
3.5 Implémentation : Correction (2ème méthode)

int main() {
int taille, i;
printf("Entrez la taille du tableau : ");
scanf("%d", &taille);
int tab[taille];
printf("Entrez les éléments du tableau : ");
for (i = 0; i < taille; i++) {
scanf("%d", &tab[i]);
}
tri_bulle(tab, taille);
printf("Tableau trié : ");
for (i = 0; i < taille; i++) {
printf("%d ", tab[i]);
}
printf("\n");
return 0;
}
3 Tri à Bulles
3.5 Implémentation : Correction

Exécution :
Tableau initial : [2, -1, 0, -4]
1ère iteration : [-1, 2, 0, -4] [-1, 0, 2, -4] [-1, 0, -4, 2]
2ème iteration : [-1, 0, -4, 2] [-1, -4, 0, 2] [-4, -1, 0, 2]
Le tableau est trié et la valeur finale est [-4, -1, 0, 2]
3 Tri à Bulles
3.4 Implémentation :Exercice 2

Ecrire le programme C qui lit un tableau d’entiers à deux


dimensions puis trie les éléments de chaque ligne
indépendamment avec l’algorithme de tri à Bulles, et
l’affiche.
3 Tri à Bulles
3.4 Implémentation: Correction

#include <stdio.h>
void tri_bulles_lignes(int tableau[][3], int nbLignes, int nbColonnes)
{
int temp;
for (int i = 0; i < nbLignes; i++) {
for (int j = 0; j < nbColonnes - 1; j++) {
for (int k = nbColonnes - 1; k > j; k--)
{ if (tableau[i][k] < tableau[i][k - 1]) {
// Échanger les éléments s’ils sont dans le mauvais ordre
temp = tableau[i][k];
tableau[i][k] = tableau[i][k - 1];
tableau[i][k - 1] = temp; } } } } }
void afficher_tableau(int tableau[][], int nbLignes, int nbColonnes) {
printf("Tableau trié :\n");
for (int i = 0; i < nbLignes; i++) {
for (int j = 0; j < nbColonnes; j++) { printf("%d \n ", tableau[i][j]); } } }
3 Tri à Bulles
3.4 Implémentation: Correction

int main() {
int nbLignes, nbColonnes;
printf("Entrez le nombre de lignes : ");
scanf("%d", &nbLignes);
printf("Entrez le nombre de colonnes : ");
scanf("%d", &nbColonnes);
int tableau[nbLignes][nbColonnes]; // Lire les éléments du tableau
for (int i = 0; i < nbLignes; i++) {
printf("Entrez les éléments de la ligne %d (%d éléments) : ", i + 1, nbColonnes);
for (int j = 0; j < nbColonnes; j++) {
scanf("%d", &tableau[i][j]); } }
printf("Tableau non trié :\n");
afficher_tableau(tableau, nbLignes, nbColonnes); tri_bulles_lignes(tableau,
nbLignes, nbColonnes);
printf("Tableau trié :\n");
afficher_tableau(tableau, nbLignes, nbColonnes);
return 0;
}
3 Tri par Bulles

3.6 Complexité

Le tri à bulles est l'un des tris les plus lents, si ce n'est le plus
lent. C'est pour cette raison que son utilisation se fait très rare
et cet algorithme reste très critiqué.
Meilleur des cas: (une seule itération) est atteint quand le
tableau est déjà trié. Dans ce cas, la complexité est en O(n).
Pire des cas: (n itérations) est atteint lorsque le plus petit
élément est à la fin du tableau. La complexité est alors O(n²).
Cas Moyen: En moyenne, la complexité est aussi O(n²).
En effet, le nombre d'échanges de paires d'éléments
successifs est égal au nombre d'inversions, c'est-à-dire de
couples (i,j) tels que i < j et T(i) > T(j). Ce nombre est
indépendant de la manière d'organiser les échanges.
Lorsque l'ordre initial des éléments du tableau est aléatoire, il
𝒏 𝒏 𝟏
est en moyenne égal à .
𝟒
4 Tri Rapide

4.1 Principe

Inventé en 1960 par Sir Charles Antony Richard Hoare


Consiste à:
Choisir un élément « pivot »
Diviser l’ensemble à deux sous-ensembles
Répéter la procédure récursivement
pivot
Éléments inférieurs au Éléments supérieurs au
pivot pivot
1 n
t

Pivot’ Pivot’’
4 Tri Rapide

4.2 Exemple
4 Tri Rapide
4 Tri Rapide
4.3 Algorithme

Fonction Partitionner(t: tableau d’entiers, debut: entier, fin:


entier): entier
Début
Variables
Pivot : entier
i, j, pivot : entiers
Vide : entier
Début
Pivot<-t[fin] //Choisir le pivot comme élément le plus à droite
i<-debut-1 //Indice de l'élément plus petit
Pour j de début à fin – 1 pas -1 //Parcourir tous les éléments sauf le
pivot
Si t[j] <= pivot alors
i <- i + 1 //Incrémenter l'indice de l'élément plus petit
Echanger(t[i], t[j])//Échanger l'élément actuel avec l'élément plus
petit
Echanger(t[i+1], t[fin]) //Échanger le pivot avec l'élément à indice
suivante de l’élement le plus petit
retourne i+1 // Retournez l'indice du pivot
Fin
4 Tri Rapide
4.3 Algorithme

Procedure Echanger(t: tableau d’entiers, a : entier, b :


entier)
Variables temp : entier
temp= t[a]
T[a]= t[b]
T[b]= temp
Fin

Procedure TriRapide(t : tableau d’entiers, debut, fin :


entier)
Variables
indicePivot : entier
Début
Si debut<fin alors
indicePivot<-Partitionner(t, debut, fin)
TriRapide(t, debut, indicePivot-1);
TriRapide(t, indicePivot+1, fin);
Fin si
Fin
4 Tri Rapide
4.4 Implémentation :Exercice

1. Ecrire la procédure partitionner(int tab[], int debut, int fin)


2. Ecrire la procédure echanger(int t[], int a, int b)
3. Ecrire la procédure tri_rapide(int tab[], int debut, int fin)
4. Ecrire la procédure afficheTableau(int tab[], int n)
5. Faire les appels nécessaires dans la fonction principale
main
4 Tri Rapide
4.5 Implémentation : Correction

#include <stdio.h>

// Fonction pour échanger deux éléments dans un tableau


void echanger(int t[], int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
3 Tri à Bulles
4.5 Implémentation : Correction

partitionner(int t[], int debut, int fin) {


// Choisissez le pivot comme élément le plus à droite
int pivot = t[fin];
// Indice de l'élément plus petit
int i = debut - 1;
// Parcourir tous les éléments, sauf le pivot
for (int j = debut; j <= fin - 1; j++) {
// Si l'élément actuel est plus petit ou égal au pivot
if (t[j] <= pivot) {
// Incrémentez l'indice de l'élément plus petit
i++;
// Échangez l'élément actuel avec l'élément plus petit
echanger(t, i, j);
} }
// Échangez le pivot avec l'élément à l'indice suivante de
l'élément plus petit
echanger(t, i + 1, fin);
// Retournez l'indice du pivot
return (i + 1);
}
3 Tri à Bulles
4.5 Implémentation : Correction

void tri_rapide(int t[], int debut, int fin) {


if (debut < fin) {
// Trouver l'indice du pivot
int pivotIndex = partitionner(t, debut, fin);
// Trier les éléments avant et après le pivot
tri_rapide_croissant(t, debut, pivotIndex - 1);
tri_rapide_croissant(t, pivotIndex + 1, fin);
}
}

// Fonction d'affichage pour vérifier le résultat


void afficheTableau(int t[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", t[i]);
}
printf("\n");
}
}
3 Tri à Bulles
4.5 Implémentation : Correction

// Exemple d'utilisation
int main() {
int t[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(t) / sizeof(t[0]);

printf("Tableau non trié : \n ");


afficheTableau(t, n);

tri_rapide_croissant(t, 0, n - 1);

printf("Tableau trié en ordre croissant : \n ");


afficheTableau(t, n);

return 0;
}
4 Tri Rapide

4.6 Complexité

La partie du tri la plus sensible reste le choix du pivot. Dans


l'algorithme précédent, il est choisi au hasard parmi les éléments du
tableau, mais ce choix peut se révéler catastrophique : si le pivot
est à chaque choix le plus petit élément du tableau, alors le tri
rapide dégénère en tri par sélection.
En général, la complexité de ce tri est :
 dans le meilleur des cas, en O (N log2 N) ;
 en moyenne, en O (N log2 N) ;
 dans le pire des cas, en O (N2).
Il existe bon nombre d'astuces pour rendre le cas dégénéré du tri
rapide le plus improbable possible, ce qui rend finalement cette
méthode la plus rapide en moyenne parmi toutes celles utilisées.

Vous aimerez peut-être aussi