Vous êtes sur la page 1sur 29

Graphes

G= (V, E)
• sommet (vertex)
j 5
1 3 • arête (edge)
• (orientée, multiple,
a i boucle)

e • Degré d’un sommet


0 c 6
f • Sommets adjacents
b (voisins)
h • Chemin (simple)
2 4
d g • Cycle (simple)
7
• Graphe connexe
Propriétés
Notations
n nombre de sommets
m nombre d'arêtes
deg(v) degré du sommet v

n – 1  m  n(n – 1)/2
1  di  n – 1 Pour un graphe non-orienté,
sans boucles ou arêtes multiples
TAD Graphes
Liste Liste Matrice
arêtes adjacence adjacence
ej=get arête (vi, vk) O(m) O(d) O(1)
(vi, vk) =get sommets (ej) O(1) O(m) O(n2)
vk =get sommet opposé (vi,ej)
{vn } =get voisins (vi) O(m) O(dm) O(n)
Parcourir les arêtes O(m) O(m) O(n2)
Parcourir les sommets O(n) O(n) O(n)
Ajouter arête (ek,vi,vj) O(1) O(1) O(1)
Ajouter sommet (vi) O(1) O(1) O(n2) n noeuds
Retirer arête (ej) O(1) O(m) O(1) m arêtes
d degré
Retirer sommet (vi) O(m) O(dm) O(n2)
Liste d’arêtes

a b c d e f g h i j

0 1 2 3 4 5 6 7
Liste d’adjacence
0 a b
j 5
1 a j 1 3
2 b c d a i

3 c e j e
0 c 6
4 d e f g f
b
5 i h
2 4
6 f h i d g 7
7 g h
Matrice d’adjacence
0 1 2 3 4 5 6 7
0 a b

1 a

2 b c

3 c

4
5
6
7
0 1 2 3 4 5 6 7 8 9
0 1 1 1 0 0 0 0 0 0
1 0 0 0 0 1 0 0 0
2 0 1 1 0 0 0 0
3 0 0 0 0 0 0
4 1 0 0 1 1
5 0 0 1 0
6 1 0 0
7 1 0
8 0
9
Parcours de graphe
0 a b
j 5
1 a j 1 3
2 b c d a i

3 c e j e
0 c 6
4 d e f g f
b
5 i h
2 4
6 f h i d g 7
7 g h
Parcours de graphe
DFS(v, G, P) {
visite(v)
0 a b arbre = {}
for all e in G.getAretes(v)
1 a j P.empile(e)

2 b c d while !P.vide() {
e= P.dépile()
3 c e j (w,w’)= G.getSommets(e)
if !G.visité(w)
4 d e f g v= w Parcours
if !G.visité(w’) en profondeur
5 i v= w’
if !G.visité(v) {
6 f h i visite(v)
arbre = arbre U {e} Ici un arbre de
7 for all e in G.getAretes(v) recouvrement est
g h P.empile(e) généré
}
}
Parcours de graphe
BFS(v, G, F) {
visite(v)
0 a b arbre = {}
for all e in G.getAretes(v)
1 a j F.enfile(e)

2 b c d while !F.vide() {
e= F.défile()
3 c e j (w,w’)= G.getSommets(e)
if !G.visité(w)
4 d e f g v= w Parcours
if !G.visité(w’) en largeur
5 i v= w’
if !G.visité(v) {
6 f h i visite(v)
arbre = arbre U {e} Ici un arbre de
7 for all e in G.getAretes(v) recouvrement est
g h P.enfile(e) généré
}
}
Parcours de graphe
0 a b
1 a j
2 b c d DFS(v, G) {
visité(v)
3 c e j for all e in G.getAretes(v) {
w= e.getSommetOpp(v)
4 if !G.visité(w) { Parcours
d e f g
arbre = arbre U {e}
DFS(w,G)
en profondeur
5 i récursif
}
}
6 f h i } Ici un arbre de
7 g h recouvrement est
généré
Parcours complet de graphe non-connexe
Algorithm DFS(G)
Entrée graphe G
Sortie étiquetage des arêtes de G j 5
1 3
comme arêtes découvertes a i
et arêtes de retour
for all u  G.vertices() c
0 6
setLabel(u, UNEXPLORED) f
for all e  G.edges() b
setLabel(e, UNEXPLORED) h
2 4
for all v  G.vertices() g 7
if getLabel(v) =
UNEXPLORED
DFS(G, v)
Parcours de graphe récursif (en profondeur)
Algorithm DFS(G, v)
Entrée graphe G et un sommet de
début v de G j 5
Sortie étiquetage des arêtes de G 1 3
dans a i
le composant connexe de
v
setLabel(v, VISITED) 0 c 6
f
for all e  G.incidentEdges(v) b
if getLabel(e) = UNEXPLORED h
w  opposite(v,e) 2 4
if getLabel(w) = g 7
UNEXPLORED
setLabel(e,
DISCOVERY)
DFS(G, w)
else
Recherche d’un chemin?
Algorithm DFS(G, S, v, z) 8 m
setLabel(v, VISITED) S.push(v)
if (v==z) S.save()
k
j 5
for all e  G.incidentEdges(v) 1 3 n
if getLabel(e) = UNEXPLORED a
w  opposite(v,e)
if getLabel(w) = c e
UNEXPLORED 0 6
f
setLabel(e, b
DISCOVERY) S.push(e) h
2 4
d g
DFS(G,S,w,z) S.pop() 7

else
S.pop()
setLabel(e, BACK)
Recherche d’un cycle?
Algorithm DFS(G, v, z) 8 m
setLabel(v, VISITED) S.push(v)
k
j 5
for all e  G.incidentEdges(v) 1 3 n
if getLabel(e) = UNEXPLORED a
w  opposite(v,e)
S.push(e) c e
0 6
if getLabel(w) = f
UNEXPLORED
setLabel(e, h
DISCOVERY) 2 4
d g
DFS(G, w) S.pop() 7
C  new Cycle
C.add(S.pop())
else Do
setLabel(e, BACK) S.pop() o= P.pop()
C.add(o)
While (o=w)
Parcours de graphe en largeur
Algorithm BFS(G, s) m
8
L0  nouvelle séquence vide k
L0.insertLast(s) 5
j
setLabel(s, VISITED)
i0
1 3 n
while ! Li.isEmpty() a
Li +1  nouvelle séquence vide
for all v  Li.elements() c e
for all e  G.incidentEdges(v) 0 f
6
if getLabel(e) = UNEXPLORED b
w  opposite(v,e) h
if getLabel(w) = 2 4
UNEXPLORED d g
setLabel(e, 7
DISCOVERY)
setLabel(w,
VISITED)
Li +1.insertLast(w)
else
setLabel(e, CROSS)
Plus court chemin dans un graphe
• Objectif: trouver le plus court chemin entre
deux sommets dans un graphe pondéré
• Si le graphe n’est pas pondéré (minimiser le 8
nombre de visite de sommets), la solution 1 3
est le parcours en largeur 2
• Nous calculons en fait le plus court chemin
entre un sommet et tous les autres 7 4 6
0
• Tous les sous-chemins sont aussi des plus
courts chemins
• L’ensemble de ces plus courts chemins 3
2 4
forme un arbre 2
Algorithme de Dijkstra

• C’est un algorithme glouton qui procède en 4 étapes afin de trouver


Plus court chemin dans un graphe
8
2
7
2 5
1 3 3
2
5

1 5 3
0 6

6
4 1
2 4
6
3 7
Algorithme de Dijkstra
Algorithm ShortestPath(G, v):
Entrés : Un graphe pondéré G et un sommet particulier v de G.
Sortie : Une étiquette D[u], pour chaque sommet u de G, telle que
D[u] est la longueur d'un plus court chemin de v à u dans G.

initialise D[v]  0 et E[v]  null


D[u]  ∞ et E[u]  null pour chaque sommet v  u
T=
Soit Q une file à priorité qui contient tous les sommets de G
utilisant les étiquettes de D comme clés .
while Q   do {insérer u dans le nuage C}
u  Q.removeMinElement()
ajouter E[u] à T
pour chaque sommet z adjacent à u tel que z est dans Q faire
{exécuter l'opération de relaxation sur l’arête (u, z) }
Si D[u] + w((u, z)) < D[z] alors
D[z] D[u] + w((u, z))
changer la valeur de la clé de z dans Q à D[z]
E[u]= (u,z)
Retourner l’arbre T et l’étiquette D[u] de chaque sommet u.
Algorithme de Dijkstra
D 0 8 2 3 5 11
A B C D E F

0
8 A 4
2 (C,D) 3
8 7 2 1 3
B C D
3 9 (A,B) 8 (C,E) 5
5 8
2 5 Monceau
E F Juste avant d’insérer
Le sommet D
(C,F) 11
Après insertion
de D, il faut relaxer
le sommet avec (D,F) à 8
Arbre couvrant minimum
7 D
B 4
• Arbre couvrant de G 5
9
F
2
• Sous-graphe de G contenant tous les sommets deC G 8
8 3
• Sans cycles, donc formant un arbre 7 E
A
• Arbre couvrant minimum (ACM) d’un graphe pondéré
• Arbre couvrant ayant la somme minimale des poids des arêtes
choisies
Arbre couvrant minimum

• Propriété des cycles

8 f 8
f
4 4
C C 9
9 6
2 6 2
3 3 e
e 7
8 7 8

7 7

Si on créé un cycle en ajoutant une arête externe e à l’ACM,


alors toutes les arêtes de ce cycle ont un poids inférieur à e
Arbre couvrant minimum
• Propriété de partition
U V U
8 f 8
f
4 4
9 9
5 2 5
2 8
8
8 3 8 e 3
e
7 7
V

Si on partitionne le graphe G en deux sous-graphes alors l’arête e


de poids minimal qui joint les 2 sous-graphes fait partie de l’ACM
Algorithme de Prim Jarnik
Algorithm PrimJarnik(G):
Entrés : Un graphe pondéré G et un sommet particulier v de G.
Sortie : Une étiquette D[u], pour chaque sommet u de G, telle que
initialise D[v]  0 et E[v]  null
D[u]  ∞ et E[u]  null pour chaque sommet v  u
T=
Soit Q une file à priorité qui contient tous les sommets de G
utilisant les étiquettes de D comme clés .
while Q   do {insérer u dans le nuage C}
u  Q.removeMinElement()
ajouter E[u] à T
pour chaque sommet z adjacent à u tel que z est dans Q faire
{exécuter l'opération de relaxation sur l’arête (u, z) }
Si w((u, z)) < D[z] alors
D[z] w((u, z))
changer la valeur de la clé de z dans Q à D[z]
E[u]= (u,z)
Retourner l’arbre T et l’étiquette D[u] de chaque sommet u.
Arbre couvrant minimum d’un graphe pondéré
8
2
7
2 5
1 3
3
2
5

1 5 3
0 6

6
4 1
2 4
6
3 7
Algorithme de Kruskal

• On peut aussi utiliser la propriété de partition


• Tous les sommets sont initialement places chacun dans une
partition
• A chaque iteration, l’arête de poids minimal joingnant deux
partitions est ajoutée à l’ACM
• Jusqu’à ce que tous les sommets se retrouvent dans la même
partition
Arbre couvrant minimum d’un graphe pondéré
8
2
7
2 5
1 3
3
2
5

1 5 3
0 6

6
4 1
2 4
6
3 7
Algorithme de Kruskal
Algorithm Kruskal(G):
Entrée: Un graphe pondéré G.
Sortie: Un ACM T pour G.
Soit P une partition des sommets de G, où chaque sommet est dans un ensemble séparé.
Soit Q une file à priorité gardant en mémoire les arêtes de G, ordonnées selon leur poids
Soit T un arbre initialement vide
Tant que T contient moins que n-1 arêtes faire
(u,v)  Q.removeMinElement()
Si P.find(u) != P.find(v) alors
Ajouter (u,v) à T
P.union(u,v)
retourner T

Vous aimerez peut-être aussi