Académique Documents
Professionnel Documents
Culture Documents
I- Algorithmes de tri
Généralité
• Père
Fonction pere({E} i : entier) : entier
début
renvoyer (i mod 2)
fin
• Fils gauche
Fonction gauche({E} i : entier) : entier
début
renvoyer (2*i)
fin
• Fils droit
Fonction droit({E} i : entier) : entier
début
renvoyer (2*i+1)
fin
Les tas satisfont également la propriété de tas : pour chaque nœud i autre que la
racine,
• Tas-max : chaque élément est inférieur à son parent, ainsi, le plus grand élément d'un
tas max est stocké dans la racine.
NB : Pour l'algorithme du tri par tas, on utilise des tas max. Les tas min servent
généralement dans les files de priorités.
• Partition du tableau
Principe :
Pour faire la partition d'un Tableau Tab en deux sous-tableaux L1 et L2 :
on choisit une valeur quelconque dans du tableau Tab (la dernière par exemple) que l'on
dénomme pivot, puis on construit
le sous-tableau L1 comme comprenant tous les éléments de L dont la valeur est inférieure ou
égale au pivot,
et l'on construit la sous-tableau L2 comme constituée de tous les éléments dont la valeur est
supérieure au pivot.
Tab = [ 4, 23, 3, 42, 2, 14, 45, 18, 38, 16 ]
Prenons comme pivot la dernière valeur pivot = 16
Nous obtenons par exemple :
L1 = [4, 14, 3, 2] // tous les valeurs du tableau inférieures ou égales au pivot
L2 = [23, 45, 18, 38, 42] // tous les valeurs du tableau supérieures au pivot
A cette étape voici l'arrangement de Tab :
Tab = L1 + pivot + L2 => [4, 14, 3, 2, 16, 23, 45, 18, 38, 42]
En appliquant la même démarche au deux sous-listes : L1 (pivot=2) et L2 (pivot=42)
Cas de L1 prenons comme pivot la dernière valeur pivot = 2
Nous aurons deux sous-tableaux à savoir L11( pour les valeurs inférieures ou égales au pivot)
et L12( pour les valeurs supérieures au pivot)
L11=[ ] liste vide // tous les valeurs du tableau inférieures ou égales au pivot
L12=[3, 4, 14] // tous les valeurs du tableau supérieures au pivot
L1=L11 + pivot + L12 => [2,3, 4,14]
Cas de L2 prenons comme pivot la dernière valeur pivot = 42
Nous aurons deux sous-tableaux à savoir L21( pour les valeurs inférieures ou égales au pivot)
et L22( pour les valeurs supérieures au pivot)
L21=[23, 38, 18] // tous les valeurs du tableau inférieures ou égales au pivot
L22=[45] // tous les valeurs du tableau supérieures au pivot
L2=L21 + pivot + L22 => [23, 38, 18, 42, 45]
A cette étape voici le nouvel arrangement de Tab :
Tab = [(2,3, 4, 14), 16, (23, 38, 18, 42, 45)]
On répétera cette action jusqu'au rangement complet de Tab
etc...
Ainsi de proche en proche en subdivisant le problème en deux sous-problèmes, à chaque étape
nous obtenons un pivot bien placé.
Le point principal de l'algorithme est la fonction Partition qui réarrange le sous tableau
Tab[p..r]. En plus, elle émet l'indice de partitionnement q.
fonction Partition( A, p ,r : entier ) : entier
var
i , j , piv , temp : entier
début
piv ← Tab[r];
i ← p-1;
j ← r;
repeter
repeter
i ← i+1
jusquà Tab[i] >= piv // recherche l'indice de la valeur supérieur e ou égale au pivot
repeter
j ← j-1
jusquà Tab[j] <= piv // recherche l'indice de la valeur inférieure ou égale au pivot
//****** Permuter les valeurs des indices de i et j *******
temp ← Tab[i];
Tab[i] ← Tab[j];
Tab[j] ← temp
jusqu à j <= i;
//******************* Refaire une autre permutation après la sortie de la boucle avec les
indice i,j et r
Tab[j] ← Tab[i];
Tab[i] ← Tab[r];
Tab[r] ← temp;
renvoyer i
FinPartition
Explication : La variable pointeur Pt pointe sur l'espace mémoire Pt^ d'adresse Adr1. Cette
cellule mémoire contient la valeur "UVCI" dans le champ Info et la valeur spéciale Nil dans
le champ Suivant.
Ce champ Suivant servira à indiquer quel est l'élément suivant lorsque la cellule fera partie
d'une Liste. La valeur Nil indique qu'il n'y a pas d'élément suivant. Pt^ est l'objet dont
l'adresse est rangée dans Pt.
Remarque : Les listes chaînées entraînent l'utilisation de procédures d'allocation et de
libération dynamiques de la mémoire. Ces procédures sont les suivantes :
Allouer(Pt) : réserve un espace mémoire Pt^ et donne pour valeur à Pt l'adresse de cet espace
mémoire. On alloue un espace mémoire pour un élément sur lequel pointe Pt.
Désallouer(Pt) : libère l'espace mémoire qui était occupé par l'élément à supprimer Pt^ sur
lequel pointe Pt.
Pour définir les variables utilisées ci-dessus, il faut :
//définir le type des éléments de liste :
Type Cellule= Structure
Info : Chaîne
Suivant : Liste
fin Structure
//définir le type du pointeur :
Type Liste = ^Cellule
//déclarer une variable pointeur à partir du type pointeur transcrit dans Liste :
Var
Pt : Liste
//allouer une cellule mémoire qui réserve un espace en mémoire et donne à Pt la valeur de
l'adresse de l'espace mémoire Pt^:
Allouer(Pt)
//affecter des valeur à l'espace mémoire Pt^:
Pt^.Info ← "UVCI"
Pt^.Suivant ← Nil
//Quand Pt = Nil alors Pt ne pointe sur rien.
Pour accéder au troisième élément de la Liste, il faut toujours débuter la lecture de la Liste par
son premier élément dans le pointeur duquel est indiqué la position du deuxième élément.
Dans le pointeur du deuxième élément de la Liste on trouve la position du troisième élément
etc.
Il existe différents types de listes chaînées :
Liste chaînée simple constituée d'éléments reliés entre eux par des pointeurs.
Liste chaînée ordonnée où l'élément suivant est plus grand que le précédent. L'insertion et la
suppression d'élément se font de façon à ce que la liste reste triée.
Liste doublement chaînée où chaque élément dispose non plus d'un mais de deux pointeurs
pointant respectivement sur l'élément précédent et l'élément suivant. Ceci permet de lire la
liste dans les deux sens, du premier vers le dernier élément ou inversement.
Liste circulaire où le dernier élément pointe sur le premier élément de la liste. S'il s'agit d'une
liste doublement chaînée alors de premier élément pointe également sur le dernier.
Ces différents types peuvent être mixés selon les besoins.
NB :
On utilise une liste chaînée plutôt qu'un tableau lorsque l'on doit traiter des objets
représentés par des suites sur lesquelles on doit effectuer de nombreuses suppressions et
de nombreux ajouts. Les manipulations sont alors plus rapides qu'avec des tableaux.
• Les piles
Une pile est une liste chaînée d'informations dans laquelle :
Un élément ne peut être ajouté qu'au sommet de la pile,
Un élément ne peut être retiré que du sommet de la pile.
Il s'agit donc d'une structure de type LIFO (Last In First Out) Traduction : « Le dernier
élément qui a été ajouté est le premier à sortir ».
On ne travaille que sur le sommet de la pile. Les éléments de la pile sont reliés entre eux à
la manière d'une liste chaînée. Ils possèdent un pointeur vers l'élément suivant.
Le dernier élément (tout en bas de la pile) doit pointer vers nil.
• Les files
Une file est une liste chaînée d'informations qui est basée sur une structure de données basée
sur le principe « Premier entré, premier sorti », en anglais FIFO (First In, First Out), ce qui veut
dire que les premiers éléments ajoutés à la file seront les premiers à être récupérés.
Le fonctionnement ressemble à une file d'attente : les premières personnes à arriver sont les
premières personnes à sortir de la file.
Une file est comparable à une queue de clients à la caisse d'un magasin.
Les files servent à traiter les données dans l'ordre où on les a reçues et permettent de :
- gérer des processus en attente d'une ressource système (par exemple la liste des travaux à
éditer sur une imprimante)
- construire des systèmes de réservation
- certains moteurs multitâches, dans un système d'exploitation, qui doivent accorder du temps-
machine à chaque tâche, sans en privilégier aucune.
- un algorithme de parcours en largeur utilise une file pour mémoriser les nœuds visités.
- on utilise aussi des files pour créer toutes sortes de mémoires tampons (en anglais buffers).
etc.
Pour ne pas avoir à parcourir toute la liste au moment d'ajouter un élément en queue, on
maintient un pointeur de queue. Attention une file peut très bien être simplement chaînée
même s'il y a un pointeur de queue.