Vous êtes sur la page 1sur 38

1. Qu’est- ce qu’un tri ?

Donnons-nous un tableau de nombres. Le problème est de trier ces nombres dans l’ordre
croissant. En d’autres termes, nous devons modifier le tableau pour qu’il contienne les mêmes
nombres qu’auparavant, mais cette fois les nombres sont rangés dans l’ordre croissant, du
plus petit au plus grand.
Exemple
Le résultat du tri du tableau : 6 3 7 2 3 5

Est le suivant : 2 3 3 5 6 7

2. Tri par sélection


2.1. Principe du tri par sélection
Donnons-nous un tableau T de n nombres. Le principe du tri par sélection est le suivant. On
sélectionne le minimum de tous les éléments, et on le place en première par un échange. Il ne
reste plus qu’à trier les n-1 premiers éléments, pour lesquels on itère le procédé.
(Expliqué avec un exemple)
2.2. Algorithme de tri par sélection
L’algorithme de tri par sélection (par exemple sur des nombres entiers) est le suivant :

Procédure TriSelection (entier T


void TriSelection (int T [],
[], entier n)
int n)
début
{
entier i, j, imin, temp;
int imin, temp;
pour i ← 0 à n-1 pas 1
for (int i=0;i<n; i++)
faire
{
imin ← i;
imin = i;
pour j← i+1 à n-1 pas 1
for (int j=i+1;j<n;
faire
j++)
si T[imin] >T[j]
if (T[imin]
imin ← j;
> T[j])
fin pour
imin
temp ← T[i];
=j;
T[i] ← T[imin];
temp = T[i];
T[imin] ← temp;
T[i] = T[imin];
fin pour
T[imin] = temp;
}
}
Structures de données avancées Université Larbi Tébessi L. Laimeche

2.3. Estimation du nombre d’opérations


• Coût des échanges : Le tri par sélection sur n nombres fait n − 1 échanges, ce qui fait 3(n −
1) affectations.
3. Tri par bulles
Principe du tri par bulles

Dans le tri par bulle, on échange deux éléments successifs T[i-1] et T[i] s’ils ne sont pas dans
l’ordre. Évidemment, il faut faire cela un grand nombre de fois pour obtenir un tableau trié.
Plus précisément, on fait remonter le maximum à sa place définitive par échanges successifs
avec ses voisins.
3.1.Algorithme de tri par bulles
L’algorithme de tri par bulles (par exemple sur des nombres entiers) est le suivant :

Procédure TriBulles (entier T [], entier


n)
début void TriBulle (int T [], int n)
entier i, j; {
booléen vérif. = faux ; int temp;
i=0 ; for (int i=n-1;i>0;i--)
tant que (i<n ) et (vérif.=faux) {
vérif.= vrai ; j=i ; for(int j=0;j<i-1;j++)
tant que (j<n-1 ) {
si T[j] > T[j+1] if (T[j] > T[j+1])
début {
vérif. = faux ; temp = T[j];
temp ← T[i]; T[j] =
T[i] ← T[j+1]; T[j+1];
T[j+1] ← temp; T[j+1] =
fin temp;}
j=j+1 ; }
fin tant que }
fin tant que
fin

Page 2 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

4. Tri par insertion


4.1. Principe du tri par insertion
Le principe du tri par insertion est le suivant : on trie d’abord les deux premiers éléments, puis
on insère le 3ème à sa place pour faire une liste triée de 3 éléments, puis on insère le 4ème
élément dans la liste triée. La liste triée grossit jusqu’à contenir les n éléments.
(Expliqué avec un exemple)

void TriInsertion (int T [], int n)


{
int val, j;
for(int i=0;i<n; i++)
{
val=T[i];
j=i-1;
while((j>=0)&&(val<T[j]))
{

T[j+1] =T[j];
j--;
}
T[j+1] = val;
}
}

Estimation du nombre d’opérations


L’indice i varie de 1 à n − 1, soit n − 1 valeurs différentes. Pour chaque valeur de i, l’indice j
prend au plus i valeurs différentes. Le total du nombre d’opérations est donc au plus de :

Soit un nombre d’opération d’au plus :

Ce qui est un polynôme du second degré en le nombre n d’éléments. L’algorithme est donc
quadratique .

Page 3 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

5. Trie rapide:
On choisit aléatoirement un indice dans la table à trier, le pivot. Puis on partage les éléments
de la table en ceux qui sont plus petits, qu’on place avant, et ceux qui sont plus grands, qu'on
place après. On recommence récursivement sur les deux sous listes de chaque côté du pivot.

Partitionner (tableau T, entier premier, entier dernier, entier pivot)


Échanger T[pivot] et T[dernier]
j := premier
pour i de premier à dernier - 1
si T[i] <= T[dernier] alors
échanger T[i] et T[j]
j := j + 1
échanger T[dernier] et T[j]
renvoyer j

Tri_rapide(tableau T, entier premier, entier dernier)


si premier < dernier alors
pivot := choix_pivot(T, premier, dernier)
pivot := partitionner(T, premier, dernier, pivot)
tri_rapide(T, premier, pivot-1)
tri_rapide(T, pivot+1, dernier)
finsi
fin

Page 4 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

1.1.

La complexité des algorithmes est une évaluation du coût d’exécution d’un algorithme en
termes de temps (complexité temporelle) ou d’espace mémoire (complexité spatiale). Le cout
d’exécution dépend de:

 Nombre des données,


 La taille du code,
 Type de la machine sur laquelle s’exécute l’algorithme (processeur), et
 La complexité en termes de temps de l’algorithme « abstrait » sous-jacent.

1.2.

Exemple : échange de deux valeurs entières

Programme A Programme B
int main() int main()
{ {
int A = 10,B = 15, Temp; int A = 10,B = 1;
Temp = A; A = B - A;
A = B; B = B - A
B=Temp ; A = A + B;

} }

 Le programme A utilisé une variable supplémentaire et réalise 3 affectations,


 Alors le deuxième programme n'utilise que les deux variables dont on veut échanger les
valeurs, mais réalise 3 affectations et 3 opérations.

1.3.

Calculer la complexité d’un algorithme consiste à calculer le temps d’exécution d’un


algorithme, on ne mesure pas la durée en heures, minutes, secondes. Ces mesures ne seraient
pas pertinentes car le même algorithme sera plus rapide sur une machine plus puissante.
Page 5 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

De ce fait, nous utilisons des unités de temps abstraites proportionnelles au nombre


d'opérations effectuées. On pourra ensuite adapter ces quantités en fonction de la machine sur
laquelle l'algorithme s'exécute.
Ainsi :
 Chaque instruction basique consomme une unité de temps (affectation d'une variable,
comparaison, ),
 Chaque itération d'une boucle rajoute le nombre d'unités de temps consommées dans le
corps de cette boucle,
 Chaque appel de fonction rajoute le nombre d'unités de temps consommées dans cette
fonction,
 Pour avoir le nombre d'opérations effectuées par l'algorithme, on additionne le tout.

Exemple : calcul de la factorielle de n

Algorithme factoriel
Var fact, i, n : entier Test à chaque itération :1
Début
Lire (n) …………………………………………… Introduire une valeur :1
i  2 …………………………………………… Initialisation :1
fact 1 …………………………………………… Initialisation :1
Tant que i ≤ n faire ……………………… Itérations :n-1
fact fact* i ……………………………Multiplication + Affectation :2
i  i+1 ………………………………………… Addition + Affectation :2
Fin tant que
Écrire (fact)……………………………………… renvoi d’un résultat :1
Fin

Nombre total d'opérations est :

1.4.

Le paramètre de complexité est la variable qui va faire varier le temps d'exécution de


l'algorithme.

Exemples

1. Calcul de factorielle
 Le paramètre de complexité est la valeur de n
2. Multiplier tous les éléments d'un tableau d'entiers par un entier donné
 Le paramètre de complexité est la longueur de Tableau
Page 6 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

3. Faire la somme des premiers éléments de chaque ligne d'un tableau à deux
dimensions
 Le seul paramètre de complexité est la longueur de tab[0].

1.5.

Lorsque, pour une valeur donnée du paramètre de complexité, le temps d'exécution varie
selon les données d'entrée, on peut distinguer :

 La complexité au pire : temps d'exécution maximum, dans le cas le plus défavorable.


 La complexité au mieux : temps d'exécution minimum, dans le cas le plus favorable
(en pratique, cette complexité n'est pas très utile).
 La complexité moyenne : temps d'exécution dans un cas médian, ou moyenne des
temps d'exécution.
Le plus souvent, on utilise la complexité au pire, car on veut borner le temps d'exécution.

Exemple

fonction recherche (chaine [] tab, chaine x) : booléen


Entier i;
Début
i <- 0;
Tant que (i < n) faire
Si (tab[i] = x) alors
Recherche = VRAI;
i <- i+1 ;
Fin si
Fin tant que
Recherche= FAUX;
Fin

 Si x est dans la première case du tableau : 1 tour de boucle avec la condition tab[i]=x
vraie
 Si x est dans la deuxième case du tableau : 1 tour de boucle avec la condition tab[i]=x
fausse et 1 tour de boucle avec la condition tab[i]=x vraie
 Si x est dans dernière case du tableau : n-1 tours de boucle avec la condition tab[i]=x
fausse et 1 tour de boucle avec la condition tab[i]=x vraie
 Si x n'est pas dans le tableau : n tours de boucle avec la condition tab[i]=x fausse

Page 7 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

1.6.

Un algorithme peut être divisé en plusieurs séquences. Chacune des séquences représentant
une suite d’instructions reflète une étape de l’algorithme. Dans un algorithme on distingue
plusieurs types d’instructions:
 Instructions élémentaires,
 Structures conditionnelles
 Structures itératives
Soient :
: le temps théorique de l’exécution d’un algorithme A.
: le temps théorique de l’exécution de iième séquence de l’algorithme A.

1.6.1. Evaluation des séquences élémentaires

Le temps d’exécution d’une séquence composée d’une suite d’instructions élémentaires égale
à la somme des coûts

1.6.2. Evaluation d’une structure conditionnelle


En algorithmique il y a 2 types de structure conditionnelle, le « Si » et le Sélectionneur «
selon ».

a) Structure conditionnelle « Si-Alors- Sinon »

b) Structure conditionnelle « Selon »

Page 8 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

L’instruction « selon » permet d'exécuter l'une des séquences selon le cas su Expression.

Temps d’exécution de choix selon


 { }

1.6.3. Evaluation d’une structure Itérative

a) La boucle « tant que »


Elle permet de répéter l'exécution d'une séquence de la boucle.

Condition : est une expression booléenne (condition élémentaire ou composée) dite aussi
condition de continuité.

Temps d’exécution de tant que

 ( )

Où n est la taille des données sur lesquelles sera exécutée la boucle. Le temps T(n) est au
moins égale à T (condition) car la condition est au moins évaluée une fois.

b) La boucle « pour »
Elle permet de répéter l'exécution d'une action de la boucle dont le nombre de répétition est
connu à priori.

( )

Cpt est le compteur de boucle, de Binf et Bsup sont les bornes inferieures et supérieures (l’ordre
des valeurs peut être croissant ou décroissant).
1. Binf et Bsup sont d'abord évaluées,
2. Cpt prend la valeur Binf.
3. Si alors l’action est exécutée, puis Cpt est incrémenté de 1, et on
recommence depuis (3).
La boucle « tant que », qui permet de choisir dynamiquement si l’on continue à répéter le
corps de la boucle ou si l’on s’arrête est un outil plus puissant que la boucle « pour ». En fait,
la boucle « pour » est un cas particulier de la boucle « tant que ».

Page 9 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Temps d’exécution de tant que

 (  ) ( )

c) La boucle « répéter …jusqu’ »


Elle permet comme tant que de répéter l’exécution d’une action au moins une fois.

1.7. Notation de Landau O(.)

Les calculs à effectuer pour évaluer le temps d'exécution d'un algorithme peuvent parfois être
longs ; On aura donc recours à une approximation de ce temps de calcul, représentée par la
notation O(.) ;
Exemple
Soit un algorithme effectuant opérations ;
1. On remplace les constantes multiplicatives par 1 :
2. On annule les constantes additives :
3. On garde le terme de plus haut degré :
4. et on a donc .

1.8.

 : complexité constante, pas d'augmentation du temps d'exécution quand le paramètre


croit
 : complexité linéaire, augmentation linéaire du temps d'exécution quand le
paramètre croit (si le paramètre double, le temps double).
Exemple : algorithmes qui parcourent séquentiellement des structures linéaires.
 : complexité logarithmique, augmentation très faible du temps d'exécution
quand le paramètre croit.
 : complexité quasi-linéaire, augmentation un peu supérieure à .
 : complexité quadratique, quand le paramètre double, le temps d'exécution est
multiplié par 4.
 : complexité polynomiale, quand le paramètre double, le temps d'exécution est
multiplié par .

Page 10 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

 : complexité exponentielle, quand le paramètre double, le temps d'exécution est


élevé à la puissance 2.
 : complexité factorielle, asymptotiquement équivalente à

Fig. 7.1. Classe de complexité

1.9.

L’objectif de la complexité consiste à mesurer les performances asymptotiques d’un


algorithme dans le pire des cas

1. Borne supérieur asymptotique


On ne considère que des fonctions de N vers IR+.
Définition
Une fonction est une borne supérieure asymptotique pour si et seulement si :

On note

Ou n0 est un seuil et C permet d’ignorer le comportement des fonctions pour les données de
petites tailles. La constante C, appelée facteur, permet de faire abstraction de vitesse de la
machine utilisée.

Page 11 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Exemple
Montrez que

On à :

Donc

2. Borne inférieur asymptotique


Définition
Une fonction est une borne inférieur asymptotique pour , si et seulement si :

On note
Exemple

Montez que

Posons , alors

Remarque
 ( )

Exemple

Montrez que
Il suffit de montrer que

pour tout

Page 12 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

3. Borne asymptotique

Définition

Une fonction est une borne asymptotique pour , si et seulement si :

On note : .
Exemple
Montrez que

Page 13 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

1. On considère les algorithmes suivants. Quelle est la complexité de ces algorithmes.

b) Cpt=1;
a) pour i = 5 à n-5 faire
tq (n>2)
pour j = i-5 à i+5 faire
n=n div 2;
3 x += 3
Cpt=Cpt+ 1;
fin tq

c) i = 1;
Tq (i<=n) d) Pour (j=1 à n) faire
Pour (j=1 à i) faire i = 1;
Ecrire (Salut); Tq (i<=j)
Fin pour Ecrire(‘Salut’)
i = 2*i; i = 2*i;
Fin Tq Fin Tq
Fin pour

e) pour i = 1 à n - 1 faire f) Tant que (n>2) faire


pour j = i + 1 à n faire √
pour k = 1 à j faire fin tq
opération en O(1) ; fin pour
fin pour
fin pour
fin pour

2. Montrez que:
a)
b)
c) ( – )
d)

3. Un tableau Tab est trié par ordre croissant si pour tout i

a- Elaborer un algorithme récursif permettant de vérifier qu’un tableau X est trié ou non
b- Estimer sa complexité.

Page 14 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

5.1.

Un arbre est une structure composée de nœuds et de feuilles (nœuds terminaux) reliés par des
branches. On le représente généralement en mettant la racine en haut et les feuilles en bas.

5.2.

Quelques exemples donnent un aperçu de l’étendue de leur utilisation:

1. Le livre, organisé en chapitres, sections, paragraphes


2. La représentation d’une expression arithmétique pour l’évaluer et la dériver
3. Les arbres généalogiques
4. Explorateur de Windows
5. Les systèmes de gestion de bases de données
6. Arbre d’appel des fonctions
7. Compression de données (Code de Huffman)

5.3.

On utilise classiquement la terminologie suivante pour décrire les arbres :

 La racine de l'arbre est l'unique nœud qui n'a pas de père. Dans l’exemple, la racine de
l’arbre c’est A
 Un nœud interne possède au moins un fils. Dans l’exemple, les nœuds internes sont : B,
C, D et G
 Une feuille de l'arbre est un nœud qui n'a pas de fils. Dans l’exemple, les feuilles sont :
E, I, K et H
 Un sous-arbre d'un nœud A est un arbre dont la racine est un fils de A.
 La Branche est un chemin qui relie une feuille à la racine. Dans l’exemple, les branches
sont : ABE, ABF ACGI ACGK et ADH
 La profondeur d’un nœud est son nombre d’ancêtres. Dans l’exemple, le nœud G est de
profondeur 2.
 Le niveau situe les nœuds de même profondeur. On dit que le niveau de la racine est 0,
les fils ont le niveau 1, les fils des fils ont le niveau 2….
Page 15 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

 La hauteur d’un arbre est la distance entre la racine et la feuille la plus lointaine. L’arbre
de l’exemple est de hauteur 3
 Degré d’un nœud est le degré d’un nœud est le nombre de fils associé à ce nœud. Dans
l’exemple le degré de G est 2.
 La taille d’un arbre est le nombre total des nœuds.

Hauteur
A Racine

B C D Nœud interne

E F G H Niveau 2

Feuille (Nœudexterne)
Branche
I K

Sous arbre

Fig.6.1. Forme générale d’un arbre

5.4.

Il existe plusieurs types d’arbres, les principaux sont les suivants :

5.4.1. Arbre binaire : c’est un arbre dont chaque nœud n’accepte pas plus de deux nœuds, un
nœud fils à droite et un fils à gauche (à part les feuilles). Plusieurs variantes des arbres
binaires dont les principales :

 Arbre binaire localement complet (parfait incomplet)


 Arbre binaire complet (parfait)
 Arbre partiellement ordonné
 Le Tas
 Arbre binaire de recherche (arbre non équilibré)
 Arbre AVL (arbre binaire équilibré)
Page 16 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

5.4.2. Arbre n-aires : c’est un arbre dont chaque nœud peut accepter de 0 à n nœuds.
Plusieurs variantes des arbres binaires dont les principales :
 B-Arbre
 B-Arbre*
 B-Arbre+

5.5.

Les arbres binaires sont un cas particulier d’arbres. Ce sont des arbres ou chaque nœud
possède au plus un fils gauche et au plus un fils droite. Même si un nœud possède un seul fils,
il peut être un fils gauche ou un fils droit. Il existe plusieurs variantes d’arbres binaires :

A) Arbre binaire localement complet (parfait incomplet)

Un arbre binaire localement complet est un arbre binaire dont chaque nœud interne a deux
fils.

Dans un arbre binaire localement complet :

 Nombre de feuilles = nombre de nœuds internes +1

B) Arbre binaire complet (parfait)

On appelle arbre binaire complet tout arbre qui est localement complet et dont toutes les
feuilles ont la même profondeur.

Dans un arbre binaire localement complet :

1. le nombre de nœuds total en fonction de la hauteur h égale à


2. Le nombre de nœuds internes égale à
3. Le nombre de feuilles égale à

Page 17 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

C) Arbre partiellement ordonné

C'est un arbre étiqueté dont les valeurs des nœuds appartiennent à un ensemble muni d'une
relation d'ordre total (les nombres entiers, réels etc... en sont des exemples) tel que pour un
nœud donné tous ses fils ont une valeur supérieure ou égale à celle de leur père.
Nous remarquons que la racine d'un tel arbre est toujours l'élément de l'ensemble possédant la
valeur minimum (le plus petit élément de l'ensemble), car la valeur de ce nœud par
construction est inférieure à celle de ses fils et par transitivité de la relation d'ordre à celles de
ses descendants c'est le minimum.

D) Le Tas

On appelle tas un tableau représentant un arbre parfait partiellement ordonné. L'intérêt


d'utiliser un arbre parfait complet ou incomplet réside dans le fait que le tableau est toujours
compacté, les cellules vides s'il y en a se situent à la fin du tableau. Le fait d'être partiellement
ordonné sur les valeurs permet d'avoir immédiatement un extremum à la racine.

5.5.1.

Parcourir un arbre signifie visiter dans un certain ordre tous ses nœuds. Nous distinguerons
deux types de parcours : le parcours en profondeur et le parcours en largeur. Le parcours en
profondeur permet d'explorer l'arbre en explorant jusqu'au bout une branche pour passer à la
suivante. Le parcours en largeur permet d'explorer l'arbre niveau par niveau. C'est à dire que
l'on va parcourir tous les nœuds du niveau 1 puis ceux du niveau deux et ainsi de suite jusqu'à
l'exploration de tous les nœuds.

A) Parcours en profondeur

Les parcours en profondeur les plus classiques sont les parcours Infixé, préfixé et postfixé.

1. Le parcours préfixe (Préordre) visite dans l’ordre la Racine, le sous arbre Gauche et le
sous arbre Droite (RGD).
2. Le parcours infixe (inordre) visite dans l’ordre le sous arbre Gauche, la Racine et le
sous arbre Droit (GRD).

Page 18 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

3. Le parcours postfixe (postorder) visite dans l’ordre le sous arbre Gauche, le sous arbre
droit et la racine (GDR).

Exemple
A

B F

C E G H

I J

 Le parcours de l’arbre préfixé donne la liste : A.B.C.I.J.E.F.G.H


 Le parcours de l’arbre infixé donne la liste : I.C.J.B.E.A.G.F.H
 Le parcours de l’arbre en postfixé donne la liste : I.J.C.E.B.G.H.F.A

B) Parcours en largeur ( ou par niveau )

Nous allons aborder un type de parcours un peu plus compliqué, c'est le parcours en largeur. Il
s'agit d'un parcours dans lequel, on traite les nœuds un par un sur un même niveau. On passe
ensuite sur le niveau suivant, et ainsi de suite.
Le parcours en largeur de l'arbre suivant est : A.B.F.C.E.G.H.I.J

B F
C H
E G
I J

2.6.2.

Un nœud est une structure (ou un enregistrement) qui contient au minimum trois champs: un
champ contenant les données du nœud. Cette information peut être un entier, une chaîne de
caractère ou tout autre chose que l'on désire stocker. Les deux autres champs sont le fils
gauche et le fils droit du nœud.

Page 19 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

A)

En C/C++

Typedef struct Nœud


{
Type élément Val ;
Struct Nœud FG;
Struct Nœud *FD;
} Arbre;

B)

parcours Infixé parcours Préfixé


void Infixé (Arbre *A) void Préfixé (Arbre *A)
{ {
if (A !=NULL) if (A !=NULL)
{ {
Cout<< A->val; Préfixé (A->FG) ;
Infixé (A->FG) ; Cout<< A->val;
Infixé (A->FD) ; Préfixé (A->FD) ;
} }
} }

parcours Postfixé
void Préfixé (Arbre *A)
{
if (A !=NULL)
{
Postfixé (A->FG) ;
Postfixé (A->FD) ;
Cout<< A->val;
}
}

C)

1. Nombre total des nœuds


Le calcul du nombre total des nœuds est très simple. On définit le calcul en utilisant la
définition récursive :
 Si l'arbre est vide : renvoyer 0
 Sinon renvoyer 1 plus la somme du nombre de nœuds des sous arbres gauche et droit.

Page 20 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Nombre total des nœuds En C/C++


int NbrNoeud (Arbre *A)
{
if (A==NULL)return 0;
else return (1+n NbrNoeud (A->FG)+ NbrNoeud (A->FD));
}

2. Nombre de feuilles
Le calcul du nombre de feuille repose sur la définition récursive :

 Un arbre vide n'a pas de feuille.


 Un arbre non vide, son nombre de feuille défini de la façon suivante :
4. Si le nœud est une feuille alors on renvoie 1 :(A->FG==NULL) && (A->FD==NULL)
5. Si c'est un nœud interne alors le nombre de feuille est la somme du nombre de feuille
de chacun de ses fils.

Nombre de Feuilles En C/C++


int NbreFeuilles (Arbre *A)
{
if (a==NULL)return 0;
else
if ((A->FG==NULL)&&(A->FD==NULL))return 1;
else
return ( NbreFeuilles ( A->FG )+ NbreFeuilles ( A->FD));
}

3. Nombre de nœuds interne


La définition récursive est la suivante :
 Un arbre vide n'a pas de nœud interne.
 Si le nœud en cours n'a pas de fils alors renvoyer 0
 Si le nœud a au moins un fils, renvoyer 1 plus la somme des nœuds interne des sous
arbres.

Nombre de nœuds interne En C/C++


int NbreNoeudInt (Arbre *A)
{
if (A==NULL)return 0;
else
if ((A->FG==NULL)&&(A->FD==NULL))return 0;
else
return ( 1+ NbreNoeudInt ( A->FG )+ NbreNoeudInt ( A->FD));
}

Page 21 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

4. Recherche d’un élément dans un arbre

Recherche d’un arbre En C/C++


int Recherche (Arbre *A, int x)
{
if (A==NULL)return 0;
else
if (A->val==x) return 1;
else
return ( 1+ NbreNoeudInt ( A->FG )+ NbreNoeudInt ( A->FD))
}

5. Egalité de deux arbres

Egalité de deux Arbres En C/C++


int Eagle(Arbre *A, Arbre *B)
{
if(( A==NULL) && (B==NULL))return 1;
else
if ((A==NULL) ||(B==NULL)) return 0;
else
return((A->val==B->val) && Egale(A->FG,B->FG) && Egale(A->FD,B->FD))
}

6. Calcule de la hauteur d’un arbre

Pour calculer la hauteur d'un arbre, nous allons nous baser sur la définition récursive :
 un arbre vide est de hauteur 0
 un arbre non vide a pour hauteur 1 + la hauteur maximale entre ses fils.

De part cette définition, nous pouvons en déduire un algorithme en pseudo code :

Hauteur d’un En C/C++


int Hauteur (Arbre *A)
{
int h1,h2;
if (A==NULL) h1=h2=-1;
else
{
h1=1+Hauteur (A->FG);
h2=1+Hauteur (A->FD);
}
if (h1>h2) return(h1);
else return(h2);
}

Page 22 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

7. Hauteur d’un arbre: 2èmeSolution

Hauteur d’un En C/C++


int Hauteur (Arbre *A)
{
if (A==NULL) 0;
else
return (1 + max (Hauteur (A->FG), Hauteur (A->FD));
}

8. Parcours en largueur (Niveau)

Hauteur d’un En C/C++


void ParcoursLargeur (Arbre *A)
{
Arbre ptr;
File F ;
InitFile(F) ;
Enfiler (F, A) ;
While( ! FileVide(F))
{
ptr =défiler(F);
cout<<ptr->val;
if (! FileVide (ptr->FG)) Enfiler (F, ptr->FG);
if( ! FileVide (ptr->FD)) Enfiler (F, ptr->FD);
}
}

5.6.

Les arbres binaires de recherche sont utilisés pour accélérer les opérations de recherche,
insertion et suppression de valeurs.
Un arbre binaire de racine R est dit de recherche si seulement si :
 Toutes les valeurs du sous-arbre gauche de R sont inférieures à val (R)
 Toutes les valeurs du sous-arbre droit de R sont supérieures à val (R)
 Le sous-arbre gauche de R doit être un arbre de recherche binaire
 Le sous-arbre droit de R doit être un arbre de recherche binaire

Page 23 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Exemple

Fig.6.2. Arbre binaire de recherche

5.6.1.

A) Recherche d’un élément

Principe : le principe de la recherche d’un élément est comme suit:

Commencer à la racine
 Si la valeur de ce nœud est l’élément recherché, stop
 Si la valeur du nœud courant est plus grande que la valeur recherchée, alors
continué la recherche dans la partie gauche de l’arbre.
 Si la valeur du nœud courant est plus petite que la valeur recherchée, alors
continué la recherche dans la partie droite de l’arbre.
 On poursuit ainsi la recherche jusqu'à trouver la valeur de l’élément ou arriver à
une feuille de l’arbre. Si on tombe sur une feuille et que l’élément n'est pas trouvé,
la valeur fausse est retournée.

Recherche d’un élément dans un ABR


bool Recherche (Arbre * A, int v)
{
if (A!=NULL)
if (A->val>v)
A= A->FG;
else
if A= A->FD;
else return true;
else return false;
}

Page 24 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

B) Ajout d’un élément

Principe : le principe d’ajout d’un élément dans un ABR est comme suit :

 Si la valeur de l’élément que l’on veut ajouter existe, on ne l’ajoute pas.


 Sinon, le dernier nœud visité est nécessairement le parent de celui que l’on veut ajouter.
Il suffit alors de l’ajouter à gauche ou à droite de ce nœud selon le cas.

Ajout d’un élément dans un ABR En C/C++


Arbre *ajout (Arbre *A, int v)
{
Arbre *Ptr,*Temp,*Prec;
Ptr=(Arbre*)malloc(sizeof(Arbre));// En C++ : Ptr= new Arbre ;
Ptr->val=v;
Ptr->FG=0;
Ptr->FD=0;
if (A==NULL) A=Ptr;
else
{
Temp=A;
while (A!=NULL)
{
Prec=Temp;
if (v<Temp->val)
Temp= Temp->FG;
else Temp= Temp->FD;
}
if (v<Prec->val)
Prec->FG=Ptr;
else Prec->FD=Ptr;
}
}

Page 25 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

C) Suppression d’un élément

Principe : la suppression est un peu plus compliquée. On procède de la façon suivante : une
fois l’élément à supprimer est localisé, on se trouve dans une des situations suivantes :

 Le nœud en question a un seul fils : on le supprime et on le remplace par son fils.


 Le nœud en question est une feuille : on le supprime et on le remplace par NULL.
 Le nœud en question a deux fils : on le supprime et on le remplace par son successeur
ou son prédécesseur.

Exemple : suppression des nombres 13 (cas 1), le nombre 16 (cas 2) et de nombre 15 (cas 3)

 Cas 1

Fig.6.3. Suppression de la clé 13 par élimination d'une feuille.

 Cas 2

Fig.6.4. Suppression de la clé 16 par remonté du fils

 Cas3

Fig.6.5. Suppression de la clé 15 par substitution de la clé 14 et suppression de ce nœud.

Page 26 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

5.7.

A) Définition

Les arbres AVL ont été introduits par les finlandais Adelson-Velskii-Landis dans les années
60.En plus d’être un arbre de recherche, pour chaque nœud d’un arbre AVL, la différence des
hauteurs entre le sous-arbre droit et le sous arbre gauche est 0, -1 ou 1.

Exemple:

Fig. 6.7. Un arbre AVL, avec les hauteurs aux nœuds.


B) Facteur d'équilibrage et rotation
Chaque nœud contient un entier appelé facteur d'équilibrage qui permet de déterminer s’il est
nécessaire de rééquilibrer l'arbre. Le facteur d'équilibrage d'un nœud est la différence entre la
hauteur de son sous-arbre droit et celle de son sous-arbre gauche. Lors d'insertion ou
suppression, l'arbre peut se déséquilibrer (valeur 2 ou -2), on utilise alors des rotations pour
rééquilibrer l'arbre.

C) Rotations
Une rotation droite autour du sommet q d'un arbre binaire de recherche consiste à faire
descendre le sommet q et à faire remonter son fils gauche p sans invalider l'ordre des
éléments. L'opération inverse s'appelle rotation gauche autour du sommet p.

Fig.6.8. Rotation gauche et droite.

Page 27 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Remarques

 Pour rééquilibrer un arbre AVL après une insertion, une seule rotation ou double
rotation suffit.
 Pour rééquilibrer un arbre AVL après une suppression, il faut jusqu’au h rotations ou
double rotations (h est la hauteur de l'arbre)

D) Opérations d'insertion et suppression


Les opérations d'insertion et suppression sont celles d'un arbre binaire de recherche dans
lesquelles on ajoute la gestion du facteur d'équilibrage.

Algorithmes de rééquilibrage dans l’opération d’insertion


A chaque nœud de l'arbre, nous ajoutons une information indiquant quel est le sous-arbre le
plus haut :
 0 indique que les deux sous-arbres du nœud ont même hauteur.
 -1 indique que le sous-arbre gauche est plus haut que le sous-arbre droit.
 1 indique que le sous-arbre droit est plus haut que le sous-arbre gauche.
Le nœud sera donc déclaré comme suit:
Supposons que le nœud T était précédemment équilibré:
Lors d'une insertion dans le sous-arbre gauche deux cas se présentent:
1. La hauteur du sous-arbre gauche n'augmente pas : l'arbre était équilibré par hypothèse,
donc il le reste.
2. La hauteur du sous-arbre gauche augmente. Trois cas peuvent se présenter :
 La hauteur du sous-arbre gauche était égale à la hauteur du sous-arbre droit moins un :
l'arbre est alors encore mieux équilibré qu'avant l'insertion.

+1 0
A A

Ag Ad Ag Ad
h-1
h

Page 28 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

 La hauteur du sous-arbre gauche était égale à la hauteur du sous-arbre droit, l'arbre reste
équilibré.
0 -1
A A

Ag Ad Ag Ad

h-1
h

 La hauteur du sous-arbre gauche était égale à la hauteur du sous arbre droit plus 1; après
l'insertion, l'arbre devient déséquilibré.

Etudions les différentes possibilités qui se présentent lorsque l'arbre est déséquilibré.
Supposons qu'avant l'insertion la hauteur du sous-arbre droit soit h -1, la hauteur du sous-
arbre gauche avant l'insertion était égale à h, elle a augmenté lors de l'insertion, et est donc
maintenant de h +1. Soit B le sous-arbre gauche de A. Deux possibilités se présentent :

B penche gauche

Bg

Après insertion
 Devient après rééquilibrage:

Page 29 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

B penche droite

Un au moins des deux arbres Cg ou Cd a une hauteur h +1, l'autre pouvant avoir une hauteur
h, et c'est celui sur lequel se produit le déséquilibre.

 Devient après rééquilibrage:

Opération de Suppression

L'algorithme de suppression est plus compliqué. Il est fondamentalement le même que


l'algorithme de suppression dans un arbre binaire de recherche. Seulement, la suppression
peut entraîner un rééquilibrage, et à la différence de l'algorithme d'adjonction, le rééquilibrage
peut entraîner des rééquilibrages en cascade, ce qui implique de connaître la totalité du
chemin parcouru. Ainsi soit le chemin sera mémorisé dans une pile dans la version itérative
de l'algorithme, soit grâce à la mémorisation de l'état précédant dans la version récursive.

E) Déclaration d’un arbre AVL

En C/C++

Typedef struct Nœud


{
Type élément Val, Facteur-d’équilibrage ;
Struct Nœud FG;
Struct Nœud *FD;
} Arbre;

Rotation Gauche Rotation droite


Arbre RotationGauche (Arbre *A) Arbre * RotationDroite (Arbre *A)
{ {
Arbre *Temp = A->FD; Arbre *Temp = A->FG;
A->FD=Temp->FG; A->FG=Temp->FD;
Temp ->FG = A ; Temp ->FD = A ;
return Temp ; return Temp ;
} }

Page 30 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

2. Construire à la main l’ABR correspondant à la liste des entiers :


20, 15, 5, 3, 10, 8, 59, 27, 33, 25, 71, 55, 52.

- Supprimer dans l’arbre obtenu les nœuds 33 et 5.


- Ecrire deux algorithmes qui permettent de trouver la valeur minimale et la valeur
maximale dans un ABR.

3. Ecrire une fonction C++ qui donne le père d’un nœud donné.

4. Ecrivez un algorithme qui renvoie le deuxième plus petit élément contenu dans un arbre
binaire d’entiers.

5. Spécifier et implanter les méthodes nécessaires pour vérifier qu'un arbre binaire vérifie
effectivement la propriété qui en fait un arbre de recherche.

6. Ecrire une fonction qui teste si un arbre est localement complet.

7. Soit l’arbre binaire de recherche suivant : 25

15 30

6 19 28 32

b) Comment peut-ont représenté cet arbre en utilisant un tableau ? Donner la structure de


donné
c) On veut ajouter les nœuds 3,9, et 1. Créer un deuxième arbre à partir du premier.

d) Ecrire la fonction qui calcule le nombre de fils gauche d’un arbre. (le nombre de fils
gauche dans cet arbre est 3)
8. Ecrire un algorithme permettant de tester si un ABR est ordonné. Un ABR est ordonné si
l’ensemble des fils de chaque nœud est totalement ordonné.

1
Exemple :
2 3

4 5
6 7

8 9

10
0
Page 31 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Introduction
De manière générale, un graphe permet de représenter les connexions d’un ensemble en
exprimant les relations entre ses éléments : réseau de communication, réseau routier,
circuit électronique,…, mais aussi relations sociales ou interactions entre espèces
animales. Le vocabulaire de la théorie des graphes est utilisé dans de nombreux domaines
: chimie, biologie, sciences sociales, etc., mais c’est avant tout une branche à part entière
et déjà ancienne des mathématiques. Néanmoins, l’importance accrue que revêt l’aspect
algorithmique dans ses applications pratiques en fait aussi un domaine incontournable de
l’informatique. Pour schématiser, les mathématiciens s’intéressent avant tout aux
propriétés globales des graphes (graphes Eulériens, graphes Hamiltoniens, arbres,
coloration, dénombrement, . . .) là où les informaticiens vont plutôt chercher à concevoir
des algorithmes efficaces pour résoudre un problème faisant intervenir un graphe
(recherche du plus court chemin, problème du voyageur de commerce, recherche d’un
arbre couvrant, . . .). Tout ceci forme un ensemble très vaste, dont nous n’aborderons que
quelques aspects, essentiellement de nature algorithmique
4.1. Graphes non orientés

Un graphe non orienté G, est la donnée d’un couple (V(G), E(G)) où V(G) est un ensemble
(fini) de sommets et E(G) un ensemble (fini) d’arêtes, chaque arête ayant deux sommets pour
extrémités. Une arête est une boucle si elle relie un sommet à lui-même. On parle de
multigraphe lorsque plusieurs arêtes relient les mêmes paires de sommets. Dans le cas
contraire, on dit que le graphe est simple.

Graphe simple sans boucles Graphe simple ayant deux boucles Multigraphe

Page 32 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

 Un graphe simple correspond ainsi au graphe d’une relation symétrique entre des
objets, représentés par les sommets.
 Deux sommets reliés par une arête sont dits adjacents (on dit également qu’ils sont
voisins).
 Une arête reliant deux sommets est dite incidente à ces deux sommets.
 Le degré d’un sommet est le nombre d’arêtes incidentes à ce sommet, les boucles
comptant pour deux.

degré de A : 4
degré de B : 2
degré de C : 3
degré de D : 3

Tout graphe vérifie la propriété élémentaire suivante :

La somme des degrés des sommets d’un graphe vaut deux fois le nombre de ses arêtes.

Sur l’exemple précédent, on vérifie en effet que 4 + 2 + 3 + 3 = 12 = 2 x 6.


 Un chemin de longueur k est une suite de k+1 sommets u0, …, uk telle que deux
sommets consécutifs sont reliés par une arête. On dit qu’un tel chemin relie le sommet
u0 au sommet uk. Un chemin est simple s’il n’emprunte pas deux fois la même arête, il
est élémentaire s’il ne passe pas deux fois par le même sommet.
 Un cycle est un chemin reliant un sommet à lui-même. Dans le graphe ci-dessus,
DCABCA est un chemin (ni simple, ni élémentaire), ABCD est un chemin (simple et
élémentaire), ABCA est un cycle.
 Un cycle Hamiltonien est un cycle passant une seule fois par tous les
sommets d’un graphe.
 Un cycle Eulérien est un cycle passant une seule fois par toutes les arêtes
d’un graphe. Également, ce cycle a comme particularité que tous ses sommets
doivent être de degrés pairs. Dans le cas contraire, le cycle n’est pas eulérien.
 La distance entre deux sommets u et v est la longueur d’un plus court chemin reliant u
à v (cette distance est infinie si aucun chemin ne relie ces deux sommets). Le diamètre
d’un graphe est le maximum des distances entre ses sommets. Le graphe précédent a

Page 33 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

ainsi pour diamètre 2 (qui correspond aux distances entre les sommets D et A, ou D et
B).

 Un graphe g = (V', E') est un sous-graphe d'un graphe G si tous les sommets et toutes
les arêtes de g sont aussi des sommets et des arêtes de G :

 Un sous-graphe de G qui contient tous les sommets de G est dit un graphe partiel de
G.

 Un sous graphe induit d’un graphe G est un graphe G’ tel qu’il existe un sous-
ensemble X de V(G) vérifiant G’ = G[X].

Graphe G Un sous graphe Un sous graphe induit de G


partiel de G (par X = {A, B, C})
 Un graphe est
connexe si toute paire de sommets est reliée par un chemin. Un graphe est donc
connexe si et seulement si son diamètre est fini. Une composante connexe d’un graphe
est un sous-graphe induit connexe maximal.

4.2. Graphes orientés


Un graphe orienté G, est la donnée d’un couple (V(G), A(G)) où V(G) est un ensemble (fini)
de sommets et A(G) un ensemble (fini) d’arcs, chaque arc ayant un sommet pour extrémité
initiale et un sommet pour extrémité finale. Un arc est une boucle s’il a le même sommet pour
extrémités.

Page 34 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Un graphe orienté correspond ainsi au graphe d’une relation non nécessairement symétrique
entre des objets, représentés par les sommets. Deux sommets reliés par un arc sont dits
adjacents (on dit également qu’ils sont voisins). Si deux sommets u et v sont reliés par un arc
(u, v), v est un successeur de u et u est un prédécesseur de v.

Graphe orienté
sans boucles

Le degré sortant d’un sommet est le nombre de successeurs de ce sommet. Le degré entrant
d’un sommet est le nombre de prédécesseurs de ce sommet. Dans l’exemple précédent, le
sommet C a pour degré entrant 1 et pour degré sortant 2.
Tout graphe orienté vérifie la propriété élémentaire suivante:

La somme des degrés sortants des sommets d’un graphe est égale à la somme des degrés
entrants de ces sommets et au nombre d’arcs du graphe.

Sur l’exemple précédent, on vérifie en effet que 1 + 1 + 2 + 0 = 1 + 1 + 1 + 1 = 4.

4.3. Représentation des graphes

4.3.1. Matrices d’adjacence

À tout graphe G, orienté ou non, on peut associer sa matrice d’adjacence M = M(G). Cette
matrice est une matrice carrée dont les éléments, indicés par V(G) × V(G), sont définis par M
[i,j] = 1 s’il existe un arc (ou une arête) allant de i vers j et M [i,j] = 0 sinon. Si le graphe G est
non orienté, la matrice M(G) est symétrique.

Page 35 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Graphe non orienté

Graphe orienté

Une telle matrice se représente aisément au niveau algorithmique par un tableau à deux
dimensions.
Dans le cas d’un graphe non orienté, la matrice étant symétrique, il est plus efficace (en terme
d’espace occupé) de représenter la matrice par un tableau à une seule dimension, en ne
stockant que la partie inférieure de la matrice, ligne par ligne. Pour la matrice M(G) ci-dessus,
on obtiendrait la liste suivante:

Pour un graphe à n sommets, ce tableau n’utilise donc que cases. La fonction


suivante permet d’accéder à l’élément M [i,j] :

fonction accesElement (M : tableau de CMAX entiers, i, j : entiers ) : entier


début
si i > j
alors retourner (M[ i*(i+1)/2 + j + 1 ] )
sinon retourner (M[ j*(j+1)/2 + i + 1 ] )
fin_si
fin

Page 36 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

Propriété
Soit G un graphe, orienté ou non, et M sa matrice d’adjacence. La puissance kième
Mk de la matrice M est telle que l’élément Mk [i,j] correspond au nombre de chemins de
longueur k allant de i vers j.
L’exemple suivant permet de constater cette propriété :

Graphe non orienté Matrice M Matrice M2

Regardons par exemple les chemins de longueur 2 issus du sommet 2 (3ème ligne de la matrice
M2) :
 1 chemin de 2 vers 0 : 210
 1 chemin de 2 vers 1 : 201
 3 chemins de 2 vers 2 : 202, 212 et 232
 aucun chemin de 2 vers 3
 1 chemin de 2 vers 4 : 234

0 → 1, 2
1 → 0, 1, 2
2 → 0, 1, 3
3→ 2

Graphe non orienté Listes d’adjacence

0→1
1→2
2 → 0, 3
3→

Graphe orienté Listes d’adjacence

Page 37 sur 38
Structures de données avancées Université Larbi Tébessi L. Laimeche

4.4.Modélisation de problèmes à l’aide de graphes

De nombreux problèmes peuvent être modélisés à l’aide de la théorie des graphes. Le principe
général est le suivant :
 On modélise le « support » du problème à l’aide d’un graphe (il faut alors choisir les
objets que représentent les sommets et les relations que représentent les arcs ou les
arêtes),
 On reformule le problème en termes de graphes,
 On tente de résoudre le problème en question : on retombe parfois sur un problème
bien connu en théorie des graphes, pour lequel on dispose d’algorithmes de résolution,
et parfois sur un nouveau problème, source possible de nouvelles recherches en
théorie des graphes…
Des domaines d’application courants sont par exemple :
 La théorie des jeux : les sommets représentent les positions de jeux, les arcs les «
coups » faisant passer d’une position à une autre ; le problème consiste généralement à
trouver un (plus court) chemin menant de la position initiale à une position gagnante.
 Les problèmes de réseau routier : le graphe (orienté) modélise le réseau et on cherche
généralement des chemins optimaux selon des critères de coût spécifiques, distance,
temps,(exemple classique : le GPS).
 Les problèmes de réseaux (informatique, électrique, …) : diffusion ou collecte
d’information, résistance aux pannes, optimisation de débit, … etc.

Page 38 sur 38

Vous aimerez peut-être aussi