Les tris
Traitement de données triées Les tris Traitement de données triées Le traitement de données déjà triées est plus rapide. Nécessaire pour le traitement séquentiel d’intervalles. Il faut trier des données à bas coût ! nb de comparaisons nb de déplacements d’éléments
Tri selon une relation d’ordre Les tris Tri selon une relation d’ordre Besoin : attribut de tri :<nom,…>, <nom,prenom,...> generalement une cle que l’on peut comparer {<,=,>} deplacer toute l’information :<cle,...> ou <cle,indirection>, + indirection vers l’information
Les tris Tris simples tri par insertion : 44,55,12,42,94,18,06,67 Algorithme : insérer chacun des n elements à la bonne place dans le tableau creéé jusqu’ici
Les tris Tris simples tri par insertion : 44,55,12,42,94,18,06,67 44 12,44,55 12,42,44,55 12,42,44,55,94 12,18,42,44,55,94 06,12,18,42,44,55,94 06,12,18,42,44,55,67,94
Les tris Tris simples tri par insertion : #include <stdio.h> 1/2 #define CN 0 #define OK 1 typedef int TypeEl; void triInsertion(TypeEl tab[], int n, int * err); void main() { TypeEl x[]={44,55,12,42,94,18,6,67}; int nbr,i; nbr=sizeof(x)/sizeof(TypeEl); printf("Le tableau non trie\n"); for(i=0;i<nbr;i++) printf("%3d",x[i]); printf("\n"); int err; triInsertion(x,nbr,&err); printf("Le tableau trie\n"); }
Les tris Tris simples tri par insertion : void triInsertion(TypeEl tab[], int n, int * err) 2/2 { /* connu: - entree: tab, n sortie: ----resultat: tab trie et *err = OK, si n >= 0,tab est inchange et *err = CN, sinon. hypothese: n >= 0 */ int i, j; TypeEl x; if(n < 0) { *err = CN; return; } *err = OK; for(i = 1; i < n; i++) { j = i; x = tab[i]; while(j-1 >= 0 && x < tab[j-1]) { tab[j] = tab[j-1]; j--; } tab[j] = x;
Les tris Tris simples tri par insertion : Le tableau non trie 44 55 12 42 94 18 6 67 Le tableau trie 6 12 18 42 44 55 67 94
Les tris Tris simples tri par insertion : Meilleur cas : séquence triée nb de comparaisons ? O(n) nb de deplacements ? O(n) Pire cas : séquence triée inverse nb de comparaisons ? O(n2) nb de deplacements ? O(n2)
Les tris Tris simples tri par sélection : 44,55,12,42,94,18,06,67 Algorithme : remplir les cases de 1 à n avec le minimum des éléments du tableau restant
Les tris Tris simples tri par sélection : 44,55,12,42,94,18,06,67 06,55,12,42,94,18,44,67 06,12,55,42,94,18,44,67 06,12,18,42,94,55,44,67 06,12,18,42,44,55,94,67 06,12,18,42,44,55,67,94
Les tris Tris simples tri par sélection : #include <stdio.h> 1/3 #define CN 0 #define OK 1 typedef int TypeEl; void triSelection(TypeEl tab[], int n, int * err); void main() { TypeEl x[]={44,55,12,42,94,18,6,67}; int nbr,i; nbr=sizeof(x)/sizeof(TypeEl); printf("Le tableau non trie\n"); for(i=0;i<nbr;i++) printf("%3d",x[i]); printf("\n"); int err; triSelection(x,nbr,&err); printf("Le tableau trie\n"); }
Les tris Tris simples tri par sélection : void triSelection(TypeEl tab[], int n, int * err) 2/3 { /* connu: - entrée: tab, n; sortie: - résultat: tab trié et *err = OK, si n>= 0 tab est inchangé et *err = CN, sinon. hypothese: n >= 0 */ int i, j, pos; TypeEl x; for(i = 0; i < n -1; i++) { pos = i; x = tab[i]; for(j = i + 1; j < n; j++) { if (tab[j] < x) { x = tab[j]; pos = j; }
Les tris Tris simples tri par sélection : /*x est l’élément minimum du sous-tableau non trié*/ 3/3 if (x != tab[i]) { tab[pos] = tab[i]; tab[i] = x; } } //fin de boucle for } //fin de la fonction Le tableau non trie 44 55 12 42 94 18 6 67 Le tableau trie 6 12 18 42 44 55 67 94
Les tris Tris simples tri à bulles (Bubblesort) : 44,55,12,42,94,18,06,67 Algorithme : remonter les plus petites bulles à la surface, et ce, à chaque itération
Les tris Tris simples tri à bulles (Bubblesort) : 44,55,12,42,94,18,06,67 06,44,55,12,42,94,18,67 06,44,55,12,18,42,94,67 06,12,44,55,18,42,94,67 06,12,44,55,18,42,67,94 06,12,18,44,55,42,67,94 06,12,18,42,44,55,67,94
Les tris Tris simples tri à bulles (Bubblesort) : #include <stdio.h> 1/2 #define CN 0 #define OK 1 typedef int TypeEl; void triBulles(TypeEl tab[], int n, int * err); void main() { TypeEl x[]={44,55,12,42,94,18,6,67}; int nbr,i; nbr=sizeof(x)/sizeof(TypeEl); printf("Le tableau non trie\n"); for(i=0;i<nbr;i++) printf("%3d",x[i]); printf("\n"); int err; triBulles(x,nbr,&err); printf("Le tableau trie\n"); }
Les tris Tris simples tri à bulles (Bubblesort) : void triBulles(TypeEl tab[], int n, int * err) 2/2 { /* connu: - entrée: tab, n; sortie: - résultat: tab trié et *err = OK, si n>= 0 tab est inchangé et *err = CN, sinon. hypothese: n >= 0 int i, j, pos; TypeEl x; for(i = 1; i < n; i++) { for(j = n - 1; j >= i; j--) { if ( tab[j-1] > tab[j]) { x = tab[j-1]; tab[j-1] = tab[j]; tab[j] = x; } Le tableau non trie 44 55 12 42 94 18 6 67 Le tableau trie 6 12 18 42 44 55 67 94
Les tris Tris simples tri à bulles (Bubblesort) - amélioration void triBulles(TypeEl tab[], int n, int * err) { int i, pos, change; TypeEl x; pos=1; //le nombre d’éléments triés après la boucle for do { change=0; for(i = 0; i < n-pos; i++) if ( tab[i] > tab[i+1]) { x = tab[i]; tab[i] = tab[i+1]; tab[i+1] = x; change=1; } pos++; }while(change); Amélioration consiste à arrêter le processus s'il n'y a aucun échange dans une passe
Les tris Tris simples tri par fusion (merge sorting): Algorithme Fusion de deux tableaux triés en un seul plus grand, appelé récursivement sur les deux moitiés du tableau, jusqu'à une taille de tableau de 1 (ou plus, avec un tri spécifique pour petits tableaux, par exemple par échange sur des sous-tableaux de 3 éléments).
Les tris tri par fusion (merge sorting): Le premier étape Le deuxième étape
Les tris Tris simples tri par fusion (merge sorting): #include <stdio.h> 1/4 void merge_sort(int in[],int a,int b,int out[]); void aff_tab(int in[],int k); void merge_array(int in1[],int in2[],int n1,int n2,int out[]); int compar=0; main() { int in_tab[] = {3,1,4,1,5,9,2,6,5,4}; int n=sizeof(in_tab)/sizeof(int); int out_tab[20]; printf("Le tableau non trie\n"); aff_tab(in_tab,n); merge_sort(in_tab,0,n-1,out_tab); printf("Le tableau trie\n"); aff_tab(out_tab,n); printf("Le nombre de comparaison est %d\n",compar); } Le tableau non trie 3 1 4 1 5 9 2 6 5 4 Le tableau trie 1 1 2 3 4 4 5 5 6 9 Le nombre de comparaison est 22
Les tris Tris simples tri par fusion (merge sorting): Définition de la fonction d’affichage void aff_tab(int in[],int k) 2/4 { int i; for(i=1;i<=k;i++) printf("%d%c",in[i-1],i%5==0?'\n':' '); printf("\n"); }
Les tris Tris simples tri par fusion (merge sorting): void merge_sort(int in[],int a,int b,int out[]) 3/4 { int m, out1[20], out2[20]; if(a==b) out[0]=in[a]; else if(1==(b-a)) { if ( in[a]<=in[b] ) { out[0]=in[a]; out[1]=in[b]; } else { out[0]=in[b]; out[1]=in[a]; } compar++; } { m=a+(b-a)/2; merge_sort(in, a, m, out1); merge_sort(in, m+1, b, out2); merge_array(out1, out2, 1+m-a, b-m, out); Définition de la fonction merge_sort
Les tris Tris simples tri par fusion (merge sorting): void merge_array(int in1[],int in2[],int n1,int n2,int out[]) 4/4 { int i=0,j=0,k=0; while ( (i<n1) && (j<n2) ) { if(in1[i] <= in2[j]) { out[k]=in1[i]; i++; } else { out[k]=in2[j]; j++; } k++; compar++; } if(i !=n1) do { out[k]=in1[i]; i++; } while(i<n1); else do { out[k]=in2[j]; j++; } while(j<n2); Si on a des éléments dans les deux sous-tableaux Définition de la fonction merge_array Si on n’a pas d’éléments dans un des deux sous-tableaux
Les tris Tris simples tri panier (bucket sort) La grandeur de l’ensemble de base est petite, une constante fixe m On utilise m compteurs
Les tris Tris complexes tri rapide (Quicksort) : Ce tri est récursif. On cherche à trier une partie du tableau délimitée par les indices gauche et droite. On choisit une valeur de ce sous-tableau (une valeur médiane serait idéale, mais sa recherche ralentit plus le tri que de prendre aléatoirement une valeur, par exemple la dernière), = pivot.
Les tris Tris complexes tri rapide (Quicksort) : On cherche la position définitive de ce pivot, On effectue des déplacements de valeurs de telle sorte que tous les éléments avant le pivot soient plus petits que lui, et que toutes celles après lui soient supérieures, mais sans chercher à les classer pour accélérer le processus. On rappelle récursivement le tri de la partie avant le pivot, et de celle après le pivot. On arrête la récursivité sur les parties à un seul élément, nécessairement triée. L'algorithme est achevé quand les piles ne contiennent plus aucune partie de liste à être traitée par l'étape de réduction.
Les tris Tris complexes tri rapide (Quicksort) : 44,55,12,42,94,18,06,67 Algorithme : choisir un pivot p (élément médian) partager le tableau en 2: Sous - tableau de gauche : éléments <= p Sous - tableau de droite : éléments > p appel récursif avec le sous - tableau de gauche appel récursif avec le sous - tableau de droite
Les tris Tris complexes tri rapide (Quicksort) : 44,55,12,42,94,18,06,67 06,55,12,42,94,18,44,67 06,18,12,42,94,55,44,67
Les tris Tris complexes tri rapide (Quicksort) : 06,18,12,42,94,55,44,67 06,12,18,42,94,55,44,67 06,12,18,42,44,55,94,67 06,12,18,42,44,55,67,94
Les tris Tris complexes tri rapide (Quicksort) : #include <stdio.h> 1/4 typedef int TypeEl; void swap(TypeEl *a,int l,int r); quicksort( TypeEl *a, int low, int high ); void partition( TypeEl *a, int low, int high,int *pivot ); void main() { TypeEl x[ ]={44,55,12,42,94,18,6,67}; int nbr,i; nbr=sizeof(x)/sizeof(TypeEl); printf("Le tableau non trie\n"); for(i=0;i<nbr;i++) printf("%3d",x[i]); printf("\n"); quicksort(x,0,nbr-1); printf("Le tableau trie\n"); } Le tableau non trie 44 55 12 42 94 18 6 67 Le tableau trie 6 12 18 42 44 55 67 94
Les tris Tris complexes tri rapide (Quicksort) : Définition de la fonction quicksort quicksort( TypeEl *a, int low, int high ) 2/4 { int pivot; /* condition terminale! */ if ( high > low ) partition( a, low, high,& pivot ); quicksort( a, low, pivot-1 ); quicksort( a, pivot+1, high ); }
Les tris Tris complexes tri rapide (Quicksort) : void partition( TypeEl *a, int low, int high, int *pivot) 3/4 { int left, right; TypeEl pivot_item; *pivot = (low+high)/2; pivot_item = a[*pivot]; left=low; right = high; while ( left < right ) { /* deplacer le pointeur gauche tant que element < pivot */ while( a[left] < pivot_item ) left++; /* deplacer le pointeur droite tant que element > pivot */ while( a[right] >= pivot_item ) right--; if ( left < right) swap(a,left,right); } Définition de la fonction partition
Les tris Tris complexes tri rapide (Quicksort) : Définition de la fonction d’échange void swap(TypeEl *a,int l,int r) 4/4 { TypeEl t; t=a[l]; a[l]=a[r]; a[r]=t; }
Les tris Tris complexes tri rapide (Quicksort) : Meilleur cas : pivot = médiane nb de comparaisons ? O(n log n) nb de déplacements ? O(1)
Les tris Tris complexes tri rapide (Quicksort) : Pire cas : pivot = min. ou max. nb de comparaisons ? O(n2) nb de déplacements ? O(n2)
Les tris Tris complexes tri rapide (Quicksort) : Exemple – Trier en ordre alphabétique une séquence de chaînes de caractères entrées par clavier en utilisant la fonction standarde qsort (de la bibliothèque stdlib.h). #include <stdio.h> 1/2 #include <string.h> #include <stdlib.h> #define MAXMOTS 100 #define MAXCARS 3000 char espace[MAXCARS], *libre = espace; char *mots[MAXMOTS]; int nbr_mots = 0; int comparer(const void *a, const void *b) { /* Les arguments de cette fonction doivent être déclarés "void *" (voyez la */ /* déclaration de qsort). */ return strcmp(*(char **)a, *(char **)b); } a et b sont des adresses de "chaînes"
Les tris Tris complexes tri rapide (Quicksort) : Exemple – Trier en ordre alphabétique une séquence de chaînes de caractères entrées par clavier en utilisant la fonction standarde qsort (de la bibliothèque stdlib.h). main() 2/2 { int i; while(puts ("Entrer une chaine\n"),gets(libre) != NULL && *libre != '\0') { mots[nbr_mots++] = libre; libre += strlen(libre) + 1; } qsort(mots, nbr_mots, sizeof(char *), comparer); for (i = 0; i < nbr_mots; i++) printf("%s\n", mots[i]);
Les tris Tris complexes tri rapide (Quicksort) - problèmes: Algorithme récursif : taille de la pile =? meilleur cas :O(log n) pire cas :O(n) en moyenne : O(log n) Comment faire pour minimiser la taille de la pile ? empiler toujours le plus grand des 2 sous-tableaux O(1) <= taille de la pile <= O(log n) plutot que : O(1) <= taille de la pile <= O(n)
Les tris Tris complexes tri rapide (Quicksort) - problèmes: Attention aux bornes: Choix de pivot Comment choisir un bon pivot ? Solution idéale : Trouver a chaque fois la valeur médiane du sous - tableau a trier - sa recherche précise rend le tri plus lent que sans elle. Solution quelquefois utilisée : Prendre par exemple trois valeurs, pour en prendre la valeur médiane. La totalité de ces améliorations peut apporter un gain de l'ordre de 20% par rapport à la version de base.
Les tris Tris complexes tri par arbre (Treesort): Algorithme Utiliser une structure d’arbre pour trier la séquence de clés.