Option Informatique 2 e année
Judicaël Courant 29 novembre 2016
1 Introduction
Les problèmes algorithmiques auxquels on veut s’intéresser : 1. Recherche des composantes connexes d’un graphe non-orienté.
2. Recherche du chemin le plus court entre deux points dans un graphe pondéré.
1. Quelles sont les opérations dont on a besoin sur les graphes ? 2. Quelles sont les implantations envisageables ?
3. Quelles sont leurs complexités ?
2 Opérations
Pour simplifier, on considérera :
1. Que le nombre de sommets est fixé.
2. Que les sommets sont représentés par des entiers.
On va commencer par les graphesorientés, plus faciles à représenter.
type sommet == i n t ; ; type g r a p h e ; ;
(∗ Opé r a t i o n s de c o n s t r u c t i o n ∗)
(∗ c r e a t e n : c r é e un g r a p h e de sommets { 0 , . . . , n−1} s a n s a r c
∗)
value c r e a t e : i n t −> g r a p h e ; ; value a j o u t e _ a r e t e :
g r a p h e −> sommet −> sommet −> u n i t ; ; value e n l e v e _ a r e t e :
g r a p h e −> sommet −> sommet −> u n i t ; ; (∗ Opé r a t i o n s de t e s t ∗)
value a r e t e _ p r e s e n t e :
g r a p h e −> sommet −> sommet −> b o o l ; ;
(∗ Opé r a t i o n s de p a r c o u r s ∗)
(∗ I t é r a t i o n s u r l e s s u c c e s s e u r s d ’ un sommet ∗) value i t e r _ s u c c :
( sommet −> u n i t ) −> g r a p h e −> sommet −> u n i t ; ;
(∗ I t é r a t i o n s u r l ’ e n s e m b l e d e s a r ê t e s ∗) value i t e r _ a r e t e s :
( sommet −> sommet −> u n i t ) −> g r a p h e −> u n i t ; ;
(∗ On p e u t v o u l o i r l a l i s t e d e s s u c c e s s e u r s d ’ un sommet : ∗) value s u c c _ l i s t : g r a p h e −> sommet −> sommet l i s t ; ;
3 Implantations envisageables
Il y en a beaucoup. On va commencer par les deux classiques : 1. Représentation par graphe d’adjacence.
2. Représentation par liste d’adjacence.
3.1 Par graphe d’adjacence
Étant donné un graphe G = (S, A) où S = [[0, n[[, la matrice d’adjacence de G est la matrice [[aij[[(i,j)∈[[0,n[[2 telle que pour tout (i, j)∈[[0, n[[2,aij vaut vrai si une arête relie iàj et faux sinon1
La matrice d’adjacence caractérise le graphe de façon unique.
type g r a p h e == b o o l v e c t v e c t ; ;
l e t c r e a t e n = make_matrix n n f a l s e ; ;
l e t a j o u t e _ a r e t e g s 1 s 2 = g . ( s 1 ) . ( s 2 ) <− t r u e ; ; l e t e n l e v e _ a r e t e g s 1 s 2 = g . ( s 1 ) . ( s 2 ) <− f a l s e ; ; l e t a r e t e _ p r e s e n t e g s 1 s 2 = g . ( s 1 ) . ( s 2 ) ; ;
l e t i t e r _ s u c c f g s 1 =
f o r s 2 = 0 to v e c t _ l e n g t h g . ( s 1 ) − 1 do i f g . ( s 1 ) . ( s 2 ) then f s 2
done; ;
l e t i t e r _ a r e t e s f g =
f o r s 1 = 0 to v e c t _ l e n g t h g − 1 do i t e r _ s u c c (fun s 2 −> f s 1 s 2 ) g s 1 done; ;
(∗ NB : l ’ i m p l a n t a t i o n de s u c c _ l i s t e s t i n d é p e n d a n t e de l a r e p r é s e n t a t i o n c h o i s i e pour l e s g r a p h e s . ∗)
l e t s u c c _ l i s t g s = l e t r = r e f [ ] in
i t e r _ s u c c (fun s ’ −> r := s ’ : : ! r ) g s ; ; Complexité des opérations en temps :
Ajout d’arête O(1) Retrait d’arête O(1)
1. Chez certains auteurs : 1 et 0 à la place de vrai et faux.
Test O(1).
Parcours des successeurs O(|S|).
Parcours des arêtes O(|S|2).
Coût de la représentation mémoire : O(|S|2).
3.2 Par listes d’adjacence
On représente le graphe par un tableaut de |S| listes de sommets, tel que pour tout sommets, t.(s) est la liste des successeurs des.
type g r a p h e == sommet l i s t v e c t ; ;
l e t c r e a t e n = make_vect n [ ] ; ;
l e t a r e t e _ p r e s e n t e g s 1 s 2 = list__mem s 2 g . ( s 1 ) ; ; l e t a j o u t e _ a r e t e g s 1 s 2 =
i f not ( a r e t e _ p r e s e n t e g s 1 s 2 ) then g . ( s 1 ) <− s 2 : : g . ( s 1 ) ; ;
l e t e n l e v e _ a r e t e g s 1 s 2 = g . ( s 1 ) <− e x c e p t s 2 g . ( s 1 ) ; ;
l e t i t e r _ s u c c f g s 1 = d o _ l i s t f g . ( s 1 ) ; ;
l e t i t e r _ a r e t e s f g =
f o r s 1 = 0 to v e c t _ l e n g t h g − 1 do i t e r _ s u c c (fun x −> f s 1 x ) g s 1 done; ;
Complexité des opérations en temps : Ajout d’arête O(d)
Retrait d’arête O(d) Test O(d).
Parcours des successeurs O(d).
Parcours des arêtes O(|A|+|S|).
Coût de la représentation mémoire : O(|A|+|S|).
NB :
1. O(|A|+|S|) et O(max(|A|,|S|)) désignent la même classe asymptotique.
2. On a toujours |A| ≤ |S|2. Informellement, si |A| est proche de |S|2, on dit que le graphe est dense.
3.3 Autres représentations possibles
Listes d’adjacences : inefficacités dues aux listes (ajout/test/suppression linéaires).
On pourrait utiliser des ensembles d’adjacences, implantés de façon efficace (par exemple tables de hachage). On aurait alors
type sommet == i n t ; ;
type ’ a e n s e m b l e == ( ’ a , ( ) ) hashtbl__t ; ; type g r a p h e == sommet e n s e m b l e v e c t ; ;
Remarquez qu’on peut alors en profiter :
1. Pour associer une valeur à chaque arête (graphes pondérés).
2. Pour remplacer aussi le tableau d’ensembles par une table de hachage ce qui ajoute la possibilité a) d’ajouter/retirer des sommets ;
b) d’avoir un type de sommets arbitraire.
type ( ’ sommet , ’ p o i d s ) g r a p h e ; ;
value c r e a t e : u n i t −> ( ’ s , ’ p ) g r a p h e ; ;
value ajoute_sommet : ( ’ s , ’ p ) g r a p h e −> ’ s −> u n i t ; ; value enleve_sommet : ( ’ s , ’ p ) g r a p h e −> ’ s −> u n i t ; ;
value a r e t e _ p r e s e n t e :
( ’ s , ’ p ) g r a p h e −> ’ s −> ’ s −> b o o l ; ;
(∗ l è v e Not_found s i l ’ a r ê t e e s t a b s e n t e du g r a p h e ∗) value p o i d s _ a r e t e :
( ’ s , ’ p ) g r a p h e −> ’ s −> ’ s −> ’ p ; ; value a j o u t e _ a r e t e :
( ’ s , ’ p ) g r a p h e −> ’ s −> ’ s −> ’ p −> u n i t ; ; value e n l e v e _ a r e t e :
( ’ s , ’ p ) g r a p h e −> ’ s −> ’ s −> u n i t ; ;
value i t e r _ s u c c : ( ’ s −> ’ p −> u n i t ) −> ( ’ s , ’ p ) g r a p h e −> ’ s −> u n i t ; ; value i t e r _ a r e t e s : ( ’ s −> ’ s −> ’ p −> u n i t ) −> ( ’ s , ’ p ) g r a p h e −> u n i t ; ; (∗ e n s e m b l e s d ’ a d j a c e n c e ∗)
type ( ’ s , ’ p ) ens_adj == ( ’ s , ’ p ) hashtbl__t ; ;
type ( ’ s , ’ p ) g r a p h e ==
( ’ s , ( ’ s , ’ p ) ens_adj ) hashtbl__t ; ;
l e t c r e a t e _ h ( ) = hashtbl__new 1 9 7 3 ; ;
l e t c r e a t e ( ) = c r e a t e _ h ( ) ; ;
l e t ajoute_sommet g s =
hashtbl__add g s ( c r e a t e _ h ( ) ) ; ;
(∗ TODO : e n l e v e r a r ê t e s e n t r a n t e s e t s o r t a n t e s ∗) l e t enleve_sommet g s = hashtbl__remove g s ; ;
(∗ s u c c : ( ’ s , ’ p ) g r a p h e −> ’ s −> ( ’ s , ’ p ) ens_adj Retourne l e s s u c c e s s e u r s d ’ un sommet ∗)
l e t s u c c g s = h a s h t b l _ _ f i n d g s ; ;
l e t p o i d s _ a r e t e g s 1 s 2 =
h a s h t b l _ _ f i n d ( s u c c g s 1 ) s 2 ; ;
l e t a r e t e _ p r e s e n t e g s 1 s 2 =
try l e t _ = p o i d s _ a r e t e g s 1 s 2 in t r u e with
| Not_found −> f a l s e ; ;
l e t e n l e v e _ a r e t e g s 1 s 2 =
hashtbl__remove ( s u c c g s 1 ) s 2 ; ;
l e t a j o u t e _ a r e t e g s 1 s 2 p = hashtbl__add ( s u c c g s 1 ) s 2 p
; ;
l e t i t e r _ s u c c f g s = l e t e = s u c c g s in hashtbl__do_table f e
; ;
l e t i t e r _ a r e t e s f g = l e t t r a i t e _ s o m m e t s 1 e =
hashtbl__do_table (fun s 2 p −> f s 1 s 2 p ) e in hashtbl__do_table t r a i t e _ s o m m e t g
; ;
Si on fait l’hypothèse que pour une table de hachage contenantn éléments : 1. Le temps d’accès/modification est un O(1) ;
2. L’espace mémoire utilisé est en O(n).
Alors, la complexité des opérations en temps est : Ajout d’arête O(1)
Retrait d’arête O(1) Test O(1).
Parcours des successeurs O(d).
Parcours des arêtes O(|A|+|S|).
Ajout de sommet O(1).
Retrait de sommet O(1) (retrait sous réserve d’avoir retiré les arêtes entrantes et sortantes) Coût de la représentation mémoire : O(|A|+|S|).