info-f-203 : algorithmique 2 - université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfchapitre 1...

92
INFO-F-203 : Algorithmique 2 Bernard Fortz 2011-2012

Upload: others

Post on 10-Jul-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

INFO-F-203 : Algorithmique 2

Bernard Fortz

2011-2012

Page 2: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Une grande partie de ce document est le fruit du travail d’Olivier Markowitch, qui m’agénéreusement fourni toutes ses sources. Je l’en remercie énormément, ce partage de res-sources m’ayant permis de me concentrer sur les nouveaux chapitres et quelques modifica-tions et ajouts mineurs au texte.

Bernard Fortz

Page 3: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Table des matières

1 Introduction aux tables de hachage 1

1.1 Introduction aux tables de hachage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.2 Tables à accès direct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.3 Tables de hachage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.1.4 Fonctions de hachage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.1.5 Adressage ouvert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Arbres binaires de recherche équilibrés 10

2.1 Arbres binaires de recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.1.2 Définition et propriétés des arbres binaires de recherche . . . . . . . . . . . . . 10

2.1.3 Recherche dans un arbre binaire de recherche . . . . . . . . . . . . . . . . . . . 12

2.1.4 Insertion et suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.2 Arbres rouges-noirs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.2.1 Propriétés des arbres rouges-noirs . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.2.2 Rotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.2.3 Insertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2.2.4 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3 Les graphes 21

3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.2 Graphes, arcs et arêtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.3 Mise en œuvre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3.4 Accessibilité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.4.1 Roy-Warshall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3.5 Parcours de graphes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

4 Cycles et connexité 37

Page 4: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Table des matières ii4.1 Définitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4.2 Recherche des composantes connexes . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.3 Ponts et points d’articulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

4.4 Détection des cycles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

4.5 Recherche des composantes fortement connexes . . . . . . . . . . . . . . . . . . . . . . 46

5 Le tri topologique 50

5.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

5.2 Implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

5.3 Interprétations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

5.4 Tri topologique inversé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

6 Les arbres sous-tendants minimaux 57

6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

6.2 Algorithme de Prim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

6.3 Algorithme de Kruskal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

7 Les plus courts chemins 69

7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

7.2 Plus courts chemins dans un digraphe . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

7.3 Tous les plus courts chemins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

7.4 Plus courts chemins dans un DAG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

7.5 Digraphes ayant des poids négatifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

7.6 Dernières remarques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

8 Algorithmes génériques sur les graphes 82

8.1 Types d’algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

8.2 Algorithmes gloutons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

8.2.1 Parcours en largeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

8.2.2 Parcours en profondeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

8.2.3 Arbre sous-tendant minimum . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

8.2.4 Plus court chemin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

8.2.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

Page 5: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1

Introduction aux tables de hachage

1.1 Introduction aux tables de hachage

1.1.1 Introduction

De nombreuses applications ont besoin d’un ensemble dynamique qui permet les opérations INSERT,DELETE, SEARCH.

Le problème

Table de symboles S contenant n enregistrements.

Opérations sur S :– INSERT(S ,x)– DELETE(S ,x)– SEARCH(S ,x)Comment organiser la structure de données S ?

1.1.2 Tables à accès direct

Idée

– Supposons que les clés appartiennent à l’ensemble U ⊆ 0, 1, . . . ,m − 1 et qu’elles sont toutesdistinctes.

– Tableau T [0..m− 1] :

T [k] =

x si x ∈ S et key[x] = k,

NULL sinon .

Implémentation

D i r e c t−Address−S ea rc h ( T , k ) r e t u r n T [ k ] ;

D i r e c t−Address− I n s e r t ( T , x ) T [ x . key ] = x ;

Page 6: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 2

FIGURE 1.1 – Implémentation d’un ensemble dynamique par une table à accès direct (source : [1])

D i r e c t−Address−D e l e t e ( T , x ) T [ x . key ] = NULL;

Les opérations prennent O(1).

Problème

L’espace des clés peut être très grand !– Nombres de 64 bits : ' 18× 1018 clés différentes,– chaînes de caractères : encore plus !En pratique, le nombre de clés utilisées est largement inférieur au nombre de clés possibles (plusieursordres de grandeur).

1.1.3 Tables de hachage

Solution

Utiliser une fonction de hachage h pour associer l’espace U des clés à l’ensemble 0, 1, . . . ,m − 1avec m “raisonnable”.

Quand un enregistrement à insérer est envoyé sur un espace déjà utilisé dans T , une collision se produit.

Résolution des collisions par chaînage

Utiliser une liste chaînée pour sauver les enregistrements d’un même emplacement.

Pire cas :

– Tous les enregistrements sont envoyés sur le même emplacement– Temps d’accès : Θ(n) si |S| = n.

Analyse du hachage avec liste chaînées

Page 7: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 3

FIGURE 1.2 – Implémentation d’un ensemble dynamique par une table de hachage (source : [1])

FIGURE 1.3 – Résolution des collisions par chaînage (source : [1])

Page 8: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 4– Hypothèse : hachage uniforme simple : chaque clé k ∈ S a la même probabilité d’être envoyée sur

chaque emplacement de T , indépendamment des autres clés.– Soient

– n le nombre de clés dans la table,– m le nombre d’emplacements.

– Le facteur de charge (load factor) de T est défini par

α =n

m

i.e. le nombre moyen de clés par emplacement.– On suppose que le calcul de h(k) est réalisable en O(1).

Temps moyen pour une recherche

Théorème 1. Dans une table de hachage où les collisions sont résolues par liste chaînée, une rechercheprend en moyenne un temps Θ(1 + α) sous l’hypothèse de hachage uniforme simple.

Démonstration. Pour j = 0, 1, . . . ,m − 1, nous notons nj la longueur de la liste T [j], avec n =n0 + n1 + · · ·+ nm−1. Nous traitons séparément le cas où la recherche échoue et le cas où elle réussit.

Si la recherche échoue, sous l’hypothèse de hachage uniforme simple, chaque clé k qui n’est pas encoredans la table a la même probabilité d’être envoyée par la fonction de hachage dans chacun des m empla-cements. Le temps moyen pour une recherche qui ne trouve pas une clé k est le temps moyen nécessairepour parcourir la liste T [h(k)], qui a une longueur moyenne E[n(hk)] = α. Donc le nombre d’élémentsexaminés en moyenne dans une recherche qui échoue est α, et le temps total, en ajoutant le calcul deh(k), est Θ(1 + α).

Si la recherche réussit, nous supposons que chacun des n éléments de la table a la même probabilitéd’être cherché. Le nombre d’éléments examinés lors d’une recherche (avec succès) d’un élément x estle nombre d’éléments qui se trouvent avant x dans la liste plus 1. Puisque les nouveaux éléments sontplacés en début de liste, tous les éléments avant x dans la liste ont été insérés après x.

Pour calculer le nombre moyen d’éléments examinés, nous prenons l’espérance, sur les n éléments dela table, du nombre moyen d’éléments ajoutés à la liste de x après l’ajout de x, plus 1. Soit xi le i−èmeélément ajouté à la liste , pour i = 1, 2, . . . , n et soit ki = xi.key. Pour les clés ki et kj , nous définissonsla variable aléatoire indicatriceXij = Ih(ki) = h(kj). Sous l’hypothèse de hachage uniforme simple,nos avons Prh(ki) = h(kj) = 1/m et donc E[Xij ] = 1/m.

En conclusion, le nombre moyen d’éléments examinés dans une recherche fructueuse est

Page 9: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 5

E

1

n

n∑i=1

1 +n∑

j=i+1

Xij

=

1

n

n∑i=1

1 +n∑

j=i+1

E[Xij ]

=

1

n

n∑i=1

1 +

n∑j=i+1

1

m

= 1 +

1

nm

n∑i=1

(n− i)

= 1 +1

nm

(n∑

i=1

n−n∑

i=1

i

)

= 1 +1

nm

(n2 − n(n+ 1)

2

)= 1 +

n− 1

2m

= 1 +α

2− α

2n.

Le temps total pour une recherche fructueuse (incluant le calcul de h(k)) est donc Θ(2+α/2−α/2n) =Θ(1 + α).

– Si α = O(1) (ou n = O(m)), alors le temps moyen pour une recherche est O(1).– Insertion et suppression en O(1).

1.1.4 Fonctions de hachage

Choix d’une bonne fonction de hachage

L’hypothèse de hachage uniforme simple est difficile à garantir, d’autant plus qu’on ne connaît généra-lement pas la distribution de probabilités des clés. De plus, l’indépendance de la distribution des clés estrarement garantie.

Idéalement :

– Une bonne fonction de hachage devrait distribuer les clés uniformément dans les emplacements de latable.

– La régularité dans la distribution des clés ne doit pas affecter l’uniformité de la distribution.

Dans la suite, nous supposons que les clés sont des nombres naturels.

La méthode de division

h(k) = k mod m.

Mauvais choix de m

Page 10: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 6– Éviter un m qui a un petit diviseur d, car une prépondérance de clés congruentes modulo d peut

affecter l’uniformité.– Si m = 2r, le hachage ne dépend même pas de tous les bits de k :

k = 1011000111 0110102︸ ︷︷ ︸h(k)

r = 6 h(k) = 0110102

La méthode de division : choix de m

Choisir m premier, pas trop proche d’une puissance de 2 ou 10, et pas trop utilisé dans l’environnementde calcul.

Cette méthode est populaire, pourtant la méthode suivante est en général supérieure.

La méthode de multiplication

Supposons que m = 2r et notre ordinateur utilise des mots de w bits.

h(k) = (Ak mod 2w) rsh (w − r),

où rsh est l’opérateur “bitwise right-shift” (>> en C et java) et A est un entier impair tel que 2w−1 <A < 2w.

– Ne pas prendre A trop proche de 2w−1 ou 2w.– La multiplication modulo 2w est rapide comparativement à la division.– L’opérateur rsh est rapide.

La méthode de multiplication : exemple

h(k) = (Ak mod 2w) rsh (w − r),

Supposons que m = 8 = 23 et que notre machine a des mots de 7 bits.

A 89 101 1001

k 109 110 1101

Ak 9701 1001011 110 0101

Ak mod 2w 101 110︸ ︷︷ ︸r

0101︸ ︷︷ ︸w−r

h(k) 6︷ ︸︸ ︷110

1.1.5 Adressage ouvert

Résolution des collisions par adressage ouvert

– Aucun stockage n’est fait hors de la table de hachage.– L’insertion sonde systématiquement la table jusqu’à trouver un emplacement vide.– La fonction de hachage dépend à la fois de la clé et du numéro du sondage :

h : U × 0, . . . ,m− 1 → 0, . . . ,m− 1.

Page 11: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 7– La séquence de sondage h(k, 0), h(k, 1), . . . , h(k,m−1) devrait être une permutation de 0, 1, . . . ,m−

1 .– La table peut se remplir, et la suppression est difficile.

Implémentation de l’adressage ouvert

Hash− I n s e r t ( T , k ) i = 0 ;do

j = h ( k , i ) ;i f ( T [ j ] == NULL)

T [ j ] = k ;r e t u r n j ;

e l s e

i ++;

w h i l e ( i < m)e r r o r ( " Hash t a b l e o v e r f l o w " )

Hash−S ea rc h ( T , k ) i = 0 ;do

j = h ( k , i ) ;i f ( T [ j ] == k )

r e t u r n j ;i ++;

w h i l e ( ( i < m) and ( T [ j ] != NULL) )r e t u r n NULL;

Stratégies de sondage

Sondage linéaire

Etant donné une fonction de hachage ordinaire h′(k), le sondage linéaire utilise la fonction

h(k, i) = (h′(k) + i) mod m.

Problème majeur : “primary clustering”, de longues séquences d’emplacements occupés se créent, aug-mentant le temps moyen de recherche.

Stratégies de sondage

Double hachage

Étant données deux fonctions de hachage ordinaire h1(k) et h2(k), le double hachage utilise la fonction

h(k, i) = (h1(k) + ih2(k)) mod m.

Page 12: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 8Cette méthode produit généralement d’excellents résultats, mais h2(k) et m doivent être premiers entreeux. Une manière de faire est de prendre pour m une puissance de 2 et de concevoir h2(k) de sortequ’elle ne produise que des nombres impairs.

Analyse de l’adressage ouvert

Nous faisons l’hypothèse de hachage uniforme :

Chaque clé a la même probabilité d’avoir chacune des m! permutations comme séquencede sondage.

Théorème 2. Étant donné une table de hashage à adressage ouvert avec un facteur de charge α = n/m <1, l’espérance du nombre de sondages dans une recherche sans succès est au plus 1/(1−α), en supposantun hachage uniforme.

Démonstration. Dans une recherche infructueuse, chaque sondage sauf le dernier accède à un empla-cement qui ne contient pas la clé désirée, et le dernier emplacement testé est vide. Définissons la va-riable aléatoire X comme le nombre de sondages fait dans une recherche infructueuse, et soit Ai, pouri = 1, 2, . . . , l’événement que le i-ème sondage ait lieu, et que ce sondage tombe sur un emplacementoccupé.

L’événement X ≥ i est l’intersection d’événements A1 ∩A2 ∩ · · · ∩Ai−1.

PrX ≥ i = PrA1 ∩A2 ∩ · · · ∩Ai−1= PrA1 · PrA2|A1 · PrA3|A1 ∩A2 · · ·PrAi−1|A1 ∩A2 ∩ · · · ∩Ai−2

Puisqu’il y a n éléments et m emplacements, PrA1 = n/m. Pour j > 1, la probabilité qu’il y aitun j-ème sondage et sur un emplacement occupé, sachant que les j − 1 premiers sondages étaient desemplacements occupés, est (n−j+1)/(m−j+1). Étant donné que n < m implique (n−j)/(m−j) <n/m pour tout j tel que 0 ≤ j < m, nous avons pour tout i tel que 1 ≤ i ≤ m

PrX ≥ i =n

m· n− 1

m− 1· n− 2

m− 2· · · n− i+ 2

m− i+ 2

≤( nm

)i−1= αi−1.

Nous pouvons maintenant calculer l’espérance du nombre de sondages :

E[X] =∞∑i=1

PrX ≥ i

≤∞∑i=1

αi−1

=∞∑i=0

αi

=1

1− α.

Page 13: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 1 : Introduction aux tables de hachage 9Théorème 3. Insérer un élément dans une table de hashage à adressage ouvert avec un facteur de chargeα demande au plus 1/(1− α) sondages en moyenne.

Démonstration. Un élément est inséré seulement s’il y a de la place dans la table, et donc si α < 1.Insérer un élément requiert une recherche infructueuse suivie par l’insertion de l’élément dans le premieremplacement vide trouvé. Donc, le nombre moyen de sondages est au plus 1/(1− α).

Conséquences des théorèmes

– Si α est constant, accéder à une table de hachage à adressage ouvert prend un temps constant.– Si la table est remplie à moitié, le nombre moyen de sondages est 1/(1− 0.5) = 2.– Si la table est remplie à 90%, le nombre moyen de sondages est 1/(1− 0.9) = 10.

Théorème 4. Étant donné une table de hashage à adressage ouvert avec un facteur de charge α < 1,l’espérance du nombre de sondages dans une recherche avec succès est au plus

1

αln

1

1− α

en supposant un hachage uniforme et que chaque clé de la table a la même probabilité d’être cherchée.

Démonstration. Une recherche pour une clé k reproduit la même séquence de sondages que quandl’élément avec clé k a été inséré. Si la clé k était la i+1-ème clé insérée dans la table, par le Théorème 3,le nombre moyen de sondages dans une recherche de k est au plus 1/(1− i/m) = m/(m− i).

En prenant la moyenne sur les n clés présentes dans la table, nous obtenons le nombre moyen de son-dages pour une recherche avec succès :

1

n

n−1∑i=0

m

m− i=

m

n

n−1∑i=0

1

m− i

=1

α

m∑k=m−n+1

1

k

≤ 1

α

∫ m

m−n

1

xdx

=1

αln

m

m− n

=1

αln

1

1− α.

Conséquences du théorème

– Si la table est remplie à moitié, le nombre moyen de sondages est inférieur à 1.387.– Si la table est remplie à 90%, le nombre moyen de sondages est inférieur à 2.559.

Page 14: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2

Arbres binaires de recherche équilibrés

2.1 Arbres binaires de recherche

2.1.1 Introduction

Arbres de recherche équilibrés

Un arbre de recherche équilibré est une structure de données pour laquelle une hauteur de O(log n) estgaranti pour l’implémentation d’un ensemble dynamique de n éléments.

Exemples

– Arbres AVL– Arbres 2-3– Arbres 2-3-4– Arbres B– Arbres Rouges-Noirs

Opérations

– SEARCH

– MINIMUM

– MAXIMUM

– PREDECESSOR

– SUCCESSOR

– INSERT

– DELETE

La plupart de ces opérations peuvent être implémentées en un temps proportionnel à la hauteur del’arbre.

2.1.2 Définition et propriétés des arbres binaires de recherche

– Arbre binaire qui peut être représenté par une structure de données chaînée où chaque noeud est unobjet.

– En plus d’une clé et de données additionnelles, chaque noeud contient les attributs left, right et p quipointent vers les noeud correspondant respectivement au fils gauche, au fils droit et au parent.

– Si un enfant ou le parent manque, l’attribut est NULL.

Page 15: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 11

6

5

2 5

7

8

2

5

7

6

5

8

(a) (b)

FIGURE 2.1 – Exemples d’arbres binaires de recherche contenant les mêmes clés. (a) est plus efficaceque (b) vu sa hauteur plus petite.

Les clés dans un arbre binaire de recherche sont toujours stockées de manière à satisfaire la propriétésuivante :

Propriété des arbres de recherche binaires

Soit x un noeud d’un arbre binaire de recherche. Si y est un noeud dans le sous-arbre gauche de x, alorsy.key < x.key. Si y est un noeud dans le sous-arbre droit de x, alors y.key ≥ x.key.

Parcours ordonné de l’arbre

I n o r d e r−Tree−Walk ( x ) i f ( x != NULL)

I n o r d e r−Tree−Walk ( x . l e f t ) ;p r i n t x . key ;I n o r d e r−Tree−Walk ( x . r i g h t ) ;

Théorème 5. Si x est la racine d’un a sous-arbre de n noeuds, alors l’appel à Inorder − Tree−Walkprend un temps Θ(n).

Démonstration. Notons par T (n) le temps pris par la fonction Inorder− Tree−Walk quand elle estappelée sur la racine d’un sous-arbre à n noeuds. Puisque la fonction visite tous les noeuds du sous-arbre,nous avons T (n) = Ω(n). Il reste à montrer que T (n) = O(n).

Puisque Inorder − Tree −Walk prend un petit temps constant pour un sous-arbre vide (pour le testx! = NULL), nous avons T (0) = c pour une constante c > 0.

Pour n > 0, supposons que Inorder − Tree −Walk est appelé avec un noeud x dont le sous-arbregauche a k noeuds et le sous-arbre droit n−k−1 noeuds. Le temps nécessaire pour l’appel à Inorder−Tree−Walk(x) est borné par

T (n) ≤ T (k) + T (n− k + 1) + d

où d > 0 est une constante qui représente une borne supérieure sur le temps passé à l’exécution deInorder − Tree−Walk(x) sans les appels récursifs.

Page 16: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 12Nous allons prouver récursivement que T (n) ≤ (c+ d)n+ c. Pour n = 0, nous avons (c+ d) · 0 + c =c = T (0). Pour n > O, supposons que l’hypothèse est vraie pour tout k < n. Alors

T (n) ≤ T (k) + T (n− k + 1) + d

≤ ((c+ d)k + c) + ((c+ d)(n− k − 1) + c) + d

= (c+ d)n+ c− (c+ d) + c+ d

= (c+ d)n+ c,

et donc T (n) = O(n).

2.1.3 Recherche dans un arbre binaire de recherche

Une opération très courante est la recherche d’une clé stockée dans un arbre binaire de recherche.

En plus de l’opération SEARCH, les arbres binaires de recherche permettent également des recherchestelles que MINIMUM, MAXIMUM, PREDECESSOR, SUCCESSOR.

Nous allons maintenant voir comment chacune de ces opérations peut être effectuée en un temps O(h)dans un arbre de hauteur h.

Recherche d’une clé

Etant donné un pointeur vers la racine de l’arbre et une clé k, la fonction Tree − Search renvoie lepointeur vers un noeud avec une clé k si un tel noeud existe ; sinon, elle renvoie NULL.

Tree−S ea rc h ( x , k ) i f ( ( x == Nul l ) o r ( k == x . key ) )

r e t u r n x ;i f ( k < x . key )

r e t u r n Tree−S ea rc h ( x . l e f t , k ) ;e l s e

r e t u r n Tree−S ea rc h ( x . r i g h t , k ) ;

Version itérative

I t e r a t i v e −Tree−S ea rc h ( x , k ) w h i l e ( ( x != NULL) and ( k != x . key ) )

i f ( k < x . key ) x = x . l e f t ;

e l s e

x = x . r i g h t ;

r e t u r n x ;

Page 17: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 13Minimum et maximum

Tree−Minimum ( x , k ) w h i l e ( x . l e f t != NULL)

x = x . l e f t ;r e t u r n x ;

Tree−Maximum ( x , k ) w h i l e ( x . r i g h t != NULL)

x = x . r i g h t ;r e t u r n x ;

Successeur et prédécesseur

Etant donné un noeud dans un arbre binaire de recherche, nous voulons parfois trouver son successeurou prédécesseur dans la liste ordonnée des noeuds.

Le successeur d’un noeud x est le noeud qui a la plus petite clé supérieure à x.key.

Le prédécesseur d’un noeud x est le noeud qui a la plus grande clé inférieure à x.key.

Successeur

Tree−S u c c e s s o r ( x , k ) i f ( x . r i g h t != NULL)

r e t u r n Tree−Minimum ( x . r i g h t ) ;y = x . p ;w h i l e ( ( y != NULL) and ( x == y . r i g h t ) )

x = y ;y = x . p ;

r e t u r n y ;

Prédécesseur

Tree−P r e d e c e s s o r ( x , k ) i f ( x . l e f t != NULL)

r e t u r n Tree−Maximum ( x . l e f t ) ;y = x . p ;w h i l e ( ( y != NULL) and ( x == y . l e f t ) )

x = y ;y = x . p ;

r e t u r n y ;

Page 18: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 14

2.1.4 Insertion et suppression

Insertion

Les opérations d’insertion et de suppression modifient l’ensemble dynamique représenté par un arbrebinaire de recherche. La structure de données doit être modifiée pour refléter ces changements, tout enconservant la propriété fondamentale des arbres binaires de recherche.

La procédure d’insertion d’une valeur v prend comme argument un noeud z avec z.key = v, z.left =NULL et z.right = NULL, et insère ce noeud dans l’arbre en y apportant les modifications néces-saires.

Tree− I n s e r t ( T , z ) y = NULL;x = T . r o o t ;w h i l e ( x != NULL)

y = x ;i f ( z . key < x . key )

x = x . l e f t ;e l s e

x = x . r i g h t ;z . p = y ;i f ( y = NULL)

T . r o o t = z ;e l s e i f ( z . key < y . key )

y . l e f t = z ;e l s e

y . r i g h t = z ;

Suppression

Pour la suppression d’un noeud z, nous considérons 4 cas :– Si z n’a pas d’enfant de gauche, nous remplaçons z par son enfant de droite (qui peut être NULL).– Si z a seulement un enfant, qui est celui de gauche, nous remplaçons z par cet enfant de gauche.– Sinon, z a deux enfants. Nous cherchons y, le successeur de z. y est dans le sous-arbre de droite dez et n’a pas d’enfant de gauche (pourquoi ?). Nous voulons déplacer y de sa position actuelle pourremplacer z.– Si y est le fils de droite de z, nous remplaçons z par y.– Sinon, nous remplaçons d’abord y par son enfant de droite, puis nous remplaçons z par y.

Pour déplacer des sous-arbres, nous définissons une procédure Transplant qui remplace le sous-arbreenraciné en u par le sous-arbre enraciné en v. Le parent de u devient le parent de v, et v devient l’enfantapproprié du parent de u.

T r a n s p l a n t ( T , u , v ) i f ( u . p == NULL)

T . r o o t = v ;e l s e i f ( u == u . p . l e f t )

Page 19: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 15u . p . l e f t = v ;

e l s eu . p . r i g h t = v ;

i f ( v != NULL)v . p = u . p ;

Tree−D e l e t e ( T , z ) i f ( z . l e f t == NULL)

T r a n s p l a n t ( T , z , z . r i g h t ) ;e l s e i f ( z . r i g h t == NULL)

T r a n s p l a n t ( T , z , z . l e f t ) ;e l s e

y = Tree−Minimum ( z . r i g h t ) ;i f ( y . p != z )

T r a n s p l a n t ( T , y , y . r i g h t ) ;y . r i g h t = z . r i g h t ;y . r i g h t . p = y ;

T r a n s p l a n t ( T , z , y ) ;y . l e f t = z . l e f t ;y . l e f t . p = y ;

Page 20: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 16

7

3

- -

18

10

8

- -

11

- -

22

- 26

- -

FIGURE 2.2 – Exemple d’arbre rouge-noir

2.2 Arbres rouges-noirs

Les arbres rouges-noirs fournissent (parmi d’autres) une manière de garantir un arbre binaire de re-cherche équilibré où toutes les opérations de base sur les ensembles dynamiques prennent un tempsO(log n) dans le pire des cas.

Cette structure de données utilise un champ d’un bit supplémentaire pour chaque noeud : sa couleur.

2.2.1 Propriétés des arbres rouges-noirs

Un arbre rouge-noir satisfait les propriétés suivantes :

1. Chaque noeud est soit rouge, soit noir.

2. La racine et les feuilles (T.null) sont noires.

3. Si un noeud est rouge, son parent est noir.

4. Tous les chemins simples d’un noeud x à un descendant qui est une feuille ont le même nombrede noeuds noirs (bh(x) - hauteur noire de x).

Hauteur d’un arbre rouge-noir

Théorème 6. Un arbre rouge-noir avec n noeuds internes a une hauteur d’au plus 2 log(n+ 1).

Démonstration. Nous commençons par montrer que le sous-arbre enraciné à tout noeud x contient aumoins 2bh(x) − 1 noeuds internes. Nous le prouvons en procédant par récurrence sur la hauteur de x. Sila hauteur de x est 0, x est une feuille, et le sous-arbre enraciné en x contient au moins 2bh(x) − 1 =20 − 1 = 0 noeuds internes. Considérons maintenant un noeud x avec une hauteur strictement positivequi est une noeud interne avec 2 enfants. Chaque enfant a une hauteur noire de bh(x) ou bh(x)−1 selonque sa couleur est rouge ou noire. Puisque la hauteur de chaque enfant est plus petite que la hauteur dex, nous pouvons appliquer l’hypothèse de récurrence pour conclure que chaque enfant est racine d’unsous arbre avec au moins 2bh(x)−1 − 1 noeuds internes. Donc, le sous-arbre enraciné en x contient aumoins (2bh(x)−1 − 1) + (2bh(x)−1 − 1) + 1 = 2bh(x) − 1 noeuds internes.

Soit h la hauteur de l’arbre. Par la propriété 3 des arbres rouges-noirs, au moins la moitié des noeuds surun chemin simple de la racine à une feuille, sans tenir compte de la racine, sont noirs. La hauteur noire

Page 21: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 17

FIGURE 2.3 – Les opérations de rotations sur un arbre binaire de recherche (source : [1])

de la racine est donc au moins égale à h/2. On peut en déduire que

n ≥ 2h/2 − 1.

Dès lors, log(n+ 1) ≥ h/2, i.e. h ≤ 2 log(n+ 1).

Corollaire 7. Les opérations SEARCH, MINIMUM, MAXIMUM, PREDECESSOR et SUCCESSOR prennentau plus un temps O(log n) sur un arbre rouge-noir.

2.2.2 Rotations

Opérations qui modifient l’arbre

– Les opérations d’insertion et de suppression modifient l’arbre.– Tree−Insert et Tree−Delete ne garantissent pas que les propriétés des arbres rouges-noirs restent

valides après leur application.– Il faut donc appliquer :

– des changements de couleurs ;– une restructuration de la structure de pointeur via des rotations.

Rotations

– Les rotations conservent l’ordre des clés :

a ∈ α, b ∈ β, c ∈ γ ⇒ a ≤ A ≤ b ≤ B ≤ c.

– Une rotation peut être effectuée en un temps O(1).

Le f t−R o t a t e ( T , x ) y = x . r i g h t ;x . r i g h t = y . l e f t ;i f ( y . l e f t != T . n u l l )

y . l e f t . p = x ;y . p = x . p ;i f ( x . p == T . n u l l )

T . r o o t = y ;e l s e i f ( x == x . p . l e f t )

Page 22: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 18x . p . l e f t = y ;

e l s ex . p . r i g h t = y ;

y . l e f t = x ;x . p = y ;

Le code de Right−Rotate est laissé en exercice.

2.2.3 Insertion

Idée

– Insérer x dans l’arbre.– Colorier x en rouge.– Seule la propriété 3 peut être violée.– Faire monter la violation dans l’arbre par re-coloration jusqu’au moment où la violation peut être

réparée par rotations et re-coloration.

RB− I n s e r t ( T , z ) y = T . n u l l ; x = T . r o o t ;w h i l e ( x != T . n u l l )

y = x ;i f ( z . key < x . key )

x = x . l e f te l s e x = x . r i g h t ;

z . p = y ;i f ( y == T . n u l l )

T . r o o t = z ;e l s e i f ( z . key < y / key )

y . l e f t = ze l s e y . r i g h t = z ;z . l e f t = T . n u l l ; z . r i g h t = T . n u l l ;z . c o l o r = RED;RB−I n s e r t −Fixup ( T , z ) ;

RB−I n s e r t −Fixup ( T , z ) w h i l e ( z . p . c o l o r == RED) / / Cas 1

i f ( z . p == z . p . p . l e f t ) y = z . p . p . r i g h ti f ( y . c o l o r == RED)

z . p . c o l o r = BLACK; y . c o l o r = BLACK;z . p . p . c o l o r = RED;z = z . p . p ;

e l s e

i f ( z == z . p . r i g h t ) / / Cas 2z = z . p ; Le f t−R o t a t e ( T , z ) ;

Page 23: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 19z . p . c o l o r = BLACK; / / Cas 3z . p . p . c o l o r = RED;Right−R o t a t e ( T , z . p . p ) ;

e l s e ( comme c i−d e s s u s en

e c h a n g e a n t ‘ ‘ r i g h t ’ ’ e t ‘ ‘ l e f t ’ ’ )T . r o o t . c o l o r = BLACK;

Analyse

– Le cas 1 est le seul qui peut être répété, au plus O(log n) fois.– Les cas 2 et 3 sont exécutés au plus une fois, et font une rotation chacun au plus.– Le temps total de RB-Insert est donc au maximum O(log n).

2.2.4 Suppression

Adaptation de Transplant :

RB−T r a n s p l a n t ( T , u , v ) i f ( u . p == T .NULL)

T . r o o t = v ;e l s e i f ( u == u . p . l e f t )

u . p . l e f t = v ;e l s e

u . p . r i g h t = v ;v . p = u . p ;

RB−Tree−D e l e t e ( T , z ) y = z ; y−o r i g i n a l −c o l o r = y . c o l o r ;i f ( z . l e f t == T .NULL)

x = z . r i g h t ; RB−T r a n s p l a n t ( T , z , z . r i g h t ) ;e l s e i f ( z . r i g h t == T .NULL)

x = z . l e f t ; RB−T r a n s p l a n t ( T , z , z . l e f t ) ;e l s e

y = Tree−Minimum ( z . r i g h t ) ;y−o r i g i n a l −c o l o r = y . c o l o r ;x = y . r i g h t ;i f ( y . p == z )

x . p = y ;e l s e

RB−T r a n s p l a n t ( T , y , y . r i g h t ) ;y . r i g h t = z . r i g h t ; y . r i g h t . p = y ;

RB−T r a n s p l a n t ( T , z , y ) ;

Page 24: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 2 : Arbres binaires de recherche équilibrés 20y . l e f t = z . l e f t ; y . l e f t . p = y ; y . c o l o r =z . c o l o r

i f ( y−o r i g i n a l −c o l o r == BLACK)

RB−Dele t e−Fixup ( T , x ) ;

RB−Dele t e−Fixup ( T , x ) w h i l e ( ( x != T . r o o t ) and ( x . c o l o r == BLACK) )

i f ( x == x . p . l e f t ) w = x . p . r i g h t ;i f (w. c o l o r == RED) / / Cas 1

w. c o l o r = BLACK;x . p . c o l o r = RED;Lef t−R o t a t e ( T , x . p ) ;w = x . p . r i g h t ;

i f ( (w. l e f t . c o l o r == BLACK)

and (w. r i g h t . c o l o r == BLACK) ) w. c o l o r = RED; / / Cas 2x = x . p ;

e l s e i f (w. r i g h t . c o l o r == BLACK)

w. l e f t . c o l o r = BLACK; / / Cas 3w. c o l o r = RED;Right−R o t a t e ( T ,w ) ;w = x . p . r i g h t ;

w. c o l o r = x . p . c o l o r ; / / Cas 4x . p . c o l o r = BLACK;w. r i g h t . c o l o r = BLACK;Lef t−R o t a t e ( T , x . p ) ;x = T . r o o t ;

e l s e ( comme c i−d e s s u s en

e c h a n g e a n t ‘ ‘ r i g h t ’ ’ e t ‘ ‘ l e f t ’ ’ )x . c o l o r = BLACK;

Page 25: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3

Les graphes

3.1 Introduction

Informellement, un graphe se définit comme une structure composée de sommets et soit d’arcs, soitd’arêtes. Nous pouvons, pour donner de l’intuition concernant ce concept, considérer que les sommetsreprésentent des objets et les arcs ou arêtes représentent les relations entre ces objets. Un exemple degraphe est :

Un arc est une relation dirigée entre deux sommets, il s’agit donc d’une relation non symétrique :

Une arête est une relation non dirigée entre deux sommets, il s’agit ainsi d’une relation symétrique :

Nous pouvons ainsi considérer qu’une arête entre deux sommets est comparable à avoir deux arcs de

Page 26: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 22sens opposés entre ces deux sommets. Cela nous donne par exemple :

Usuellement, un graphe est composé soit uniquement d’arcs, soit uniquement d’arêtes.

Les graphes représentent un outil fort pratique permettant de modéliser de nombreux systèmes d’infor-mations. Les listes, tableaux, arbres . . . peuvent être vus comme des cas particuliers de graphes. Nouspouvons donc voir la notion de graphe comme une structure abstraite d’information (ADT).

Formellement un graphe est défini comme une structure formée de deux ensembles :– un ensemble S de sommets (a, b, c, d, par exemple) ;– un ensemble A de couples de sommets ((a, b), (b, c), (c, b), (d, d), par exemple).

Si l’ordre dans lequel un couple de sommets est exprimé importe on parle alors d’arcs et on considèreque la relation est dirigée depuis le premier sommet du couple vers le second sommet du couple. Legraphe résultant est alors dit être dirigé ou orienté. Si l’ordre dans lequel les sommets sont exprimésn’importe pas, on parle alors d’arête et on considère que la relation est non dirigée (dans ce cas (a, b)est équivalent à (b, a)). Le graphe résultant est lui appelé graphe non dirigé.

En outre, les arcs ou les arêtes peuvent posséder une étiquette symbolisant un poids, une valeur, unepondération, etc. Cette étiquette peut être définie à l’aide d’une information additionnelle associée àchaque couple de sommets de l’ensemble A.

Voyons à présent quelques définitions en relation avec les graphes :

– l’ordre d’un graphe est le nombre de sommets qu’il contient ;– un prédécesseur ou père d’un sommet i est un sommet j tel qu’il existe un arc ou une arête du sommetj vers le sommet i ;

– un successeur ou fils 1 d’un sommet i est un sommet j tel qu’il existe un arc ou une arête du sommeti vers le sommet j ;

– deux sommets i et j qui sont des fils d’un même sommet k, sont dits frères ;– le degré entrant d’un sommet est le nombre de ses prédécesseurs ;

1. Remarquons que dans le cas d’un graphe non dirigé, deux sommets reliés par une arête sont chacun père et fils l’un del’autre.

Page 27: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 23– le degré sortant d’un sommet est le nombre de ses successeurs ;– deux sommets d’un graphe sont adjacents s’ils sont distincts et s’il existe un arc ou une arête entre les

deux sommets ;– un sommet d’un graphe est isolé s’il n’est adjacent à aucun autre sommet ;– deux arcs ou arêtes sont adjacents s’ils sont distincts et ont au moins une extrémité commune ;– lorsque le graphe est tel qu’au plus m arcs ou arêtes vont d’un sommet à un autre sommet, alors le

graphe est aussi appelé un m-graphe ;– une chaîne est une succession non vide d’arêtes contiguës ;– un chemin est une succession orientée et non vide d’arcs contigus 2 ;– la longueur d’un chemin ou d’une chaîne est égale au nombre d’arcs ou d’arêtes qui le composent ;– un chemin où n’apparaît pas deux fois le même arc est appelé un chemin simple ;– un chemin qui ne passe pas plus d’une fois par chacun de ses sommets est appelé un chemin élémentaire ;– un cycle, dans un graphe non dirigé, est une chaîne d’un sommet a jusqu’à ce même sommet a qui ne

contient pas deux fois le même sommet (autre que a) :– un cycle dans un graphe dirigé, appelé aussi un circuit, est un chemin d’un sommet a jusqu’à ce même

sommet a qui ne contient pas deux fois le même sommet (autre que a) ;– un chemin d’un sommet a jusqu’à ce même sommet a où chaque arc du graphe n’apparaît qu’une

seule fois est appelé un cycle Eulerien ;– un circuit qui comprend tous les sommets du graphe est appelé un cycle Hamiltonien ;– un graphe qui ne contient aucun chemin qui part et arrive à un même sommet est appelé un graphe

acyclique ;– un graphe non dirigé qui contient une arête entre chaque paire de sommets est appelé un graphe

complet.

3.2 Graphes, arcs et arêtes

Il peut être utile de se rendre compte du nombre de graphes différents que l’on peut construire à partird’un nombre fixé de sommets. Pour évaluer cela, nous allons déterminer le nombre maximum d’arcs etd’arêtes différents que l’on peut placer dans un graphe de n sommets.

Le nombre maximum d’arêtes que peut contenir un graphe non dirigé de n sommets est n(n+1)2 . En effet,

un graphe non dirigé, ne contenant qu’un seul sommet, contient au plus une seule arête (de l’uniquesommet vers lui-même). De même, un graphe de i sommets, contient au maximum le même nombred’arêtes qu’un graphe de i − 1 sommets auquel s’ajoute une arête entre le ime sommet et chacun desi − 1 autres sommets, ainsi que l’arête du ime sommet vers lui-même. Ainsi, si on note Ci le nombremaximum d’arêtes dans un graphe de i sommets, alors

Ci = Ci−1 + (i− 1) + 1 = Ci−1 + i

ce qui revient à écrire :

Ci =i∑

j=1

j =i(i+ 1)

2

Le nombre maximum d’arcs d’un graphe dirigé de n sommets est n2. En effet, un graphe dirigé den sommets contient un arc aller et un arc retour correspondant à chaque arête du graphe non dirigééquivalent, à l’exception des arcs d’un sommet vers lui-même qui n’apparaissent qu’une seule fois. Noussavons qu’un graphe non dirigé de n sommets possède au plus n(n+1)

2 arêtes. Nous devons retrancher de

2. Dans la littérature, il arrive qu’une chaîne soit appelée un chemin (ou path en anglais) et un chemin composé d’arcs estalors appelé chemin dirigé (ou directed path en anglais).

Page 28: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 24ce nombre les n arêtes qui vont d’un sommet vers lui-même, doubler le résultat (puisqu’il y aura dansle graphe dirigé équivalent un arc aller et retour pour chaque arête), et rajouter les n arcs qui vont d’unsommet vers lui-même. Cela donne :

2 ·(n(n+ 1)

2− n

)+ n = n(n+ 1)− 2n+ n = n2

A partir de cela, sachant qu’un graphe dirigé ou non contient au plus m arcs ou arêtes, pour un nombrede sommets fixé, nous savons que nous pouvons construire 2m graphes différents, puisque chaque arcou arête peut être pris ou non dans un graphe.

Sur base de ce qui précède, le tableau ci-dessous reprend le nombre de graphes dirigés et non dirigésque l’on peut construire sur base de n sommets.

n nombre de graphes non dirigés nombre de graphes dirigés

2 8 163 64 5124 1024 655365 32768 33554432...

......

i 2i(i+1)

2 2i2

Un graphe qui contient beaucoup moins d’arcs ou d’arêtes que le nombre maximal d’arcs ou d’arêtesqu’il peut contenir est appelé un graphe clairsemé, ou sparse graph. Un graphe qui contient un nombred’arcs ou d’arêtes proche du nombre maximal d’arcs ou d’arêtes qu’il peut contenir est appelé un graphedense, ou dense graph en anglais.

3.3 Mise en œuvre

L’implémentation d’un graphe peut être statique, par exemple sous forme d’une matrice d’adjacenceou d’incidence, ou peut être dynamique, par exemple sous forme d’une liste de prédécesseurs et/ou desuccesseurs.

Une matrice d’adjacence est une matrice carrée n× n, où n est le nombre de sommets du graphe. Cettematrice contient des valeurs booléennes ou des étiquettes. La matrice d’adjacence donne de l’informationconcernant un lien (via un arc ou une arrête) entre deux sommets.

Ainsi pour le graphe sans étiquette :

Page 29: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 25

la matrice d’adjacence M correspondante est, où F=faux et V =vrai :

a b c d

a F V F Fb F F V Fc F V F Fd F F F V

Remarquons que pour un graphe non dirigé, la matrice M est symétrique.

Pour le graphe :

la matrice d’adjacence M devient, où ici par convention nous utilisons la valeur 0 pour représenterl’absence d’arc ou d’arête entre deux sommets :

a b c d

a 0 2 0 0b 0 0 1 0c 0 3 0 0d 0 0 0 2

Une autre implémentation possible est la matrice d’incidence. Cette structure donne de l’information surla relation entre un sommet et un arc ou une arête. L’information se trouvant aux indices i et j indique àla fois si l’arc ou l’arête j pointe vers le sommet i et/ou provient du sommet i.

Pour le graphe sans étiquette précédent, la matrice d’incidence I est telle que ci-dessous, où le premierbooléen du couple présent en coordonnée (i, j) indique si l’arc ou l’arête j provient du sommet i et oùle second booléen de ce couple indique si l’arc ou l’arête j arrive sur le sommet i.

1 2 3 4

a (V, F ) (F, F ) (F, F ) (F, F )b (F, V ) (V, F ) (F, V ) (F, F )c (F, F ) (F, V ) (V, F ) (F, F )d (F, F ) (F, F ) (F, F ) (V, V )

Remarquons qu’une matrice d’incidence pour un graphe non dirigé est telle que chaque couple de boo-léens de la matrice est composé de deux booléens identiques, il est alors plus économique de n’utiliserqu’un seul booléen pour représenter le couple. Aussi, dans le cas d’un graphe dirigé, si le graphe necontient aucun arc allant d’un sommet vers lui-même alors les cellules de la matrice d’incidence peuventcontenir des valeurs ternaires, comme par exemple la valeur 1 pour indiquer que l’arc part du sommet,

Page 30: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 26la valeur -1 pour indiquer que l’arc arrive au sommet et la valeur 0 pour indiquer que l’arc n’est pas liéeau sommet.

Une liste de successeurs peut être représentée par une matrice creuse. Nous pouvons aussi considérerune matrice creuse partielle, par exemple par ligne.

ou

Un graphe dont les arcs ou les arêtes ne portent pas d’étiquette serait alors représenté par un vecteurde pointeurs dont chaque élément représente un sommet de départ d’un arc ou d’une arête et chaqueélément pointé par ce vecteur représente un sommet d’arrivée d’un arc ou d’une arête.

Un graphe portant des étiquettes sur ces arcs ou arêtes pourrait être représenté comme sur la figureB ci-dessus. Nous y avons une première liste verticale doublement liée qui représente l’ensemble dessommets de départs des arcs ou des arêtes. De ces sommets sont pointés, sous forme de liste horizontaleaussi doublement liée, les éléments qui y sont reliés en y indiquant la valeur de l’étiquette (label) présentesur l’arc ou l’arête ainsi que deux pointeurs vers les sommet origine et destination de la relation ainsireprésentée.

La figure ci-dessous reprend la description de ces informations, par manque d’espace nous n’y parlonsque d’arcs, il peut s’agir bien sûr d’arcs ou d’arêtes :

On peut, bien entendu, faire de même pour avoir une liste de prédécesseurs. On peut évidemment ima-giner encore bien d’autres représentations de graphes.

Quelle que soit le type de représentation utilisée, s’il s’avère que les arêtes du graphe contiennent denombreuses informations, nous pouvons remplacer, pour chaque arête, le champs correspondant de lastructure de donnée représentant le graphe par un pointeur vers une zone de mémoire contenant unedescription complète de l’arête. Cela permet de ne jamais devoir manipuler et/ou copier ces informationsdétaillées lorsqu’on construit et lorsqu’on manipule le graphe.

Notons pour finir que la représentation d’un graphe influence l’efficacité des algorithmes le manipulant.Il faut donc choisir la représentation la mieux adaptée aux algorithmes utilisés.

Page 31: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 273.4 Accessibilité

Une autre notion importante est celle d’accessibilité. Il s’agit ici de déterminer quels sommets sontaccessibles depuis un sommet donné.

Pour ce faire, partons de la matrice booléenne d’adjacence M . L’élément Mij de cette matrice d’adja-cence est une valeur booléenne indiquant s’il existe un arc ou une arête allant du sommet i au sommetj.

Nous allons construire une matrice reprenant les informations d’accessibilité. Soit A une telle matriced’accessibilité où Aij indique si le sommet j est accessible à partir du sommet i. Cette matrice répond àla question : existe-t-il un chemin ou une chaîne du sommet i au sommet j :

Pour construire une telle matrice d’accessibilité, partons de notre matrice d’adjacence booléenne M etobservons ce que signifie le carré de la matrice d’adjacence.M2 est telle que pour tout i et j nous avons :

M2ij = (Mi1 andM1j) or . . . or (Min andMnj) =

n∨k=1

Mik ∧Mkj

Si une des expression Mik ∧Mkj est évaluée à vrai alors M2ij est aussi évaluée à vrai. Si M2

ij est vrai,cela signifie que nous observons, au moins une fois, la configuration :

Il existe ainsi un chemin de longueur deux entre le sommet i et le sommet j.

Par récurrence nous écrivons l’expression de M rij , où M r−1

ij est l’information indiquant s’il existe unchemin de longueur r − 1 entre les sommets i et j :

M rij = (Mi1 andM

r−11j ) or . . . or (Min andM r−1

nj )

Si M rij est vrai cela signifie qu’il existe un chemin de longueur r allant du sommet i vers le sommet j

Nous pouvons ainsi définir la matrice d’accessibilité A comme étant la disjonction des puissances suc-cessives de la matrice d’adjacence, où n est le nombre de sommets :

A = M0 ∨M1 ∨M2 ∨ · · · =n−1∨r=0

M r

Page 32: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 28Nous considérons finalement une disjonction de n − 1 composantes car pour un graphe de n sommets,s’il existe un chemin entre deux sommets i et j dans le graphe, alors il existe un chemin entre i et jqui est d’une longueur au plus égale à n− 1.

La matrice d’accessibilité est aussi notée M∗ et est appelée la fermeture transitive. La fermeture transi-tive peut être vue comme le graphe résultant de l’adjonction d’un arc entre deux sommets s’il existe unchemin entre ces deux sommets dans le graphe original.

Ainsi, le graphe :

a comme matrice d’adjacence M :

a b c

a 0 1 0b 0 0 1c 0 1 0

Pour chaque couple de sommets de ce graphe, il existe un chemin d’une longueur inférieure ou égale àdeux (puisque le graphe compte trois sommets), nous avons :

M2 =

a b c

a 0 0 1b 0 1 0c 0 0 1

indiquant qu’il existe un chemin de longueur deux du sommet a au sommet c, du sommet b au sommetb et du sommet c au sommet c. La matrice d’accessibilité, ou fermeture transitive, est alors :

A = M∗ = M0 ∨M1 ∨M2 =

a b c

a 1 1 1b 0 1 1c 0 1 1

où la première ligne indique qu’il existe un chemin du sommet a au sommet a, du sommet a au sommetb et du sommet a au sommet c, la seconde ligne indique qu’il existe un chemin du sommet b au sommetb et du sommet b au sommet c, enfin la troisième ligne indique qu’il existe un chemin du sommet c ausommet b et du sommet c au sommet c.

3.4.1 Roy-Warshall

L’algorithme de Roy-Warshall permet de construire la matrice d’accessibilité d’un graphe (à laquelle ilfaudrait encore rajouter M0 pour être complet). L’algorithme 3.1 présente cette méthode.

Page 33: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 29Algorithme 3.1 Algorithme de Roy-Warshall

A = matrice d’adjacence du graphe

for(k=0 ; k < ordre du graphe ; ++k)for(i=0 ; i < ordre du graphe ; ++i)

if(A[i][k])for(j=0 ; j < ordre du graphe ; ++j)

A[i][j]=A[i][j] or A[k][j]

Dans cet algorithme, quand k=0, donc au premier tour de la boucle extérieure, nous itérons i de 0 à n-1et on vérifie pour chaque i si A[i][0] est vrai, c’est à dire que nous vérifions qu’il existe un arc dusommet i au sommet 0. Si c’est le cas, on itère j de 0 jusqu’à n-1 en calculant A[i][j]=A[i][j]or A[k][j] (avec k=0). On essaye donc de chercher un chemin de longueur 2 entre les sommets iet j passant par le sommet 0, si un chemin de longueur 1 n’existe pas encore.

Puis lorsque k=1, on cherche un chemin de longueur 2 ou 3 pour rejoindre le sommet j depuis lesommet i. On a un chemin de longueur 2 si on ne passe pas par le sommet 0 mais bien par le sommet1 ; et on a un chemin de longueur 3 si on passe à la fois par le sommet 0 et par le sommet 1. Puis pourk=2, on cherche un chemin de longueur 2, 3 ou 4 pour aller de i à j. Le chemin de longueur 2 ne passeni par les sommets 0 et 1, mais bien par le sommet 2 ; le chemin de longueur 3 passe par le sommet 0ou par le sommet 1, puis par le sommet 2 ; et le chemin de longueur 4 passe par les sommets 0, 1 et 2. . .

La complexité maximale de l’algorithme de Roy-Warshall s’exprime en O(n3) contrairement à A =∨n−1r=0 M

r qui est en O(n4) puisque, pour chaque valeur de r considérée, l’évaluation de M r consisteen la multiplication de deux matrices 3, à savoir M et M r−1, et cette multiplication matricielle se fait enO(n3).

3.5 Parcours de graphes

Nous allons à présent examiner différentes manières, en termes d’ordre sur les sommets, pour parcourirun graphe. Pour ce faire, nous allons nous appuyer sur le graphe d’exemple suivant :

3. Comme Mij représente un booléen, la multiplication peut être vue comme un « et logique » (conjonction) et l’additionpeut être vue comme un « ou logique » (disjonction).

Page 34: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 30

Il existe, entre autres, deux manières tout à fait classiques pour parcourir un graphe, à savoir le parcoursen profondeur et le parcours en largeur. Ces parcours sont aussi respectivement appelés depth-first etbreadth-first.

Le parcours en profondeur découvre les sommets du graphe en essayant toujours de descendre, en sui-vant les arcs ou les arêtes, le plus profondément dans le graphe. Sur base de notre graphe d’exempleci-dessus, un parcours en profondeur explore les sommets du graphe dans l’ordre suivant :

1, 2, 4, 5, 9, 6, 7, 8, 10, 3

Nous pouvons noter que l’on revient chaque fois au dernier sommet pour lequel il reste encore dessuccesseurs à visiter.

Le parcours en largeur explore les sommets du graphe par niveau, en découvrant d’abord les sommets àune distance 1, en terme du nombre d’arcs ou d’arêtes, du sommet de départ, puis les sommets à distance2, etc. Toujours sur base du graphe d’exemple, un parcours en largeur peut se faire dans l’ordre suivant :

1, 2, 3, 4, 7, 5, 6, 8, 10, 9

L’ordre précis d’exploration dépend cependant aussi de l’ordre dans lequel on considère les fils d’unsommet (cela peut dépendre de l’implémentation choisie).

Page 35: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 31Au cours de ces parcours, à tout moment nous pouvons classifier les sommets du graphe en trois en-sembles :

1. l’ensemble des sommets déjà traités (que l’on ne traite qu’une seule fois pour éviter les cycles) ;

2. l’ensemble des sommets frontaliers (on les a vus, en tant que sommets successeurs de sommetsdéjà traités, mais il ne sont pas encore traités), appelés aussi la frange ;

3. l’ensemble des sommets encore inconnus.

Ces méthodes de parcours de graphes diffèrent dans la manière dont elles déterminent quel sommet doitpasser de l’ensemble des éléments frontaliers à celui des éléments traités.

A chaque itération du processus nous sélectionnons un élément de la frange pour être traité et un certainnombre, n, d’éléments inconnus entrent dans la frange :

Ainsi, la manière de choisir les éléments de la frange qui seront traités détermine l’algorithme. Le par-cours en profondeur sélectionne le sommet frontalier que l’on a rencontré en dernier au cours du par-cours. Par contre, le parcours en largeur sélectionne les sommets frontaliers que l’on a rencontré dansl’ordre dans lequel on les a rencontrés.

Puisque pour un parcours en profondeur nous devons accéder d’abord aux éléments rencontrés le plusrécemment, l’usage d’une pile (explicite ou implicite) pour sauvegarder les sommets déjà rencontrésnous sera d’une grande utilité. De la même façon, pour un parcours en largeur, comme nous devonsaccéder aux éléments dans l’ordre dans lequel on les a rencontrés, l’usage d’une file (ou queue) s’imposepour sauvegarder les sommets rencontrés.

Sur base de cela, nous pouvons écrire récursivement un parcours en profondeur tel que présenté parl’algorithme 3.2. Par souci de concision nous ne parlerons que d’arcs par la suite. Les algorithmes deparcours considérés fonctionnent de la même manière si on manipule des graphes non dirigés.

Au cours de l’exécution de cet algorithme nous traitons un à un les sommets, en partant d’un premiersommet indiqué comme paramètre. Pour éviter de traiter deux fois un même sommet, nous « marquons »

Page 36: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 32les sommets traités (au moyen d’une information booléenne par exemple). L’algorithme présenté sup-pose qu’initialement tous les sommets sont démarqués (la marque est initialisée à la valeur booléennefaux, par exemple). L’algorithme, ainsi que les algorithmes suivants, supposent aussi que le graphe estreprésenté d’une manière telle qu’à partir de chaque sommet nous pouvons accéder successivement àchaque arc dont ce sommet est l’origine, en utilisant les fonctions 1er_arc, puis arc_suivant. Demême, nous accédons au sommet se trouvant à l’extrémité d’un arc en utilisant la fonction extremite.

Pour chaque sommet traité, nous parcourons récursivement le graphe à partir de chacun de ses fils.

Pour ce faire, nous examinons un à un les fils du sommet courant traité, éventuellement nous réalisonsun traitement lié à l’arc ou à l’arête reliant le sommet traité et le fils considéré. Puis, si le fils n’a pasencore été traité, nous continuons, récursivement, le parcours à partir de ce fils.

Lors du retour de l’appel récursif qui a réalisé le parcours à partir d’un fils, nous considérons l’éventuelfils suivant, que l’on peut donc aussi considérer comme étant le frère du sommet à partir duquel on vientde réaliser un parcours. Un parcours sera à nouveau réalisé à partir de ce frère si ce dernier n’a pasencore été traité, et n’est donc pas marqué. Et on continue ainsi pour tous les sommets du graphe.

Algorithme 3.2 Parcours en profondeur récursif

void DF(sommet s)

traiter smarquer sa=s->1er_arcwhile(a existe)

traiter aif(a->extremite n’est pas marquée)

DF(a->extremite)a=a->arc_suivant

Il est bien sûr possible d’écrire une version itérative du parcours en profondeur, tel qu’illustré par l’al-gorithme 3.3. L’algorithme présenté suppose qu’initialement tous les sommets sont démarqués.

Cet algorithme utilise une pile d’arcs (ou de pointeurs vers des arcs). La structure de données considéréepour représenter le graphe est telle que, pour un sommet, on accède à ses différents sommets fils enpassant directement d’un arc entre le sommet père et le sommet fils aux arcs suivants reliant le sommetpère et les autres sommets fils. Nous utilisons, pour réaliser cela, la fonction arc_suivant.

L’algorithme parcourt un à un les différents sommets du graphe en sauvegardant dans une pile un accèsvers chaque sommet frère du sommet en cours de traitement lors du parcours. Puis l’algorithme passe àun des fils du sommet en cours de traitement ; sommet fils qui devient le nouveau sommet en cours detraitement. Lorsqu’un sommet sans fils non traité est rencontré, cela signifie que nous sommes « descen-dus » le plus en profondeur dans le graphe, il faut continuer le parcours en remontant au dernier sommetrencontré ayant un frère non encore traité. Pour ce faire on extrait le sommet qui se trouve au sommetde la pile et on recommence le processus à partir de ce nouveau sommet.

Plus précisément, l’algorithme démarre depuis un premier sommet s donné comme paramètre. On exé-cute alors une boucle dont le corps réalise les traitements suivants tant que le sommet s considéré n’estpas déjà marqué :

Page 37: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 33– on marque ce sommet s pour l’indiquer comme étant traité ;– on accède à son premier fils, appelons-le s’, et on traite, si nécessaire, l’information liée à l’arc a

ayant mené à ce fils ;– on assigne à la variable a l’arc suivant, à savoir l’arc partant du sommet s et menant à un autre fils des, donc un frère de s’ ;

– on sauve ce nouvel arc a, s’il existe, sur la pile ;– on sauve s’ dans s ;

Lorsque la boucle précédente se termine, car un sommet s déjà traité est rencontré :

– on extrait l’arc se trouvant au sommet de la pile ;– on traite l’information qui lui est associé ;– on sauve dans s le sommet qui est à l’extrémité de cet arc ;– on sauve dans a l’arc suivant menant au frère suivant ;– on sauve ce nouvel arc a, s’il existe, sur la pile ;

Tout cela est réalisé tant que tous les sommets n’ont pas été marqués ou tant que la pile n’est pas vidéede tous les arcs qui y ont été sauvés.

Algorithme 3.3 Parcours en profondeur itératif

void DF(sommet s)

do

while(s n’est pas marqué)

traiter smarquer sa=s->1er_arcif(a existe)

traiter as=a->extremitea=a->arc_suivantif(a existe) push(a)

if(stack n’est pas vide)

a=pop()traiter as=a->extremitea=a->arc_suivantif(a existe) push(a)

while(s n’est pas marqué or stack n’est pas vide)

Le parcours en largeur, dont l’algorithme 3.4 propose une implémentation, nécessite l’usage d’une file

Page 38: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 34de sommets (ou de pointeurs vers des sommets). L’algorithme présenté suppose qu’initialement tous lessommets sont démarqués.

L’algorithme parcourt un à un tous les sommets du graphe en sauvant dans une file tous les fils dusommet en cours de traitement lors du parcours. Puis l’algorithme passe au plus ancien sommet sauvédans la file, sommet fils qui devient le nouveau sommet en cours de traitement. Ce traitement est réalisétant que la file n’est pas vidée.

Plus précisément, l’algorithme démarre à partir d’un premier sommet s indiqué comme paramètre, traiteet marque ce sommet s et le sauvegarde dans la file. Puis une boucle est réalisée au cours de laquelletant que la file n’est pas vidée on réalise les opérations suivantes :

– on retire le plus ancien élément encore dans la file et on le sauve dans s ;– on accède au premier arc a qui émane de s ;– tant qu’il y a des arcs sortants de s, on réalise les opérations suivantes :

– on traite l’information associée à l’arc a ;– on sauve dans s le sommet qui est à l’extrémité de l’arc a ;– si ce nouveau sommet s n’a pas encore été traité, on le traite, on le marque et on le sauve dans la

file ;– on passe à l’arc suivant donnant accès au frère de s et on sauve ce nouvel arc dans a.

Algorithme 3.4 Parcours en largeur

void BF(sommet s)

traiter smarquer senqueue(s)while(queue n’est pas vide)

s=dequeue()a=s->1er_arcwhile(a existe)

traiter as=a->extremiteif(s n’est pas marqué)

traiter smarquer senqueue(s)

a=a->arc_suivant

Il est important de se rendre compte que ces algorithmes de parcours peuvent être écrits de multiplesfaçons. Par exemple, nous pouvons considérer le parcours en largeur illustré par l’algorithme 3.5 où unvecteur val est utilisé pour gérer le marquage. Cet algorithme fait, bien entendu, usage d’une file (unefile d’entiers dans ce cas) et suit le même canevas que le parcours présenté par l’algorithme 3.4.

Page 39: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 35Les deux types d’algorithmes de parcours, en profondeur et en largeur, passent en revue, lors du parcours,tous les sommets et tous les arcs. Ainsi la complexité maximale de ces algorithmes s’exprime enO(|S|+|A|), où S et A représentent respectivement l’ensemble des sommets et des arcs ou arêtes et où |S| et|A| dénotent la taille de ces ensembles.

Algorithme 3.5 Parcours en largeur au moyen d’un vecteur

void BF()

n=0val=(0,...,0)enqueue(1)while(queue n’est pas vide)

++nk=dequeue()val[k]=nt=1er successeur du sommet kwhile(t existe)

if(val[t] == 0)

enqueue(t)--val[t]

t=successeur suivant de t

Il est en pratique tout à fait possible qu’un graphe possède plusieurs sommets origine. On dit alors qu’ilest formé de plusieurs composantes. Comme par exemple :

Lors d’un parcours il faut alors parcourir chacune de ces composantes. Pour ce faire, il est nécessaired’envisager une boucle générale qui lance les parcours considérés ci-dessus pour chaque sommet originede chaque composante formant le graphe.

Une façon de faire, basée uniquement sur la recherche de sommets non marqués au sein du graphe aprèschaque parcours partiel, est présentée par les algorithmes 3.6 et 3.7, réalisant respectivement un parcoursen profondeur et en largeur.

Page 40: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 3 : Les graphes 36Algorithme 3.6 Parcours en profondeur généralisé

void DepthFirst(graphe g)

démarquer gn=ordre de gfor(s=1 ; s <= n ; ++s)

if(sommet s n’est pas marqué)DF(s)

Algorithme 3.7 Parcours en largeur généralisé

void BreadthFirst(graphe g)

démarquer gn=ordre de gfor(s=1 ; s <= n ; ++s)

if(sommet s n’est pas marqué)BF(s)

Page 41: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4

Cycles et connexité

4.1 Définitions

Nous savons à présent qu’un graphe peut être composé d’arcs ou d’arêtes Si un graphe est composéd’arcs, nous le disons dirigé ou orienté. Un tel graphe dirigé porte aussi le nom de digraph pour directedgraph. Nous nous permettrons d’utiliser le terme digraphe en français. Un digraphe qui ne présente pasde cycle est dit être un graphe dirigé acyclique ou directed acyclic graph, ou encore DAG.

Les définitions suivantes nous seront utiles par la suite :

– un sommet s2 est atteignable depuis un sommet s1 s’il existe un chemin ou une chaîne de s1 à s2 ;– deux sommets s1 et s2 sont dits fortement connexes si s1 est atteignable depuis s2 et si s2 est attei-

gnable depuis s1 ;– un graphe non dirigé dans lequel il existe un chaîne entre chaque paire de sommets est appelé un

graphe connecté ;– un digraphe est fortement connexe si toutes les paires de sommets du graphe sont fortement connexes 1 ;– un graphe est dit connexe si un chemin ou une chaîne existe entre chaque paire non ordonnée de

sommets du graphe ;– dans un graphe non dirigé composé de différents sous-graphes non connectés, ces différents sous-

graphes sont appelés des composantes connexes ;– un digraphe qui n’est pas fortement connexe comprend :

– un ensemble de composantes fortement connexes qui sont les plus grands sous-graphes fortementconnexes,

– et un ensemble d’arcs qui vont d’une composante à une autre.

Considérons le digraphe :

1. Plus simplement, nous pouvons aussi dire qu’un digraphe contenant un chemin depuis chaque sommet vers tous lesautres sommets est un graphe fortement connexe.

Page 42: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 38Ce digraphe est formé de deux composantes fortement connexes dont les sommets sont

1, 2, 6, 7

et3, 4, 5

Sur base de ces définitions, il est intéressant de remarquer que :

1. aucun graphe dirigé acyclique, ou DAG, de plus d’un sommet n’est fortement connexe ;

2. chaque sommet d’un DAG est une composante fortement connexe ;

3. si s1, s2 et s3 sont des sommets d’un graphe, la relation « deux sommets du graphe sont fortementconnexes » est transitive : si s1 et s2 sont fortement connexes et si s2 et s3 sont fortement connexesalors s1 et s3 sont fortement connexes ;

4. les composantes fortement connexes d’un digraphe sont connectées par des arcs qui vont d’unsommet d’une composante vers un sommet d’une autre composante, sans qu’il y ait de chemininverse.

4.2 Recherche des composantes connexes

Les parcours de graphes étudiés au chapitre précédent permettent de trouver les composantes connexesd’un graphe non dirigé. En effet, les algorithmes de parcours de graphes peuvent profiter du parcoursd’une composante pour afficher, par exemple, les informations relatives aux sommets parcourus.

Considérons un graphe non dirigé tel qu’illustré ci-dessous :

Nous pouvons supposer que ce graphe est représenté par une liste de successeurs telle que :

L’algorithme 4.1 découvre les différentes composantes connexes sur un tel graphe, en le parcourant enprofondeur.

Page 43: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 39L’algorithme visite ainsi un à un tous les sommets accessibles. La fonction explore passe en revuetous les sommets d’une composantes et la fonction parcours cherche un sommet d’une composantenon encore rencontrée, et lance dans ce cas, via un appel à la fonction explore, le parcours de cettenouvelle composante.

Dans cet algorithme, val est un vecteur d’entiers, adj est un vecteur de pointeurs et id est un entierpréalablement initialisé à zéro. Le vecteur val nous permet de détecter si un sommet a déjà été visitédurant le parcours, et si oui, nous indique dans quel ordre. Le vecteur inval contient les sommets d’unemême composante connexe énumérés les uns à côté des autres.

Algorithme 4.1 Parcours recherchant les composantes connexes

void parcours()

for(int k=0 ; k < ordre du graphe ; ++k)val[k]=0

for(int k=0 ; k < ordre du graphe ; ++k)if(val[k] == 0)

explore(k)

void explore(int k)++idval[k]=idinval[id-1]=kfor(sommet *t=adj[k] ; t != null ; t=t->suivant)if(val[t->sommet] == 0)explore(t->sommet)

Comme pour les algorithmes de parcours de graphes vus au chapitre précédent, cet algorithme passe enrevue tous les sommets et toutes les arêtes du graphe considéré. La complexité maximale de l’algorithmes’exprime donc en O(|S|+ |A|).

Sur notre exemple ci-dessus, l’algorithme produit les valeurs suivantes :

Dans cet algorithme, si la valeur de k est retenue avant l’appel à explore dans la fonction parcours,on possède alors les indices délimitant des différentes composantes dans inval. Une autre façon defaire consisterait à mettre, dans inval, le premier sommet d’une composante sous une forme particu-lière (échanger le numéro du sommet par son opposé, par exemple).

Pour terminer, remarquons que l’algorithme présenté peut aussi être utilisé sur un digraphe pour y dé-tecter les composantes connexes (qui seraient les sous-graphes connexes du digraphe considéré), enchoisissant judicieusement le premier sommet de chaque composante.

Page 44: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 404.3 Ponts et points d’articulation

Les ponts et points d’articulation sont des notions utiles dans le cadre de l’étude de la connexité desgraphes, en nous permettant d’introduire les concepts de biconnexité et k-connexité, ainsi qu’en appor-tant les techniques nécessaires à la détection de composantes fortement connexes.

Le problème sous-jacent qui nous intéresse consiste à nous assurer qu’un graphe est tel que deux som-mets du graphe qui sont atteignables l’un depuis l’autre, restent mutuellement atteignables si une chaîneexistante entre eux est coupée (en supprimant un sommet comme nous l’étudierons ici, ou une arête).

Un pont, ou bridge, dans un graphe non dirigé est une arête qui, si elle était retirée, séparerait un grapheconnecté en deux graphes non connectés 2.

Un point d’articulation est un sommet d’un graphe non dirigé qui, si on l’enlève, sépare le grapheconnecté en des graphes disjoints 3.

Un graphe non dirigé de plus de deux sommets est dit 2-connexe ou biconnexe s’il existe deux cheminsdistincts composés de sommets tous distincts reliant chaque couple de sommets. Un graphe non dirigéde plus de deux sommets sans point d’articulation est donc biconnexe.

Nous pouvons généraliser le concept de biconnexité : un graphe non dirigé est k-connexe s’il existe aumoins k chemins disjoints connectant chaque paire de sommets dans le graphe.

Nous appelons ensemble d’arêtes de retour, ou feedback edge set, le plus petit ensemble d’arêtes d’ungraphe non dirigé connecté qui, si on supprime ces arêtes, transforment le graphe initial en un grapheconnecté acyclique 4.

De même, nous appelons ensemble de sommets de retour, ou feedback vertex set, le plus petit ensemblede sommets d’un graphe non dirigé connecté qui, si on supprime ces sommets, transforment le grapheinitial en un graphe connecté acyclique.

Le graphe non dirigé repris ci-dessous ne représente pas un graphe biconnexe ; en effet, il n’y a pas deuxchemins composés de sommets tous distincts entre, par exemple, le sommet 1 et le sommet 10 :

2. Ainsi un graphe non dirigé qui ne possède par de pont reste connecté si une arête est retirée.3. Un graphe non dirigé qui ne possède pas de point d’articulation reste connecté si un sommet est retiré.4. Cet ensemble n’est pas nécessairement unique.

Page 45: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 41

Cependant ce graphe est formé de deux composantes biconnexes dont les sommets sont :

1, 2, 3, 4, 5

et2, 8, 9, 10

Nous remarquons ainsi qu’un même sommet peut appartenir à plusieurs composantes biconnexes, commepar exemple le sommet 2 dans l’exemple ci-dessus.

Les points d’articulation de ce graphe d’exemple sont 2, 6 et 8, car si on supprime l’un de ces sommetsnous scindons le graphe initial en deux graphes disjoints.

Ce graphe peut aussi être présenté tel que ci-dessous, où transparaît l’ordre d’un parcours en profondeurdu graphe. Les arêtes de retour y sont représentées par des pointillés.

Page 46: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 42

Nous remarquons ainsi qu’un sommet x n’est pas un point d’articulation s’il n’a pas de successeur ousi chacun de ses successeurs y admet un descendant qui a une arête de retour vers un ancêtre de x dansl’arborescence représentant l’ordre de parcours en profondeur du graphe. Ce lien peut être vu comme un« lien de secours », un deuxième chemin, entre x et y.

La racine du graphe est traité comme un cas particulier : la racine est un point d’articulation si elle a plusd’un successeur dans l’arborescence représentant l’ordre de parcours en profondeur du graphe (car elleest alors située sur le seul chemin entre ses deux, ou plus, successeurs).

Modifions à présent l’algorithme de parcours d’un graphe représenté par une liste de successeurs demanière à afficher les points d’articulation. Pour ce faire, considérons l’algorithme 4.2.

La liste de successeurs est représentée par le vecteur de pointeurs adj ainsi que par les éléments deslistes dont les deux champs sont sommet, qui donne le numéro du sommet, et suivant, qui pointe versl’élément suivant de la liste. Le vecteur val, complètement initialisé à 0, retient pour chaque sommet,utilisé comme indice du vecteur, son numéro d’ordre lors du parcours en profondeur du graphe.

L’algorithme 4.2 détermine le « plus haut » sommet dans l’arborescence que l’on peut atteindre depuischaque descendant du sommet k. On teste ainsi, pour chaque sommet k, si le sommet le plus « élevé »,ayant le numéro d’ordre le plus petit, accessible depuis un successeur du sommet k est situé plus hautque ce sommet k dans l’arborescence. Un sommet s est situé plus haut que le sommet k si le numérod’ordre du sommet s, à savoir val[s], est plus petit que le numéro d’ordre, val[k], du sommet k.

Page 47: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 43Algorithme 4.2 Détection des points d’articulation

int explore(int k)

int min

++idval[k]=idmin=idfor(t=1er adjacent de k ; t existe ; t=adjacent suivant)

if(val[t->sommet] == 0)

m=explore(t->sommet)if(m < min)

min=mif(m >= val[k])

cout << kelse

if(val[t->sommet] < min)min=val[t->sommet]

return(min)

Dans cet algorithme, au cours de chaque instance de la fonction explore paramétrée par la variablek, la variable min contiendra la valeur du sommet « le plus haut » accessible depuis les successeurs dusommet k.

Cette variable min est d’abord initialisée à la valeur présente dans la variable id, qui donne le numérod’ordre dans lequel le sommet k a été rencontré. Puis, pour chaque successeur du sommet k, si celui-cin’a pas encore été traité, on réalise un appel récursif à explore avec ce successeur comme paramètre.Ceci revient à réaliser un parcours en profondeur.

La fonction explore retourne, au retour d’un appel récursif, le numéro d’ordre du « plus haut » som-met, à savoir le sommet ayant le plus petit numéro d’ordre, rencontré en réalisant la descente lors duparcours en profondeur depuis le successeur considéré du sommet k. Ce traitement est réalisé pour tousles successeurs du sommet k.

Lors d’un retour de l’exploration à partir d’un successeur du sommet k, si on se rend compte que lenuméro d’ordre le plus petit rencontré est supérieur à celui du sommet k, on affiche que le sommet k estun point d’articulation.

Le test sur la racine, qui doit détecter si cette racine possède un ou plusieurs successeurs, peut être faitdans la fonction qui appelle explore pour la première fois.

La complexité maximale de cet algorithme est identique à celle d’un parcours de graphe, puisque nousparcourons tous les sommets et tous les arcs, à savoir : O(|S|+ |A|).

Nous pouvons utiliser le même genre de technique sur des digraphes. Un digraphe qui n’est jamaisséparé en différents sous-graphes si on supprime un de ses sommets est appelé un digraphe biconnexe.

Page 48: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 44Il apparaîtra à la section 4.5 les liens existants entre les digraphes biconnexes et les graphes fortementconnexes.

4.4 Détection des cycles

Le problème que nous nous posons à présent consiste en l’écriture d’un algorithme qui indique si ungraphe possède un cycle.

Lorsque le graphe considéré est un graphe non dirigé, un cycle est, pour rappel, une chaîne d’un sommeta jusqu’à ce même sommet a qui ne contienne pas deux fois le même sommet (autre que le sommet a).Dans ce cas, un algorithme de parcours de graphe peut nous être utile. En effet, si lors du parcours nousrencontrons un sommet déjà marqué, cela signifie que nous passons par un même sommet en suivantdeux chaînes différentes. Un cycle, non dirigé, est donc détecté.

L’arête qui mène à un sommet marqué est d’ailleurs une arête de retour. Un graphe non dirigé est acy-clique si on ne rencontre pas d’arête de retour pendant le parcours.

Notons encore qu’il n’y a pas de cycle de moins de trois sommets dans un graphe non dirigé.

Lorsque nous manipulons un digraphe, le problème est plus complexe. Si nous parcourons ce digrapheet que nous rencontrons, au cours du parcours, un sommet déjà marqué, cela ne signifie pas qu’un cycleexiste.

En effet, si nous considérons le digraphe suivant, nous pouvons constater que puisque deux cheminsmènent au sommet 4, il sera marqué lorsqu’on l’atteindra la deuxième fois en suivant le second chemin.Pourtant, ce digraphe ne présente pas de cycle (deux chemins mènent au sommet 4, mais aucun sommeti appartenant à ces chemins n’est atteignable depuis ce sommet 4) :

Pour rechercher un cycle dans un digraphe nous pouvons utiliser l’algorithme 4.3.

Notons pour commencer, que contrairement aux graphes non dirigés, où le plus petit cycle compte troissommets, un cycle dans un digraphe peut être composé de deux sommets.

Cet algorithme, qui se base, une fois de plus, sur une représentation du graphe par liste de successeurs,utilise deux vecteurs pre et post.

Le vecteur pre indique si un sommet k est marqué, auquel cas pre[k] est différent de −1. Si lesommet k est marqué, pre[k] contient alors le numéro d’ordre du sommet k lors du parcours dugraphe.

Page 49: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 45Le vecteur post indique si nous sommes revenus de l’exploration de tous les successeurs d’un sommetk sans détecter de cycle. Si la valeur de post[k] est différente de−1, cela signifie que les explorationsdu digraphe à partir de tous les successeurs du sommet k sont terminées.

La constante dim est initialisée à l’ordre du graphe. Les variables id et cnt sont des compteurs quiseront respectivement utilisés pour être assignés, après incrémentation, aux vecteurs pre et post.

L’algorithme réalise un parcours en profondeur. Pour chaque sommet k considéré, nous passons en revueles différents successeurs de ce sommet.

Si un successeur t du sommet k n’est pas marqué, donc si pre[t] vaut −1, alors nous continuons leparcours en profondeur en réalisant un appel récursif afin de continuer le parcours à partir de ce sommett.

Lorsque nous sortons de la boucle for, nous avons fini de traiter le parcours de tous les successeursdu sommet k, nous pouvons donc le marquer comme complètement traité en assignant à post[k] unevaleur différente de −1.

Lors de la réalisation de la boucle for, si le sommet t est déjà marqué, autrement dit si pre[t]est différent de −1, nous regardons alors si la valeur contenue en post[t] est différente de −1. Sipre[t] est différent de −1 et post[t] vaut −1, cela signifie que le sommet t a déjà été rencontré,mais que nous sommes toujours dans le traitement du parcours d’un de ses successeurs. Nous revenonsdonc au sommet t en étant parti de ce sommet, un cycle est détecté.

Par contre, si pre[t] et post[t] sont différents de−1, cela signifie que nous rencontrons un sommett qui a déjà été complètement traité, ce qui signifie que nous l’avons déjà rencontré et que nous avonscomplètement réalisé l’exploration du digraphe à partir de tous ses successeurs. Nous ne sommes doncpas confrontés à un cycle.

Page 50: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 46Algorithme 4.3 Détection de cycles

int id=0,cnt=0int pre[dim]=-1,...,-1int post[dim]=-1,...,-1

void main()

for(int v=0 ; v < ordre du graphe ; ++v)if(pre[v] == -1)

cycle(v)

void cycle(int k)

int t++idpre[k]=idfor(t=1er adjacent de k ; t existe ; t=adjacent suivant)

if(pre[t] == -1) cycle(t)else if(post[t] == -1) cout << ’’Cycle détecté’’

++cntpost[k]=cnt

La complexité maximale de cet algorithme de détection de cycles est, une nouvelle fois, linéaire ennombre de sommets et d’arcs du graphe considéré, l’algorithme suivant l’idée d’un parcours en profon-deur, et s’exprime donc en O(|S|+ |A|).

La recherche des cycles dans un digraphe est un outil de base pour construire une méthode de recherchedes composantes fortement connexes dans un digraphe. En effet, la présence d’un cycle nous assure qu’ilexiste un chemin dans les deux sens entre tous les couples de sommets appartenant à ce cycle.

4.5 Recherche des composantes fortement connexes

Si nous considérons un digraphe, contrairement aux graphes non dirigés ou aux DAG, savoir qu’unsommet t est atteignable depuis un sommet s ne donne aucune information sur la capacité d’atteindre lesommet s depuis le sommet t (alors que dans un graphe non dirigé on sait que si t est atteignable depuiss alors s l’est aussi depuis t ; et avec un DAG on sait que si t est atteignable depuis s alors s n’est pasatteignable depuis t).

Nous savons que si les sommets s et t sont deux sommets fortement connexes alors t et s le sont aussi.Une composante fortement connexe consiste en des sommets mutuellement atteignables.

Tarjan propose une méthode, présenté par l’algorithme 4.4, de complexité linéaire pour trouver les com-posantes fortement connexes d’un digraphe. Cet algorithme s’inspire du concept d’arête de retour quel’on adapte au digraphe, et donc aux arcs.

Page 51: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 47Nous appelons ensemble d’arcs de retour (ou feedback edge set comme pour les arêtes de retour), leplus petit ensemble d’arcs d’un digraphe connecté qui, si on supprime ces arcs, transforment le digrapheinitial en un DAG.

Le vecteur pre y indique le marquage, le vecteur low indique les plus « hauts » descendants et levecteur comp reprend les composantes.

Cet algorithme est très proche, dans sa structure, de l’algorithme 4.2 détectant les points d’articulation (àla différence que nous considérons ici un digraphe) ainsi que de l’algorithme 4.3 de détection de cycles.

Dans cet algorithme, comme précédemment, dim est une constante initialisée à l’ordre du graphe.

Afin de pouvoir se souvenir du numéro des sommets d’une même composante fortement connexe, l’al-gorithme sauve les numéros des sommets rencontrés sur une pile.

Contrairement à l’algorithme 4.2, la fonction explore ne retourne pas le plus petit numéro d’ordre dusommet rencontré à partir de chaque successeur d’un sommet k. Cet algorithme sauve cette informationdans le vecteur low à l’indice du successeur considéré.

Si on rencontre, en parcourant en profondeur depuis chaque successeur du sommet k, un sommet dontle numéro d’ordre est plus petit que le numéro d’ordre du sommet k, alors on a trouvé un arc de retouret nous sommes bien dans une même composante fortement connexe.

Par contre, si on ne rencontre pas d’arc de retour, c’est qu’il n’existe pas de chemin entre le sommet k etles sommets précédemment rencontrés. Le sommet k fait alors partie d’une autre composante fortementconnexe que les sommets précédemment rencontrés. L’algorithme traite cela en mettant dans le vecteurcomp le numéro d’une composante (on numérote les différentes composantes en partant de 0) auxindices correspondant à tous les sommets appartenant à la composante. Les numéros de ces sommetssont repris de la pile où ils avaient été sauvés un à un lors de chaque appel récursif à explore.

Page 52: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 48Algorithme 4.4 Recherche des composantes fortement connexes

int id=0,sid=0int pre[dim]=-1,...,-1int low[dim]=0,...,0int comp[dim]=0,...,0

void main()

for(int v=0 ; v < ordre du graphe ; ++v)if(pre[v] == -1) explore(v)

void explore(int k)int t,min++idpre[k]=idlow[k]=idmin=idpush(k)for(t=1er adjacent de k ; t existe ; t=adjacent suivant)

if(pre[t] == -1) explore(t)if(low[t] < min) min=low[t]

if(min < low[k]) low[k]=minelse

do

t=pop()comp[t]=sidlow[t]=infini

while(t != k)++sid

Au cours de la boucle while, en fin d’algorithme, nous attribuons un même numéro sid aux sommetsd’une composante fortement connexe. Et nous mettons dans les cellules de low correspondant auxnuméros des sommets formant la composante fortement connexe, une valeur sentinelle infini plusgrande que tous les numéros de sommets présents dans le graphe. Ceci évite que ces sommets ne soienttraités lors des appels suivants à explore.

La complexité maximale de cet algorithme s’exprime une fois de plus, et toujours pour les mêmes raisonsque précédemment, en O(|S|+ |A|).

Un exemple de recherche des composantes fortement connexes au moyen de cet algorithme est illustré

Page 53: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 4 : Cycles et connexité 49ci-dessous :

Ce digraphe présente deux composantes fortement connexes formés des sommets 0, 1, 2, 4 et 3.Ceci apparaît dans le vecteur comp, où les cellules indicées par les valeurs 0, 1, 2 et 4 contiennent lamême valeur 1, et où comp[3] contient 0, représentant ainsi une autre composante. Remarquons aussique le vecteur pre indique bien l’ordre dans lequel l’algorithme a considéré les différents sommets dudigraphe.

Nous pouvons aussi considérer ce second exemple :

Ce graphe est formé à nouveau de deux composantes fortement connexes reprenant cette fois les som-mets 0, 3 et 1, 2, 4. A présent, le vecteur comp contient la valeur 0 aux indices 1, 2 et 4, représentantainsi une des composantes fortement connexes du digraphe ; et contient la valeur 1 aux indices 0 et 3correspondant à la seconde composante fortement connexe.

Page 54: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5

Le tri topologique

5.1 Définition

La question que nous allons nous poser à présent est comment parcourir les sommets d’un digraphe demanière à ce que chaque sommet ne soit considéré que lorsque tous ses prédécesseurs sont traités.

Une telle technique est utile si pour traiter un sommet i, il faille connaître le résultat du traitement detous les sommets qui ont le sommet i comme successeur direct.

Pour résoudre ce problème, nous allons rappeler les notions d’ordre :

– une relation sur un ensemble A est un ordre partiel si et seulement si la relation est réflexive, antisy-métrique et transitive ;

– une relation sur un ensemble A est un ordre total si et seulement si elle est un ordre partiel et pourtout couple (a, b) d’éléments de A il existe une relation de a à b ou de b à a.

Par exemple, la relation « plus petit ou égal » est un exemple d’ordre total sur les entiers. Par contre,considérons le graphe suivant dont les arcs représentent les relations entre sommets :

Comme rien ne peut être dit, dans cet exemple, quant à la relation entre les informations liées auxsommets y et z, la relation ainsi définie n’est pas un ordre total, mais bien un ordre partiel.

Dans la suite de ce chapitre, nous ne considérerons plus la relation d’un élément par rapport à lui même.Cette relation sera prise en compte implicitement dans les digraphes examinés par la suite.

Remarquons que le respect de la propriété d’antisymétrie, associée à la propriété de transitivité, nousassure que des cycles ne peuvent apparaître. Nous pouvons ainsi en déduire que lorsqu’un digraphene comporte par de cycle, la fermeture transitive du graphe 1 traduit une relation d’ordre partiel sur le

1. Nous considérons la fermeture transitive afin de faire respecter la propriété de transitivité nécessaire à l’existence d’unordre partiel.

Page 55: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5 : Le tri topologique 51graphe.

Pour illustrer intuitivement ces digraphes modélisant des relations entre ses sommets, nous pouvons, parexemple, supposer que les sommets du digraphe représentent des tâches à réaliser. Par exemple, dans lecas d’un graphe modélisant la construction d’une maison, une tâche serait « faire les fondations » et uneautre tâche serait « construire les murs », etc. Les arcs d’un tel digraphe indiqueraient l’ordre dans lequelles tâches doivent être réalisées. Un arc allant d’un sommet i vers un sommet j, indique que la tâcheassociée au sommet d’origine i est à réaliser avant la tâche représentée par le sommet j. Ainsi dansnotre exemple pratique, un arc partira du sommet représentant la tâche « faire les fondations » vers lesommet représentant la tâche « construire les murs ». Si un tel digraphe possédait un cycle, cela voudraitdire, éventuellement par transitivité, qu’une tâche devrait être réalisée avant elle-même.

Nous allons donc nous concentrer sur des graphes dirigés acycliques. Nous désirons traiter chaque som-met d’un tel DAG dans un ordre tel qu’aucun sommet ne soit considéré avant tous les sommets pointantvers lui.

Considérons le graphe suivant :

Nous voyons que nous pouvons traiter d’abord le sommet 0 qui n’a aucun prédécesseur, puis nouspouvons passer aux sommets 1 et 2, dans l’ordre que l’on désire, puis aux sommets 3 et 4, ensuite ausommet 5, et enfin au sommet 6.

Une telle opération est appelée un tri topologique. On parle de tri car on ordonne les sommets. Le termeordre topologique est aussi parfois utilisé. Notons qu’il peut exister plusieurs ordres topologiques. Parexemple, dans le graphe ci-dessus, considérer les sommets dans l’ordre 0, 1, 2, 3, 4, 5, 6, est un résultatpossible d’un tri topologique sur les sommets du graphe. Cependant, l’ordre 0, 2, 1 3, 5, 4, 6, est unautre résultat possible pour un tel tri.

5.2 Implémentation

L’algorithme réalisant un tri topologique fonctionne de la manière suivante. D’un côté, on sauvegarde,pour chaque sommet, son degré entrant, et d’un autre côté on initialise une liste vide L. On réalise alorsune boucle dont le corps effectue le traitement suivant : on choisit un sommet i de degré entrant égal à 0,on l’ajoute en fin de la liste L et on diminue d’une unité le degré entrant de tous les sommets successeursdu sommet i. Cette boucle est réalisée tant qu’il reste des sommets non encore sélectionnés et ayant leurdegré entrant égal à zéro.

Cette opération transforme un ordre partiel, représenté par la fermeture transitive du graphe, en un ordretotal, représenté par la fermeture transitive de la liste L construite par l’algorithme. On parle aussi delinéarisation de l’ordre. Il n’y a pas toujours unicité de l’ordre total ainsi construit. Tout dépend des choixfaits lors de l’exécution de l’algorithme si plusieurs sommets ayant leur degré entrant à zéro peuvent êtresimultanément choisis.

Page 56: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5 : Le tri topologique 52Nous pouvons considérer le graphe suivant :

La fermeture transitive de ce graphe représente bien un ordre partiel : par exemple les relations entre lessommets b et c et entre les sommets b et d ne nous indiquent rien sur la relation entre les sommets c etd.

En appliquant l’algorithme du tri topologique sur ce graphe, nous pouvons obtenir une des listes L re-prises ci-dessous :

Dans tous les cas, un ordre total est construit permettant la « comparaison » mutuelle de tous les élémentsdu graphe initial 2.

L’algorithme 5.1 réalise un tri topologique sur un digraphe représenté par une liste de successeurs, etutilise pour ce faire une file pour sauvegarder les sommets sans prédécesseur en attente d’être traités.

2. Chacun des ordres totaux ainsi construits est compatible avec l’ordre partiel initial, c’est à dire qu’une relation existanteentre deux éléments dans l’ordre partiel doit aussi apparaître dans l’ordre total.

Page 57: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5 : Le tri topologique 53Algorithme 5.1 Tri topologique

void tri(graphe G)

int pred[dim]=0,...,0liste L;queue Q

for(int i=0 ; i < ordre du graphe ; ++i)for(int j=adj[i] ; j != null ; j=adjacent suivant)

++pred[j]

for(int i=0 ; i < ordre du graphe ; ++i)if(pred[i] == 0) Q.put(i)

while(Q n’est pas vide)

int i=Q.get()insérer le sommet i en fin de liste Lfor(int j=adj[i] ; j != null ; j=adjacent suivant)

--pred[j]if(pred[j] == 0) Q.put(j)

Nous constatons que l’algorithme fonctionne exactement comme décrit en début de section. La constantedim est initialisée à l’ordre du graphe.

Une première imbrication de deux boucles passe en revue tous les successeurs de chaque sommet dudigraphe. On incrémente alors le nombre de prédécesseurs de chaque sommet.

On parcourt alors chaque sommet du digraphe à la recherche de sommets dont le nombre de prédéces-seurs est resté à zéro, et on place ces sommets dans la file.

Puis, tant que la file n’est pas vidée, on extrait un sommet de la file, on place ce sommet en fin de liste L,qui contient alors, quand on la lit de gauche à droite, les sommets considérés dans l’ordre topologique.Pour chaque successeur de ce sommet extrait de la file, on décrémente d’une unité son nombre deprédécesseurs (que l’on peut donc à présent interpréter comme « son nombre de prédécesseurs nonencore traités »). Si ce nombre de prédécesseurs atteint la valeur nulle, on insère ce sommet, sans plusde prédécesseur à traiter, dans la file.

Dans cet algorithme, l’initialisation du vecteur s’exprime en O(|S|), le calcul du nombre de prédéces-seurs de chaque sommet est fait en O(|A|) (pour l’ensemble des deux boucles, nous considérons tousles arcs), la recherche des sommets sans prédécesseur pour initialiser la file se fait en O(|S|), puis nousavons une imbrication de deux boucles passant en revue tous les sommets et pour chaque sommet tousses successeurs, ce qui donne une complexité en O(|S| + |A|). Tous ces traitements étant réalisés enséquence, la complexité maximale globale s’exprime donc en O(|S|+ |A|).

Notons encore que la file ne se vide pas tant que tous les sommets du DAG n’ont pas été passés en revue.Nous pouvons donc l’utiliser pour tester si un graphe est un DAG. En effet, si la file se vide avant que

Page 58: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5 : Le tri topologique 54tous les sommets y soient passés, cela signifie qu’il existe un cycle.

Par exemple, considérons le digraphe suivant :

Nous voyons, en appliquant l’algorithme 5.1, qu’après avoir traité les sommets 0 et 1, nous n’avons plusde sommets sans prédécesseur qui ne sont pas encore traités, alors que nous n’avons traité que deux dessix sommets. Un cycle est détecté.

5.3 Interprétations

Outre la construction d’un ordre total, il existe, au moins, deux autres manières de considérer un tritopologique :

1. soit on le conçoit comme une renumérotation ou un renommage des étiquettes des sommets defaçon à ce que tout sommet à l’origine d’un arc soit étiqueté par une valeur qui est inférieure àcelle du sommet à l’extrémité de l’arc :

2. soit on le conçoit comme un réarrangement des sommets sur un axe horizontal de manière à ceque les arcs pointent de gauche à droite :

Page 59: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5 : Le tri topologique 55

5.4 Tri topologique inversé

Il peut aussi être intéressant de réaliser un tri topologique inversé, indiquant d’abord le dernier sommetaccessible, puis l’avant-dernier, etc. 3

Pour réaliser un tel tri inversé, il suffit, par exemple, de réaliser un parcours en profondeur sur le di-graphe en traitant les sommets en postordre (en traitant donc les sommets fils avant le sommet pèrecorrespondant).

De cette manière, nous atteignons dans un premier temps des sommets du graphe qui n’ont pas desuccesseur. Ces sommets sont bien ceux qui seraient atteints en dernier lieu par le tri topologique. Demême, puisque nous traitons les sommets en postordre, lorsque nous remontons vers un sommet, nousredescendons tout de suite, avant de traiter ce sommet, vers ses éventuels autres fils. Nous atteignonsdonc itérativement d’abord les sommets sans successeur, puis les sommets qui pointent vers ces sommetssans successeur, etc.

Par exemple, considérons la figure suivante :

3. Si les sommets d’un digraphe représentent, par exemple, des tâches à effectuer et si les arcs indiquent, comme nousl’avons déjà vu, la relation de « précédence » entre deux tâches, un tri topologique classique permet alors de connaître l’ordredans lequel il faut considérer ces tâches. Si un moment est fixé pour la réalisation de la première tâche du digraphe, et si unedurée de réalisation est connue pour chaque tâche, le tri topologique nous permet aussi de connaître le moment au plus tôtauquel chaque tâche doit être commencée. Enfin, une fois le tri topologique terminé, nous connaissons le moment où la (les)dernière(s) tâche(s) est (sont) terminée(s). A partir de ce moment, et en réalisant un tri topologique inversé, nous pouvonsdéterminer le moment au plus tard où chaque tâche doit être commencée. Ces différentes informations sont importantes lorsde la réalisation d’un planning associé à la réalisation des tâches.

Page 60: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 5 : Le tri topologique 56

Ce parcours donne si le traitement en postordre correspond à l’affichage du numéro du sommet : 3, 7, 4,2, 1, 5, 6, 0. Cela correspond bien à un tri topologique inversé car 0, 6, 5, 1, 2, 4, 7, 3 est bien une dessolutions possibles pour un tri topologique pour le digraphe donné en exemple.

Un tri topologique « classique » peut donc aussi être écrit en se basant, entre autres, sur un parcoursen profondeur. Ainsi, si le traitement, lors du parcours en profondeur, consiste à sauver sur une pile lessommets rencontrés, nous pouvons, après le parcours, vider élément par élément le contenu de la pile,obtenant ainsi, de manière un peu moins efficace, un tri topologique.

Page 61: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6

Les arbres sous-tendants minimaux

6.1 Introduction

Nous allons étudier, au cours de ce chapitre, la notion d’arbre sous-tendant minimal, appelé aussi arbrerecouvrant de poids minimal ou encore minimum spanning tree en anglais.

Imaginons le problème posé par le câblage « optimal » d’un réseau informatique. Nous sommes confron-tés à un certain nombre d’ordinateurs se trouvant physiquement éparpillés aux sein d’une entreprise etdevant être reliés entre eux d’une manière telle que le câblages soit de coût minimum (en taille totaldu câblages posé par exemple). Nous pouvons voir ce réseau à constituer comme un graphe dont lessommets représentent les ordinateurs et les arêtes correspondent aux câbles (avec leur coût) qui peuventêtre posés entre chaque ordinateur.

Nous considérons donc un graphe non dirigé et pondéré par le coût propre à chaque arête (longueur,prix, etc.). Nous parlerons, dans ce chapitre, de poids lorsque nous évoquerons les étiquettes présentessur les arêtes.

Le problème que nous nous posons ici est ainsi de trouver un ensemble d’arêtes, reliant tous les sommetsdu graphe, tel que la somme des poids de ces arêtes 1 soit inférieure ou égale à celle de n’importe quelautre ensemble d’arêtes reliant tous les sommets 2.

Cet ensemble d’arêtes constitue un arbre. En effet, s’il s’agissait d’un graphe qui ne serait pas un arbre,il y aurait un cycle, et supprimer une arête de ce cycle donnerait un ensemble d’arêtes, reliant tous lessommets, d’un poids total inférieur à celui de l’ensemble initialement considéré.

Cet arbre est appelé l’arbre sous-tendant minimal. Remarquons qu’il est parfois possible de construireplusieurs arbres sous-tendants minimaux différents à partir d’un même graphe.

Pour représenter le graphe de départ et l’arbre sous-tendant finalement produit, il existe, comme nousl’avons déjà évoqué, plusieurs représentations différentes.

Le graphe non dirigé peut être représenté par une liste de successeurs, reprenant aussi les étiquettesprésentes sur les arêtes. Nous avons illustré une telle structure à la section 3.3.

Il est aussi possible de manipuler une matrice d’adjacence, qui est bien sûr symétrique et dont les cellulescontiennent le poids présent sur l’arête entre les sommets référencés par le numéro de ligne et de colonnede la cellule concernée, comme nous l’avons vu à la section 3.3. Nous supposons aussi que le graphe ne

1. Les poids présents sur ces arêtes peuvent représenter des longueur de câblage, des distances qu’un véhicule doit parcou-rir, un coût, etc.

2. Le problème consistant à trouver un arbre sous-tendant minimal dans un digraphe est plus complexe que pour un graphenon dirigé, nous ne verrons pas de tels algorithmes ici.

Page 62: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 58contient aucune arête d’un sommet vers lui-même.

L’arbre sous-tendant minimal produit peut être représenté par (1) une structure usuellement utiliséepour représenter un graphe, un arbre sous-tendant minimal n’étant jamais qu’un sous-graphe du grapheinitial ; (2) une liste linéaire d’informations sur les arêtes formant l’arbre ; (3) un vecteur de pointeursvers les arêtes formant l’arbre ; (4) une structure d’arbre telle que celles vues au cours d’algorithmique1 ; etc.

6.2 Algorithme de Prim

La première technique nous permettant de construire un arbre sous-tendant minimal à partir d’un graphenon dirigé est celle de Prim. Cette méthode se base sur la propriété de scission.

Propriété de scission : Supposons un partitionnement quelconque des sommets d’un graphe en deuxsous-ensembles de sommets. L’arbre sous-tendant minimal contient l’arête de poids minimum reliant unsommet d’un sous-ensemble à un sommet de l’autre sous-ensemble.

Preuve : Appelons m l’arête de poids minimum reliant les deux sous-ensembles et supposons que mn’est pas dans l’arbre sous-tendant minimal. Considérons alors le graphe obtenu en ajoutant l’arête m àcet arbre. Ce graphe admet donc un cycle produit par l’arête m et l’arête n qui était déjà dans l’arbre etqui relie aussi les deux sous-ensembles. Si on supprime cette arête n, on obtient un arbre dont la sommedes poids est inférieure à la somme des poids de l’arbre de départ. Ceci contredit l’hypothèse que l’arbresous-tendant initialement considéré, qui contient n mais pas m, est minimal.

Cette propriété nous indique qu’il est donc possible de construire un arbre sous-tendant minimal endébutant depuis un sommet quelconque, puis en ajoutant itérativement dans la solution le sommet xdont l’arête, reliant ce sommet x à un des sommets déjà présents dans l’ensemble des sommets formantla solution, est celle ayant le poids le plus petit (on dit aussi qu’il s’agit du sommet « le plus proche »des sommets déjà dans la solution, on parle alors de distance entre les sommets). En cas d’ex aequo onpeut considérer n’importe laquelle des arêtes ayant le même poids minimum. L’algorithme résultant decette technique porte le nom d’algorithme de Prim.

Cette technique exploite bien la propriété de scission en deux sous-ensembles décrite par la propriétéprécédente. Un des deux sous-ensembles représente l’arbre sous-tendant minimal qui se construit.

Notons que la réalisation d’une telle scission en deux sous-ensembles est aussi appelé un cut du grapheen anglais.

La technique de Prim est illustrée par l’algorithme 6.1. Cet algorithme utilise deux vecteurs de travail, wtentièrement initialisé à l’infini et edge entièrement initialisé à la valeur sentinelle null, qui contien-dront des informations sur les sommets non encore intégrés à l’arbre sous-tendant minimal en cours deconstruction.

L’idée sous-jacente à l’usage de ces vecteurs de travail est de ne pas devoir calculer à chaque itérationla distance d’un sommet non encore dans l’arbre sous-tendant minimal par rapport à tous les sommetsdéjà contenu dans l’arbre en question, mais plutôt de conserver à tout moment la distance entre l’arbresous-tendant minimal en construction et chaque sommet du graphe n’appartenant pas encore à l’arbre.

La valeur se trouvant en wt[i] représente la plus petite distance connue entre le sommet i et l’arbresous-tendant minimal en construction sans préciser à quel sommet de l’arbre il est ainsi relié. Cette in-formation manquante se trouve dans edge[i] qui contient un pointeur vers l’arête reliant le sommetde l’arbre sous-tendant minimal en construction et le sommet i. L’algorithme réalise une boucle englo-bante partant du sommet 0, considéré comme le premier sommet du graphe. Au cours du traitement ducorps de la boucle nous allons déterminer quel est le sommet le plus proche de l’ensemble des sommets

Page 63: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 59apparaissant déjà dans l’arbre (cet ensemble ne contient que le sommet 0 lors du premier tour de laboucle). La variable min contiendra le numéro de ce sommet le plus proche. La variable v représentele sommet que l’on vient d’ajouter à l’arbre sous-tendant minimal en construction (v vaut donc 0 aupremier tour de la boucle).

Pour déterminer le sommet le plus proche de l’arbre, nous allons parcourir les sommets du graphe.Pour ce faire, la variable w contiendra un à un tous les numéros des sommets du graphe. Si mst[w]contient un pointeur différent de la valeur sentinelle null, cela signifie que ce sommet w a déjà étésélectionné pour faire partie de l’arbre sous-tendant minimal. Sinon, nous vérifions si une arête existeentre le sommet v et le sommet w. Si cette arête existe et que son poids est inférieur au poids déjà connuentre l’ensemble des sommets formant l’arbre sous-tendant minimal en construction (sans le sommetv) et le sommet w, alors nous modifions wt[w] pour indiquer qu’il est à présent (depuis l’insertion dusommet v dans l’arbre) plus proche de l’arbre sous-tendant minimal. La valeur de edge[w] est aussimodifiée pour pointer vers l’arête entre les sommets v et w.

La variable min retient l’indice du sommet jusqu’ici le plus proche de l’arbre sous-tendant en construc-tion. Si le sommet w devient le sommet le plus proche, donc si wt[w] est inférieur à wt[min], alorsla valeur de w est assignée à min. Lorsque tous les sommets n’appartenant pas à l’arbre sous-tendantminimal en construction sont examinés, la variable min contient le numéro du sommet le plus proche del’arbre, le contenu de edge[min] pointant vers cette « plus petite » arête est assigné à mst[min], quicontiendra ainsi tour à tour toutes les arêtes formant l’arbre sous-tendant minimal. Puis min est assignéeà v et nous recommençons un tour de la boucle englobante.

Page 64: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 60Algorithme 6.1 Algorithme de Prim

wt vecteur d’entiers initialisés à l’infinimst vecteur de pointeurs vers arête initialisés à nulledge vecteur de pointeurs vers arête initialisés à null

min=1for(v=0 ; min != 0 ; v=min)

min=0for(w=1 ; w < nombre de sommets ; ++w)

if(mst[w] == null)

if(arête(v,w) existe)

if(poids arête(v,w) < wt[w])

wt[w]=poids arête(v,w)edge[w]=pointeur vers l’arête(v,w)

if(wt[w] < wt[min])

min=w

if(min != 0)

mst[min]=edge[min]

L’élégance de cet algorithme réside bien dans le fait que l’on ne recalcule pas à chaque fois la distanceentre les sommets de l’arbre courant et tous les autres sommets du graphe. A chaque fois qu’un sommetest rajouté à l’arbre on se contente de regarder la distance entre ce sommet et ses successeurs afind’ajuster si nécessaire le contenu de mst et edge.

La manière de gérer le choix du minimum a des effets sur la complexité en temps de l’algorithme.L’algorithme ci-dessus est, a priori, en O(|S|2), car telles quelles, les deux boucles imbriquées passenten revue tous les sommets du graphe.

Si pour gérer l’extraction du minimum on utilise un heap de sommets, où la priorité d’un sommet estinversément proportionnelle à la plus petite distance entre le sommet considéré et l’arbre sous-tendantminimum en construction, nous obtenons assez naturellement l’algorithme 6.2.

Page 65: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 61Algorithme 6.2 Algorithme de Prim avec heap

edge vecteur de pointeurs vers arête initialisés à nullmst vecteur de pointeurs vers arête initialisés à null

min=1mst[0]=pointeur vers l’arête(0,0)for(v=0 ; min != 0 ; v=min)

min=0for(t=1er successeur de v ; t existe ; t=successeur suivant)

if(mst[t] == null)

modifierHeap(t,poids(v,t))if(heap est modifié) edge[t]=pointeur vers l’arête(v,t)

if(heap non vide)

min=suppressionMinHeap()mst[min]=edge[min]

La fonction modifierHeap réalise une insertion d’un nouvel élément dans le heap ou remonte unélément déjà présent dans le heap si sa priorité augmente (i.e. si le sommet t a déjà été inséré dans le heapmais à partir d’une arête de poids supérieur au poids de celle considérée à présent). Si modifierHeapest appelé pour un élément déjà présent dans le heap mais en précisant une priorité plus faible que celledéjà considérée, la fonction ne modifie pas le heap.

La boucle englobante dans cet algorithme tourne au plusO(|S|) fois. La seconde boucle, imbriquée dansla première, contient un appel à la fonction modifierHeap qui insère un nouvel élément dans le heapou modifie le heap si la priorité lié à un élément déjà présent dans le heap augmente. La complexité decette fonction s’exprime en O(log |S|). Au total de l’exécution des deux boucles imbriquées, on réaliseun appel à modifierHeap par arête dans le graphe, cela donne donc une complexité maximale pourl’ensemble de ces traitements qui s’exprime en 0(|A| log |S|). La complexité maximale de la suppressiondu minimum du heap, suivi par la réorganisation du heap, s’exprime est O(log |S|). Cette suppressionse trouve dans le corps de la boucle englobante. Au total nous avons donc une complexité maximale enO(|S| log |S| + |A| log |S|). Comme nous l’avons vu à la section 3.2, |A| est au plus égal à (|S|(|S| +1))/2, ainsi nous avons, pour un graphe de plus d’un sommet, que |A| est plus grand que |S|, et donccela peut aussi nous permettre d’exprimer une complexité maximale 3 par O(|A| log |S|), comme onpeut le voir parfois dans la littérature.

Nous pouvons illustrer cette méthode au moyen de l’exemple suivant. Considérons le graphe dont lesarêtes ont des poids représentés par des nombres réels :

3. Cette complexité maximale, qui exprime bien un pire des cas, est « plus mauvaise » que la complexité maximale del’algorithme 6.1. Par contre, si le nombre d’arêtes est à peu près équivalent aux nombre de sommets, alors il apparaît plusclairement que l’algorithme 6.2 est plus efficace.

Page 66: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 62

En suivant l’algorithme de Prim, l’arbre sous-tendant minimal pour ce graphe se construit ainsi :

Ainsi, par exemple à la figure a ci-dessus, les deux sous-ensembles de sommets considérés lors de lascission sont 0,1 et 2,3,4,5.

6.3 Algorithme de Kruskal

Cette seconde technique de construction d’un arbre sous-tendant minimal, appelée méthode de Kruskal,se base sur la propriété d’ajout 4 décrite ci-dessous.

Propriété d’ajout : Étant donné un graphe G, considérons le graphe G′ obtenu en ajoutant une arêtee à G. Si on ajoute aussi cette arête e à l’arbre sous-tendant minimal de G, et que l’on enlève l’arêtemaximale du cycle que l’on a ainsi produit, on obtient alors un arbre sous-tendant minimal pour G′.

Preuve :

4. La propriété d’ajout porte aussi parfois le nom de « propriété de cycles ».

Page 67: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 63– Si e est une arête ayant un poids supérieur au poids de chacune des autres arêtes, alors e ne peut

apparaître dans un arbre sous-tendant minimal de G′ (par la propriété de scission). L’arbre sous-tendant minimal de G′ est alors égal à l’arbre sous-tendant minimal de G.

– Soit t 6= e l’arête de poids maximum dans le cycle créé en ajoutant e à l’arbre sous-tendant minimal deG. Supprimons à présent les arêtes t et e de l’arbre sous-tendant minimum 5. En appliquant la propriétéde scission, nous devons choisir entre les deux arêtes t et e et prendre celle de poids minimal, à savoire.

Nous pouvons illustrer cette propriété d’ajout par l’exemple suivant. Supposons le graphe de départ sui-vant :

L’arbre sous-tendant minimal (d’un poids total égal à 16,5) correspondant à ce graphe est :

Transformons à présent le graphe de départ en ajoutant une arête de poids égal à 2 entre les sommets 0et 3. On obtient le nouveau graphe suivant :

Si nous ajoutons aussi cette arête à l’arbre sous-tendant minimal, nous faisons alors apparaître un cycle

5. Notons que cet arbre sous-tendant minimum présentant à présent un cycle n’est plus à proprement parler un arbre maisplutôt un graphe.

Page 68: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 640 - 2 - 4 - 5 - 3 - 0 dans l’arbre sous-tendant :

L’arête de ce cycle ayant le plus grand poids est l’arête de poids 6 entre les sommets 0 et 2. Retironscette arête de l’arbre sous-tendant. On obtient le nouvel arbre :

Comme l’indique la propriété ci-dessus, nous obtenons bien ainsi, pour le graphe modifié, ce dernierarbre sous-tendant minimal (de poids total égal à 12,5).

Pour reprendre les arguments de la démonstration ci-dessus, après l’ajout de l’arête de poids 2 entre lessommets 0 et 3 dans l’arbre sous-tendant minimal de départ, nous pouvons y supprimer l’arête de poidsmaximal ainsi que l’arête que nous venons d’insérer et qui a produit un cycle.

Cela nous donne la figure suivante, où les deux arêtes supprimées apparaissent en pointillé :

Nous avons donc réalisé une scission et ainsi, en respectant la propriété de scission, nous choisissonsl’arête de poids minimal reliant les deux ensembles distincts de sommets. Dans notre exemple, nousrajouterons l’arête de poids 2 entre les sommets 0 et 3.

Nous obtenons ainsi le nouvel arbre sous-tendant minimal :

Page 69: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 65

De cette propriété d’ajout, nous pouvons déduire une autre approche pour construire un arbre sous-tendant minimal.

En effet, nous pouvons construire un tel arbre en commençant par prendre l’arête ayant le poids le pluspetit, puis en rajoutant itérativement l’arête la plus petite parmi celles qui restent, si cette arête ne formepas un cycle avec les arêtes précédemment sélectionnées.

Cette méthode porte le nom d’algorithme de Kruskal et procède donc en feignant d’ajouter une à une lesarêtes dans le graphe et en adaptant l’arbre sous-tendant minimum en conséquence (en respectant doncla propriété d’ajout).

Cette méthode produit donc bien un arbre sous-tendant minimum d’une manière constructive. Au coursde cette construction, on examine tour à tour les arêtes du graphe depuis celle ayant le poids le pluspetit jusqu’à celle ayant le plus grand poids, ainsi, par la propriété d’ajout, on ne retire jamais de lasolution une arête déjà considérée comme faisant partie de l’arbre sous-tendant en construction. Si unearête considérée pour être introduite dans la solution produit un cycle, cette arête aura nécessairement unpoids plus grand que toutes celles déjà dans l’arbre sous-tendant en construction. Dans ce cas on ignorecette arête et on passe à la suivante.

L’algorithme 6.3 illustre la technique de Kruskal. Cet algorithme utilise un vecteurs de pointeurs vers desarêtes, mst qui contiendra finalement des pointeurs vers les arêtes formant l’arbre sous-tendant mini-mal. L’algorithme utilise aussi un heap pour gérer d’une manière efficace l’ordre sur les poids des arêtes.

Algorithme 6.3 Algorithme de Kruskal

mst vecteur de pointeurs vers arête initialisé à null

k=1création du heap d’arêtes sur base des poidsfor(i=0 ; i < nombre d’arêtes du graphe ; ++i)

min=suppressionMinHeap()if(min ne produit pas de cycle avec les arêtes

déjà dans mst[1...k-1])

union(min->origine,min->destination)mst[k]=min++k

Page 70: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 66La boucle principale tourne autant de fois qu’il y a d’arêtes dans le graphe. A chaque tour, on retire duheap l’arête la plus petite. Si l’ajout de cette plus petite arête dans l’arbre sous-tendant en constructionne produit pas de cycle avec les arêtes déjà présentes, alors nous conservons cette nouvelle plus petitearête dans l’arbre sous-tendant minimal et nous la rajoutons dans le vecteur mst.

Pour détecter un cycle nous pouvons nous inspirer des techniques présentées à la section 4.4. Nous yparlions, dans le cas des graphes non dirigés, de réaliser un parcours et de se baser sur le marquage,naturellement utilisé lors du parcours, pour détecter un sommet déjà rencontré.

La complexité de la procédure de création du heap contenant toutes les arêtes du graphe coûte au plusO(|A| log |A|). Puis on considère une à une toutes les arêtes du graphe en les retirant à chaque fois duheap. Cela s’exprime aussi au plus en O(|A| log |A|). La détection de cycle dans un graphe non dirigé,qui est exécutée à chaque tour de la boucle for, s’exprime classiquement en O(|S|+ |A|).

Néanmoins, concernant la détection de cycle, nous pouvons alternativement vérifier si les deux sommets,que l’on se propose de relier par une arête juste sortie du heap, ne sont pas déjà accessibles par ailleursdans l’arbre sous-tendant minimum en construction. Nous devons nous assurer que les deux sommetsqui vont être à présent reliés, font bien partie de composantes connexes différentes dans l’arbre enconstruction 6 ; sinon un cycle serait induit par l’ajout dans l’arbre de l’arête que l’on sort du heap.

En jouant sur un marquage et/ou sur la structure de donnée utilisée, il est possible d’améliorer la com-plexité de cette détection de cycle. En effet, nous pouvons marquer chaque sommet d’une même com-posante composante connexe par une même « valeur ». Lorsque nous sortons une arête du heap, nousregardons si les deux sommets aux extrémités de cette arête ne sont pas déjà marqués de la même ma-nière. Si ce n’est pas le cas, on rajoute cette arête à la solution, et on uniformise le marquage de lacomposante ainsi agrandie. Cette uniformisation est représentée par l’appel à union dans l’algorithme6.3. Pour réaliser ce marquage et cette union nous considèrerons chaque composante en constructioncomme un arbre dont chaque nœud pointe, entre autres, vers son nœud père et dont la racine d’un telarbre ait son pointeur père pointant vers lui-même. Pour détecter si deux nœuds appartiennent à la mêmecomposante, il suffit donc de remonter jusqu’à la racine de l’arbre et vérifier si la même racine est atteinteà partir des deux nœuds de départ. De même l’union de deux composantes, et donc de deux arbres, seréalise en attachant un arbre à l’autre de manière à obtenir un arbre résultant de l’union qui soit le mieuxbalancé possible. Pour réaliser ces deux opérations, nous devons donc suivre un chemin entre un nœudet la racine correspondante ; cela peut se faire, si les arbres sont bien balancés, avec une complexité enO(log |S|), qui s’approxime aussi en O(log |A|).

La complexité maximum de l’algorithme devenant alors O(|A| log |A|).

Nous l’avons vu précédemment dans ce chapitre, ainsi qu’à à la section 3.2, que |A| est au plus égalà (|S|(|S| + 1))/2, ainsi nous avons que O(log |A|) s’exprime au plus en O(log |S|). De même celanous donne que pour un graphe de plus de un sommet, |A| est plus grand que |S|. Ainsi la complexitémaximale de cet algorithme peut aussi s’exprimer en O(|A| log |S|).

Nous pouvons illustrer cette méthode au moyen des deux exemples suivants.

Considérons, pour commencer, le graphe :

6. Autrement dit, ils doivent être dans des arbres différents dans la forêt composant la solution en cours.

Page 71: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 67

En suivant l’algorithme de Kruskal, l’arbre sous-tendant minimal de ce graphe se construit ainsi :

Si nous considérons le graphe :

Nous construisons, toujours suivant l’algorithme de Kruskal, l’arbre sous-tendant minimal de la manère

Page 72: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 6 : Les arbres sous-tendants minimaux 68suivante :

Remarquons que lors du passage de l’étape c à l’étape d, l’arête la plus petite est celle de poids 2 entreles sommets 1 et 3, mais si nous rajoutons cette arête à l’arbre en cours de construction, nous formonsun cycle 1 - 0 - 2 - 3 - 1. Nous ne pouvons donc sélectionner cette arête, nous prenons donc la plus petitearête suivante, à savoir, par exemple, celle de poids 3 entre les sommets 2 et 4.

Même si, en gros, les deux méthodes ont la même complexité, O(|A| log |S|), nous constatons quel’algorithme de Prim passe en revue les sommets du graphe et que l’algorithme de Kruskal passe enrevue les arêtes du graphe. Ainsi, si un graphe est dense, on utilise plutôt l’algorithme de Prim, par contresi un graphe est composé de beaucoup de sommets et de peu d’arêtes alors l’algorithme de Kruskal estplus indiqué.

Page 73: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7

Les plus courts chemins

7.1 Introduction

Trouver le plus court chemin, ou shortest path en anglais, entre deux sommets d’un digraphe pondéréconsiste en la recherche du chemin dont la somme des pondérations des arcs le composant est minimale,parmi tous les chemins reliant les deux sommets donnés.

Nous pouvons d’ores et déjà identifier le cas particulier consistant en un digraphe où tous les poids sontégaux. Le parcours en largeur nous permet, dans ce cas, de trouver le plus court chemin entre un sommetdonné et tous les autres sommets du graphe. En effet, il s’agit alors de chercher les chemins comptant lemoins d’arcs possibles entre les sommets considérés. Nous pouvons illustrer cela par l’exemple suivant :

7.2 Plus courts chemins dans un digraphe

D’une manière générale, on pose donc le problème consistant à trouver les plus courts chemins reliantun sommet x d’un digraphe donné à tous les autres sommets de ce digraphe. Nous considérons dansun premier temps que les pondérations sur les arcs sont toutes positives. Un chemin le plus court nepouvant alors « tourner » sur lui-même, sous peine de se rallonger, il n’y a jamais de cycle dans detels plus courts chemins entre deux sommets. Ainsi, la construction des plus courts chemins depuis unsommet du graphe conduit à produire un arbre recouvrant du digraphe.

On construit l’arbre des plus courts chemins à partir d’un sommet x en ajoutant, à chaque étape de cetteconstruction, le sommet de la frange le plus proche du sommet x. Remarquons que cette technique estdifférente de celle utilisée par la méthode de Prim pour construire un arbre sous-tendant minimal. Eneffet, avec la méthode de Prim nous ajoutions le sommet le plus proche de l’arbre en construction et non

Page 74: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 70du sommet x initial.

Illustrons cela en partant du digraphe suivant 1 :

Partons du sommet 1 :

Le sommet le plus proche du sommet 1 est le sommet 3 :

Cette fois le sommet le plus proche, toujours du sommet 1, est le sommet 2 (distant de 2 unités, et nonle sommet 5 distant de 8 unités) :

1. Les figures suivantes représenteront en pointillés les éléments se trouvant dans la frange.

Page 75: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 71

Le sommet le plus proche du sommet 1 est à présent le sommet 4 :

Le sommet le plus proche du sommet 1 est maintenant le sommet 5, en passant par le sommet 4 (et nonpas par le sommet 3) :

Considérons un second exemple en partant du digraphe suivant :

Page 76: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 72

L’arbre des plus courts chemins partant du sommet initial 1 est :

Remarquons que cet arbre est bien différent de l’arbre sous-tendant minimal du graphe non dirigé équi-valent, qui peut être pour cet exemple un des deux arbres suivants :

Page 77: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 73

Ces arbres ont tous deux un poids total égal à 22 (alors que l’arbre des plus courts chemins est d’unpoids total de 23). Dans l’arbre de gauche le chemin du sommet 1 au sommet 4 est de longueur 15, etnon de longueur 12 comme l’est le plus court chemin. Pour l’arbre de droite, le chemin du sommet 1 ausommet 5 est de longueur 16, alors que le plus court chemin entre ces deux sommets est de longueur 11.

Pour réaliser le calcul des plus courts chemins à partir d’un sommet initial, nous pouvons modifierl’algorithme de Prim en stockant dans un vecteur, que nous appellerons dist, la distance de chaquesommet avec le sommet initial x. Quand on rajoute un sommet k dans l’arbre en construction, on met àjour la frange en parcourant la liste de successeurs de ce sommet k. Pour chaque sommet t de cette listede successeurs, la distance du sommet x aux sommets de cette liste est égale àdist[k] + distance de k à t.

La propriété fondamentale sur laquelle se base cet algorithme est que, dans un digraphe, le chemin leplus court entre un sommet a et un sommet c est composé du plus court chemin entre le sommet a etun sommet b et du plus court chemin entre ce sommet b et le sommet c, et ce pour tout sommet b dudigraphe se trouvant sur le plus court chemin entre les sommets a et c.

L’algorithme 7.1 réalise cette recherche des plus courts chemins depuis un sommet initial s jusqu’àtous les autres sommets du digraphe. Pour réaliser cela, nous manipulons un ensemble M de sommetscontenant initialement tous les sommets du graphe à l’exception du sommet initial s.

Page 78: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 74Algorithme 7.1 Algorithme de Dijkstra

M=ensemble videfor(i=1; i<= ordre du graphe; ++i)

dist[i]=poids arc(s,i)prec[i]=srajouter le sommet i à l’ensemble M

retirer le sommet s de l’ensemble Mwhile(l’ensemble M n’est pas vide)

m=sommet x appartenant à M tel que dist[x] est minimumretirer le sommet m de l’ensemble Mif(dist[m] == infini)

M=ensemble videelse

for(a=1er arc sortant de m ; a existe ; a=arc suivant)

y=extremité de aif(y appartient à M)

v=dist[m]+poids arc(m,y)if(v < dist[y])dist[y]=vprec[y]=m

Nous manipulons aussi deux vecteurs, dist et prec, tels que pour chaque sommet i distinct du som-met s, la valeur contenue en dist[i] indique la plus courte distance connue entre le sommet s et lesommet i, et prec[i] reprend le numéro du sommet précédant le sommet i sur le plus court cheminen construction entre les sommets s et i.

Initialement, dist[i] contient le poids présent sur l’arc entre le sommet s et le sommet i. Si cet arcn’existe pas, le poids est supposé égal à l’infini. Les entrées correspondantes du vecteur prec valenttoutes initialement s, puisque nous ne considérons dans un premier temps que les chemins ne comportantqu’un seul arc entre le sommet s et tous les autres sommets.

Par la suite, en découvrant de nouveaux arcs, nous essayons d’allonger, en nombre d’arcs, les chemins,en constatant éventuellement que nous améliorons, en terme de distance, la situation existante.

Pour ce faire, nous réalisons une boucle qui retire de l’ensemble M le sommet m dont la valeur corres-pondante dans le vecteur dist, à savoir dist[m], est la plus petite. Pour chaque sommet y successeurde ce sommet m, nous regardons s’il appartient à l’ensemble M. Si le sommet y n’y appartient pas, cela

Page 79: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 75signifie qu’il est déjà traité. Sinon, nous mettons à jour les vecteurs dist et prec si, en passant par lesommet m, le sommet y est plus proche du sommet initial s.

Si dist[m] valait l’infini lors du retrait du minimum de l’ensemble M, cela signifie que le sommet mappartient à une autre composante que le sommet s. Cela sera alors aussi le cas pour tous les autres som-mets potentiellement encore présents dans M. Dans cette situation, la recherche des plus courts cheminsdepuis le sommet s peut s’arrêter. Ces sommets encore présents dans l’ensemble M sont à une distanceinfinie du sommet s, valeur déjà présente pour ces sommets dans le vecteur dist.

L’ensemble M peut être géré au moyen d’un heap de sommets dont la priorité de chaque sommet estinversement proportionnelle à la distance courante entre le sommet s initial et le sommet considéré.Ainsi, dans l’algorithme 7.1, l’instruction rajouter le sommet i à l’ensemble M est d’unecomplexité maximale qui s’exprime en O(log(|S|)). Cette instruction est réalisée |S| fois.

La boucle while tourne au plus |S| fois et réalise, entre autres, l’extraction du minimum du heap. Cetteopération s’exprime au pire en O(log(|S|)).

De plus, par les deux boucles imbriquées while et for nous parcourons, au total, une fois chaque arcdu graphe, et pour certains de ces arcs, nous modifions le heap en réalisant l’instruction dist[y]=vqui modifie la priorité du sommet y. Cette modification s’effectue avec une complexité maximale s’ex-primant en O(log(|S|)). Au pire, cela donne donc, pour l’ensemble des arcs considérés, une complexitéde l’ordre de O(|A| log(|S|)).

Au total, nous avons une complexité maximale qui s’exprime en :

O(|S| log(|S|) + |S| log(|S|) + |A| log(|S|)) = O(|S| log(|S|) + |A| log(|S|))

Et comme, au pire, |A| = |S|2, la complexité maximale peut s’exprimer en :

O(|A| log(|S|))

7.3 Tous les plus courts chemins

Nous avons vu à la section précédente une technique donnant comme résultat, pour un digraphe, tousles plus courts chemins à partir d’un sommet de départ. Néanmoins, on peut aussi désirer connaître,a posteriori, les plus courts chemins depuis n’importe quel sommet du digraphe vers tous les autressommets.

Pour réaliser ce calcul, nous pourrions réaliser une recherche des plus courts chemins, tel que réalisé parl’algorithme de Dijkstra, en partant tour à tour de chaque sommet du digraphe.

Une autre approche consiste en l’usage de la technique calculant la fermeture transitive du graphe,comme défini à la section 3.4.1. Nous rajoutons ici au graphe une information relative aux sommets xet y qui indique s’il existe un chemin allant du sommet x au sommet y. Des informations peuvent ainsiêtre spécifiées pour tous les couples de sommets du digraphe.

Nous avons déjà vu l’algorithme 3.1, présenté à la section 3.4.1, qui calcule la fermeture transitive d’ungraphe. Nous allons exploiter cette technique de construction de la fermeture transitive en considérantque s’il existe un moyen pour aller du sommet x au sommet y en n’utilisant que des sommets d’indiceinférieur ou égal à k-1 et s’il existe un moyen pour aller du sommet k au sommet y, alors il existe unmoyen pour aller du sommet x au sommet y en n’utilisant que des sommets d’indice inférieur ou égalà k. Il est ainsi espéré que le nouveau chemin considéré, passant par le sommet k, soit plus court quetous ceux déjà explorés. Il faut donc passer en revue tous les chemins possibles, sans cycle, entre chaquepaire de sommets.

Page 80: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 76Sur base de cela, nous pouvons construire, par exemple de la manière proposée par l’algorithme 7.2, untableau reprenant le plus court chemin de tout sommet x à tout sommet y du digraphe considéré.

Algorithme 7.2 Algorithme de Floyd

for(k=0 ; k < ordre du graphe ; ++k)for(x=0 ; x < ordre du graphe ; ++x)

if(mat[x][k] < infini)for(y=0 ; y < ordre du graphe ; ++y)if(mat[k][y] < infini)

if(mat[x][k]+mat[k][y] < mat[x][y])mat[x][y]=mat[x][k]+mat[k][y]

Le graphe est représenté, dans cet algorithme, par une matrice d’adjacence mat qui sera modifiée parl’algorithme de manière à finalement contenir les plus courts chemins entre tous les couples de sommetsdu digraphe. Initialement, nous trouvons en mat[x][y] le poids de l’arc allant du sommet x au sommety. Si cet arc n’existe pas, l’entrée correspondante de la matrice vaut l’infini.

Il est bien sûr nécessaire d’ajouter à l’algorithme de base utilisé, l’algorithme 3.1, un test détectantsi en passant par le sommet k, le chemin entre les sommets x et y s’améliore. C’est uniquement encas d’amélioration que la valeur de mat[x][y] est modifiée. Ce test est réalisé par l’avant-dernièreinstruction de l’algorithme.

A la fin de l’exécution de l’algorithme, pour tout couple de sommets x et y du digraphe, mat[x][y]contient la taille du plus court chemin allant du sommet x au sommet y.

Le trajet du plus court chemin entre deux sommets peut être reconstruit en utilisant une matrice supplé-mentaire qui retient en coordonnées (i,j) le nom du sommet précédant le sommet j sur le chemin dusommet i au sommet j.

La complexité maximale de cet algorithme s’exprime, comme nous l’avons déjà vu, en O(|S|3).

7.4 Plus courts chemins dans un DAG

Considérons à présent le cas particulier où un plus court chemin doit être trouvé dans un digrapheacyclique. Dans ce cas, nous allons constater que réaliser un tri topologique peut nous être d’une grandeaide.

Pour déterminer le plus court chemin depuis un sommet initial s jusqu’à un sommet x, il faut connaîtrele plus court chemin du sommet s jusqu’à chacun des prédécesseurs du sommet x. Ainsi, on ne traiteun sommet que si tous ses prédécesseurs sont traités. Nous sommes donc bien confrontés à un tri topo-logique.

L’idée est qu’une fois que tous les plus courts chemins entre le sommet de départ s et tous les prédé-cesseurs d’un sommet x sont connus, il est facile de déterminer le plus court chemin du sommet s ausommet x. Il suffit en effet, pour chaque prédécesseur y du sommet x, d’additionner la taille du pluscourt chemin entre les sommets s et y à la distance reprise sur l’arc entre les sommets y et x. Le résultatle plus petit indiquera le plus court chemin entre s et x.

L’algorithme de Bellman, illustré par l’algorithme 7.3, utilise donc un tri topologique. Pour réalisercelui-ci, nous devons pouvoir extraire le sommet le plus proche de l’origine, à partir de l’ensemble dessommets traitables (c’est à dire ceux dont tous les prédécesseurs ont été traités).

Page 81: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 77Algorithme 7.3 Algorithme de Bellman

dist[0 ... n-1] = +infinidist[s] = 0renuméroter les sommets dans l’ordre topologiquefor(int k=1 ; k < ordre du graphe ; ++k)

j = i tel que pour tous les arcs (i,k) dans le grapheon ait dist[i]+mat[i][k] qui soit minimum

dist[k] = dist[j]+mat[j][k]pred[k]=j

La réalisation du tri topologique nécessaire à la renumérotation des sommets est d’une complexité maxi-male s’exprimant en O(|S|+ |A|).

Au cours de la boucle for, nous passons en revue tous les sommets du DAG et, pour chaque sommet,nous regardons les arcs qui y mènent. Nous observons donc, au cours de cette boucle, au total unefois tous les arcs et une fois tous les sommets du DAG, la complexité maximale s’exprime donc enO(|S|+ |A|).

Cela nous donne bien une complexité maximale totale de l’algorithme s’exprimant en O(|S|+ |A|).

Si |S| est approximativement égal à |A|, ce qui semble une hypothèse raisonnable pour un DAG, alorscet algorithme pour la recherche de plus courts chemins dans un DAG est d’une complexité inférieure àcelle de Dijkstra.

Nous pouvons illustrer cette technique au moyen du graphe d’exemple suivant :

Page 82: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 78Après renumérotation nous obtenons le graphe :

On accède donc tour à tour aux sommets dans l’ordre de leur numérotation. Ensuite nous considérons,dans cet ordre, un à un les sommets du digraphe. Pour chaque sommet k ainsi considéré, nous sélec-tionnons l’arc (j,k) dont le poids plus la distance du sommet initial au sommet j est minimal. Nousindiquons alors que ce sommet k est accessible depuis le sommet initial par un chemin de longueurdist[j]+mat[j][k], et que le prédécesseur du sommet k sur ce plus petit chemin est le sommet j.

7.5 Digraphes ayant des poids négatifs

Si des poids négatifs apparaissent sur les arcs du digraphe, alors l’algorithme de Dijkstra ne fonctionneplus. Par exemple, considérons le digraphe suivant :

Nous constatons que l’algorithme de Dijkstra trouverait un chemin du sommet 0 au sommet 1 de lon-gueur 3 et un chemin du sommet 0 au sommet 2 de longueur 4. Alors que pour aller du sommet 0 ausommet 1 le plus court chemin passe par le sommet 2 et est de longueur 2.

L’algorithme de Dijkstra ne voit donc pas que pour aller du sommet 0 au sommet 1 le plus court cheminpasse par le sommet 2. La présence de poids négatifs peut avoir comme effet que les plus courts cheminsont tendance à avoir plus d’arcs que les plus courts chemins dans des graphes dont les arcs n’ont pas depoids négatif.

Page 83: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 79En effet, dans un graphe n’ayant que des poids positifs sur ses arcs, quand un sommet t est considéré, parl’algorithme de Dijkstra, comme faisant partie d’un plus court chemin, nous sommes sûr d’avoir trouvéla plus courte distance du sommet d’origine à ce sommet t. Si ce n’était pas le cas, cela signifieraitqu’il existerait un autre chemin allant du sommet d’origine au sommet t en passant par un sommet unon encore considéré. Or ce cas de figure ne peut se présenter car comme nous extrayons toujours leminimum de l’ensemble M, le sommet u est plus éloigné du sommet d’origine que l’est le sommet t.Passer par le sommet u pour aller du sommet d’origine au sommet t rallongerait donc la distance totale.Par contre, dans le cas de figure où des poids négatifs apparaissent sur les arcs, même si un sommet uest plus éloigné du sommet d’origine que le sommet t, il peut être avantageux de passer par ce sommetu puisque le plus court chemin du sommet u au sommet t pourrait être d’un poids total négatif.

Si le poids d’un cycle est la somme des poids des arcs qui le composent, alors un graphe ayant un cyclede poids négatif n’a pas de plus court chemin puisque tant que l’on tourne dans le cycle, le poids totaldu chemin, décroît alors que sa taille, en nombre d’arcs, augmente.

Nous considérons donc des graphes ayant des arcs de poids négatifs, mais sans cycle de poids négatif.Bellman et Ford ont proposé l’algorithme 7.4 qui calcule le plus court chemin depuis un sommet initialdu digraphe et qui retourne un booléen false si un cycle de poids négatif est présent dans le graphe.

L’algorithme fonctionne en associant les sommets et les arcs à des poids. Le poids d’un arc représente,comme précédemment, la distance entre les sommets aux extrémités de l’arc, et le poids d’un sommetreprésente la distance entre le sommet initial considéré du digraphe et le sommet en question.

L’algorithme passe en revue tous les arcs (u,v) du digraphe, en comparant le poids du sommet u ad-ditionné au poids de l’arc (u,v) avec le poids du sommet v. Si l’addition produit une valeur inférieureau poids du sommet v, nous modifions alors le poids du sommet v et nous indiquons dans un vecteurpred que le prédécesseur du sommet v sur le plus court chemin est le sommet u.

Ce traitement est réalisé autant de fois qu’il y a de sommets dans le digraphe moins un. En effet, dansun tel graphe, le chemin le plus long, si on néglige les cycles, est au plus égal au nombre de sommetsdans le digraphe moins un. Donc au premier tour de la boucle englobante on considère tous les cheminscomposés d’un arc. Puis, au tour suivant, on considère les chemins composés de deux arcs, puisqu’onajoute un arc aux chemins déjà considérés au tour précédent si la somme des poids de ces arcs donneun résultat inférieur, et donc une longueur de chemin inférieure, à ce qui était précédemment obtenu.Nous continuons à rajouter un arc à chaque tour de la boucle englobante, jusqu’à considérer les cheminspotentiels les plus longs, à savoir passant par tous les sommets, si cela est possible.

Page 84: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 80Algorithme 7.4 Algorithme de Bellman et Ford

mettre le poids de tous les sommets à +infinimettre le poids du sommet initial à 0

for(int i=1 ; i < ordre du graphe ; ++i)

for((u,v)=1er arc du graphe; (u,v) existe ; (u,v)=arc suivant)

val=poids du sommet u + poids de l’arc (u,v)if(val < poids du sommet v)

pred[v]=upoids du sommet v=val

for((u,v)=1er arc du graphe; (u,v) existe ; (u,v)=arc suivant)

if(poids du sommet u + poids de l’arc (u,v) < poids du sommet v)return(false)

return(true)

La dernière boucle de l’algorithme permet de détecter si le digraphe possède un cycle de poids négatifs.Pour ce faire, cette boucle simule le rajout d’un arc de plus sur les chemins et vérifie si les sommetsainsi atteint ne sont pas plus proche du sommet initial après ce rajout. Comme la partie précédente del’algorithme a considéré les chemins les plus longs, en nombre d’arcs, envisageables au cas où il n’yavait de cycle de poids négatif dans le digraphe, si cette dernière vérification indique la constructiond’un chemin plus court, en terme de longueur, cela signifie bien qu’un cycle de poids négatif est détecté.

L’initialisation est d’une complexité maximale en O(|S|), puis les deux boucles imbriquées tournent del’ordre de O(|S|) fois pour la boucle englobante et de l’ordre de O(|A|) pour la boucle imbriquée. Autotal cela nous donne une complexité maximale s’exprimant en O(|S| + |S||A|). Ce qui s’approximedonc par O(|S||A|).

Si nous considérons à nouveau le graphe d’exemple :

Au premier tour de boucle, nous considérons tour à tour :

– l’arc (0,1) et nous changeons le poids du sommet 1 par le poids du sommet 0 additionné au poids

Page 85: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 7 : Les plus courts chemins 81de l’arc (0,1), ce qui fait 0 + 3 = 3 <∞ ;

– l’arc (0,2) et nous changeons le poids du sommet 2 par le poids du sommet 0 additionné au poidsde l’arc (0,2), ce qui fait 0 + 4 = 4 <∞ ;

– l’arc (2,1) et nous changeons le poids du sommet 1 par le poids du sommet 2 additionné au poidsde l’arc (2,1), ce qui fait 4− 2 = 2 < 3.

A la fin de ce premier tour, les sommets du graphes sont donc pondérés comme ci-dessous :

Au second tour de boucle, nous considérons tour à tour :

– l’arc (0,1) et nous ne changeons pas le poids du sommet 1 car le poids du sommet 0 additionné aupoids de l’arc (0,1) donne 0 + 3 = 3 > 2, où le poids du sommet 1 vaut 2 ;

– l’arc (0,2) et nous ne changeons pas le poids du sommet 2 car le poids du sommet 0 additionné aupoids de l’arc (0,2) donne 0 + 4 = 4 = 4 et le sommet 2 a déjà un poids égal à 4 ;

– l’arc (2,1) et nous ne changeons pas le poids du sommet 1 car le poids du sommet 2 additionné aupoids de l’arc (2,1) donne 4− 2 = 2 et le sommet 1 a déjà un poids égal à 2.

Ainsi, le plus court chemin entre le sommet 0 et le sommet 1 est de longueur 2 et passe par le sommet2 ; et le plus court chemin entre le sommet 0 et le sommet 2 est de longueur 4.

Remarquons que si nous obtenons dans cet exemple les plus courts chemins dès la fin du premier tourde la boucle, cela est dû à l’ordre dans lequel nous avons considéré les différents arcs. Si nous avionsconsidérés les arcs dans l’ordre suivant (0,1), (2,1) et (0,2), nous aurions alors eu besoin desdeux tours pour retrouver les plus courts chemins.

7.6 Dernières remarques

Nous terminerons ce chapitre par une définition et une dernière remarque.

Le couple de sommets dans un digraphe qui est tel que le chemin entre les sommets de ce couple est leplus grand du digraphe définit le diamètre du digraphe. La valeur de ce diamètre est donc la longueur dece plus long chemin.

Remarquons enfin que si un DAG possède plusieurs sommets initiaux sans prédécesseur, nous pouvonsle modifier en lui ajoutant une source unique qui a comme successeurs les sources initiales et dont lesarcs ainsi ajoutés sont de poids nuls.

Page 86: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 8

Algorithmes génériques sur les graphes

8.1 Types d’algorithmes

Si nous faisons le point sur les différentes méthodes que nous avons étudiées ces deux dernières années,nous constatons qu’il existe différents types d’algorithmes organisés en fonction de la manière dont ilsconstruisent la ou les solutions à un problème.

Nous avons vu l’an passé des techniques réalisant, par exemple, des recherches exhaustives ou utilisant latechnique branch and bound. Nous avons aussi abordé la technique dite diviser pour résoudre lorsqu’unproblème peut être divisé en sous-problèmes solubles indépendemment. Nous avions alors généralisécette technique de diviser pour résoudre pour aboutir au concept de programmation dynamique, où desinformations intermédiaires utiles à la construction de la solution sont sauvegardées afin de ne pas devoirles recalculer plus d’une fois.

Nous venons aussi de voir, avec le problème du flot maximum, la technique par chemins augmentants.

Un autre type d’algorithmes se base sur la technique consistant à ajouter successivement des éléments àune solution en cours de construction, suivant des critères précis, jusqu’à obtenir une solution complèteoptimale. C’est ce qu’on appelle un algorithme glouton.

Les algorithmes Monte Carlo tirent parti du hasard. Par exemple, dans le cas d’un graphe, on pourraitchoisir un sommet, un arc ou une arête au hasard et si cet élément semble solutionner le problème posé,on le prend, sinon on réessaye avec un autre élément choisi aléatoirement. Il faut noter que cette méthodene garantit pas toujours qu’une solution sera trouvée.

8.2 Algorithmes gloutons

Il apparaît clairement que de nombreux algorithmes vus cette année sont des algorithmes gloutons. Celase transparaît d’autant plus si nous considérons l’algorithme 8.1 ci-dessous.

Page 87: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 8 : Algorithmes génériques sur les graphes 83Algorithme 8.1 Canevas générique pour certains algorithmes gloutons

for(int i=0; i < ordre du graphe ; ++i)val[i]=-infini

prec[0]=0mettre (0,0) sur le heap

for (int n=1 ; heap n’est pas vide ; ++n)

s=extraire le minimum du heapval[s]=-val[s]t=premier successeur du sommet swhile(t existe)

if(val[t] < 0)

insérer (t,Prior) sur le heapif(heap a été modifié)

val[t]=-Priorprec[t]=s

t=successeur suivant de s

Si nous considérons que nous travaillons sur un graphe, dans cet algorithme, quand val[t] vaut −∞,cela signifie que le sommet t n’a pas encore été rencontré et n’est donc pas encore dans la frange. Sival[t] vaut -i (avec i > 0) cela signifie que la priorité du sommet t vaut i mais qu’il n’a pas encoreété traité. Et enfin, si val[t] est plus grand ou égal à zéro cela signifie que le sommet t est traité.

L’algorithme utilise un vecteur prec tel que prec[s] vaut t si le sommet t est le sommet prédéces-seur du sommet s dans la solution qui est en cours de construction.

Nous utilisons aussi un heap. Une insertion d’un élément dans ce heap ajoute un élément s’il n’y est pasdéjà, ou déplace un élément s’il était déjà dans le heap mais que sa priorité s’améliore.

L’algorithme se base enfin sur une variable nommée Prior qui modifie la manière dont l’algorithmefonctionne. Plus précisément, cette variable va agir sur la priorité des éléments qui vont être insérés dansle heap.

Cet algorithme réalise donc une initialisation nécessitant O(|S|) opérations.

Ensuite, une boucle tournant |S| fois est réalisée. Dans cette boucle, on extrait un minimum du heap, enO(log |S|) opérations, puis on considère un à un les différents arcs ou arêtes du graphe, ce qui représente,au total des tours de la boucle, O(|A|) opérations, et enfin, au pire, pour chaque arc ou arête on modifiele heap, ce qui représente à nouveau O(log |S|) opérations.

Nous avons donc une complexité maximale qui s’exprime en :

O(|S|+ |S| log |S|+ |A| log |S|)

Page 88: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 8 : Algorithmes génériques sur les graphes 84Ce qui donne :

O(|S| log |S|+ |A| log |S|)

A nouveau, dans un pire cas, si le graphe est dense, nous avons |A| = |S|2 ou |A| = |S|(|S|+ 1)/2, lacomplexité maximale vaut alors aussi O(|A| log |S|).

8.2.1 Parcours en largeur

Que le graphe soit dirigé ou non, si Prior vaut le contenu de la variable n de la boucle for, alorscet algorithme réalise un parcours en largeur, car Prior ne fait que croître, le heap peut alors être vucomme une simple file.

Nous pouvons, pour illustrer cela, partir du digraphe suivant :

Lors du parcours, le heap contiendra successivement les éléments suivants, où chaque couple (a,b)présent dans le heap est tel que a est le numéro du sommet et b la priorité de ce sommet :

Nous extrayons donc itérativement du heap les sommets 0, 1, 2, 3, 6, 5 et 4, ce qui représente bien unparcours en largeur du digraphe considéré.

Le vecteur prec représente donc, en fin d’algorithme, l’arbre du parcours. Les arcs y apparaissant sontles arcs empruntés pour passer, pour la première fois, d’un sommet au sommet suivant.

8.2.2 Parcours en profondeur

A nouveau, que le graphe soit dirigé ou non, si Prior vaut la différence entre l’ordre du graphe et lecontenu de la variable n de la boucle for, alors cet algorithme réalise un parcours en profondeur. En

Page 89: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 8 : Algorithmes génériques sur les graphes 85effet, Prior ne fait que décroître, le heap peut alors être vu comme une pile.

Nous pouvons, pour illustrer cela, partir du digraphe suivant :

Lors du parcours, le heap contiendra successivement les éléments suivants :

Nous extrayons donc itérativement du heap les sommets 0, 1, 4, 5, 2 et 3, ce qui représente bien unparcours en profondeur du digraphe.

Le vecteur prec représente donc à nouveau, en fin d’algorithme, l’arbre du parcours.

8.2.3 Arbre sous-tendant minimum

Pour un graphe non dirigé, si Prior vaut le poids de l’arête présente entre les sommets s et t consi-dérés dans l’algorithme, alors la construction d’un arbre sous-tendant minimal est réalisé en suivant latechnique de Prim. En effet, on extrait systématiquement du heap le sommet le plus proche de l’arbresous-tendant en construction.

Nous pouvons illustrer cela à partir du graphe non dirigé pondéré suivant :

Page 90: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 8 : Algorithmes génériques sur les graphes 86

Lors de la construction de l’arbre, le heap contiendra successivement les éléments suivants :

Nous extrayons donc itérativement du heap les sommets 0, 1, 2, 4 et 3, le vecteur prec représentealors l’arbre sous-tendant suivant de poids total égal à 9 :

8.2.4 Plus court chemin

Enfin, pour un digraphe, si Prior vaut le poids de l’arc présent entre les sommets s et t considérésdans l’algorithme, additionné au contenu de val[s], alors une recherche des plus courts chemins estréalisée suivant la méthode de Dijkstra. En effet, pour tout sommet x, la valeur de val[x] sera alorsla distance entre le sommet initial du digraphe et le sommet x. Notons aussi que contrairement auxinstanciations précédentes, lorsque nous traitons le sommet initial 0, nous devons initialiser val[0] àzéro.

Nous pouvons, pour illustrer cela, partir du digraphe pondéré suivant :

Lors de la construction de l’arbre, le heap contiendra successivement les éléments suivants :

Page 91: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Chapitre 8 : Algorithmes génériques sur les graphes 87

Nous extrayons donc itérativement du heap les sommets 0, 1, 2, 3 et 4, le vecteur prec représentealors l’arbre des plus courts chemins suivant :

8.2.5 Conclusion

Pour conclure, remarquons que l’algorithme générique que nous venons de voir ne s’adapte qu’à certainsalgorithmes gloutons. Nous avons, en effet, vu d’autres algorithmes gloutons, tels que l’algorithme deKruskal ou le tri topologique qui ne s’instancient pas aisément à partir du canevas considéré.

Page 92: INFO-F-203 : Algorithmique 2 - Université libre de …homepages.ulb.ac.be/~bfortz/ag2.pdfChapitre 1 : Introduction aux tables de hachage 2 FIGURE 1.1 – Implémentation d’un ensemble

Bibliographie

[1] Thomas Cormen, Charles Leiserson, Ronald Rivest and Clifford Stein, Introduction to Algorithms,third edition, The MIT Press.

[2] Robert Sedgewick, Algorithmes en langage C : cours et exercices, édition de 2001, Dunod

[3] Robert Sedgewick, Algorithms in C++, second edition, Addison Wesley

[4] Robert Sedgewick, Algorithms in C++, third edition, Addison Wesley