SlideShare une entreprise Scribd logo
1  sur  22
Télécharger pour lire hors ligne
Graphs & Algorithmie : Recherches sur l’implémentation
des algorithmes liés à Dijkstra et au problème des K-plus
courts chemins
Arthur Van de Wiele
Louis Thibon
25 Janvier 2011
Table des matières
1 Structures de donnée et outils divers 2
1.1 Graphviz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Conversion d’une méthode de saisie simple vers graphviz . . . . . . . . . . . . . . . 3
1.3 Structure de donnée liée au stockage du graphe . . . . . . . . . . . . . . . . . . . . 6
1.4 Structure de donnée liée à l’algorithme de Dijkstra . . . . . . . . . . . . . . . . . . 6
1.5 Structure de donnée nécessaire à l’algorithme des k-plus courts chemins . . . . . . 7
2 Problème du plus court chemin 9
2.1 Présentation du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Analyse de l’algorithme de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Commentaires sur l’implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4 Fonctions utiles à l’affichage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.1 Fonction nécessaire à l’obtention du code Graphviz . . . . . . . . . . . . . . 10
2.4.2 Fonction d’affichage des tableaux liés à la structure de donnée spécifique à
Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Fonctions spécifiques au structures de données utilisées . . . . . . . . . . . . . . . . 11
2.5.1 Fonction de génération du graphe . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5.2 Fonction d’affichage des tableaux liés à la structure de donnée spécifique à
Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 Fonctions utiles à l’algorithme de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . 13
2.6.1 Fonction retournant le poids de l’arc entre deux sommets . . . . . . . . . . 13
2.6.2 Trouver la distances minimum depuis le tableau des distances . . . . . . . . 13
2.6.3 Fonction permettant de retrouver les successeurs d’un sommet . . . . . . . 14
2.6.4 Fonction de verrouillage des deux tableaux . . . . . . . . . . . . . . . . . . 14
2.6.5 Initialisation nécessaire à l’algorithme de Dijkstra . . . . . . . . . . . . . . . 14
2.6.6 L’algorithme en lui même . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.6.7 La fonction main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3 Problème des K-plus courts chemins 18
3.1 Présentation du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2 Analyse de l’algorithme des k-plus court chemins . . . . . . . . . . . . . . . . . . . 19
3.3 Commentaires sur l’implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.3.1 Fonction d’affichage de l’arbre . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.3.2 Fonction de création des nœuds des successeurs . . . . . . . . . . . . . . . . 20
3.3.3 Fonction algorithme des k plus court chemins . . . . . . . . . . . . . . . . . 21
1
Chapitre 1
Structures de donnée et outils divers
1.1 Graphviz
Graphviz est une suite d’utilitaires sous système Unix qui permet de tracer le visuel d’un graphe
donné à partir d’un structure de donnée (langage) propre à Graphviz. Il est donc possible de créer
un utilitaire simple pour convertir une structure de graphe simpliste en langage interprétable par
un des programmes de Graphviz : “dot”.
Le langage interprétable par Graphviz se présente comme suite :
1 digraph G
2 {
3 edge [ color=purple , arrowsize =2];
4 node [ color=pink , s t y l e=f i l l e d ] ;
5 0 −> 1 [ l a b e l =1];
6 0 −> 3 [ l a b e l =2];
7 1 −> 2 [ l a b e l =3];
8 1 −> 3 [ l a b e l =4];
9 2 −> 3 [ l a b e l =5];
10 }
Ce qui permet d’obtenir le tracé suivant :
Figure 1.1 – Exemple de grape obtenu à l’aide des outils de Graphviz
2
Mais cet utilitaire prend tous son sens lors de tracés de graphes plus importants, lorsque le
tracé devient réellement fastidieux, comme dans cet exemple :
Figure 1.2 – Second exemple de graphe obtenu à l’aide des outils de Graphviz
1.2 Conversion d’une méthode de saisie simple vers graphviz
Le langage qu’interprète Graphviz implique certaines redondances dans son écriture. Afin de
faciliter l’écriture d’un graphe, nous avons développé un petit utilitaire travaillant sur une méthode
de saisie simple qui permet d’obtenir instantanément un code de type Graphviz.
Le méthode de saisie que nous avons souhaité utilisé se construit comme suit : Chaque ligne cor-
respond à un sommet suivi du nombre et de la liste de ses successeurs avec l’affectation du poids
de l’arc entre eux. Pour plus de facilité, la première ligne doit comporter le nombre de sommets
du graphe. Ce qui se traduit par l’écriture suivante pour le cas de la figure 1.1 :
1 4
2 0 2 1 1 3 2
3 1 2 2 3 3 4
4 2 1 3 5
5 3 0
Le code source de ce programme est donné ci après. Les explications se trouvent à la suite du
code.
3
1 #include <stdio . h>
2 #include <s t d l i b . h>
3 #include <s t r i n g . h>
4
5 // Structure de donnee permettant d ’ obtenir des l i s t e s chainees
6 typedef struct l i s t e l i s t e ;
7 struct l i s t e
8 {
9 int noeud ;
10 int poid ;
11 l i s t e ∗ suiv ;
12 };
13
14 int main ( int argc , char ∗argv [ ] )
15 {
16
17 // Ouverture du f i c h i e r comportant l e code s i m p l i f i e du graphe .
18 FILE∗ src_graph=fopen ( argv [ 1 ] , " r " ) ;
19
20 // Afin de ne pas surcharger l e code , l e t e s t l i e a l ’ existence du
parametre ou du f i c h i e r n ’ apparait pas .
21
22 // L ’ u t i l i s a t i o n des l i s t e s chainees et de l ’ a l l o c a t i o n memoire via
des malloc permet d ’ optimiser l ’ espace memoire u t i l i s e pour
stocker un graphe . Ceci permet egalement de t r a i t e r toute t a i l l e
de graphe .
23
24 l i s t e ∗∗deb=NULL;
25 l i s t e ∗∗ parc_tbl=NULL;
26
27 l i s t e ∗parc_chaine=NULL;
28 l i s t e ∗ prec=NULL;
29
30 int nbr_noeud=0,no_noeud=0, nbr_successeurs =0;
31 int no_succ=0, poid_arc=0;
32
33 int i =0;
34
35 f s c a n f ( src_graph , "%d" , &nbr_noeud ) ;
36
37 deb = ( l i s t e ∗∗) malloc ( nbr_noeud ∗ sizeof ( l i s t e ∗ ) ) ;
38 parc_tbl=deb ;
39
40 for ( i =0; i<nbr_noeud ; i++)
41 {
42
43 f s c a n f ( src_graph , "%d %d" , &no_noeud,& nbr_successeurs ) ;
44 prec = NULL;
45
46 i f ( nbr_successeurs )
47 {
48 while ( nbr_successeurs != 0)
49 {
50 parc_chaine = ( l i s t e ∗) malloc ( sizeof ( l i s t e ) ) ;
51 f s c a n f ( src_graph , "%d %d" , &no_succ ,&poid_arc ) ;
52 parc_chaine−>noeud = no_succ ;
4
53 parc_chaine−>poid = poid_arc ;
54 parc_chaine−>suiv = NULL;
55 i f ( prec == NULL) ∗ parc_tbl = parc_chaine ;
56 else prec−>suiv = parc_chaine ;
57 prec = parc_chaine ;
58 nbr_successeurs −−;
59 }
60 }
61 else
62 {
63 ∗ parc_tbl = NULL;
64 }
65 parc_tbl++;
66 }
67
68 // Ci apres , la l e c t u r e du graphe donnant l e code necessaire au bon
fonctionnement des u t i l i t a i r e s de graphviz .
69
70 // Cet algorithme revient a parcourir simplement la structure de
donnee u t i l i s e e pour stocker l e graphe . Cette structure est
presentee dans un autre paragraphe .
71
72 parc_tbl = deb ;
73 p r i n t f ( " digraph G {n" ) ;
74 p r i n t f ( "edge [ color=purple , arrowsize =2];n" ) ;
75 p r i n t f ( "node [ color=pink , s t y l e=f i l l e d ] ;  n" ) ;
76 for ( i =0; i<nbr_noeud ; i++)
77 {
78 parc_chaine=∗parc_tbl ;
79 while ( parc_chaine!=NULL)
80 {
81 p r i n t f ( "%d −> %d [ l a b e l=%d ] ;  n" , i , parc_chaine−>noeud ,
parc_chaine−>poid ) ;
82 parc_chaine=parc_chaine−>suiv ;
83 }
84 parc_tbl++;
85 }
86 p r i n t f ( "}n" ) ;
87
88 f c l o s e ( src_graph ) ;
89
90 return 0;
91 }
Le fonctionnement de ce programme est simple, il prend en paramètre (lors de l’appel de
l’exécutable) un nom de fichier (lien relatif) et en effectue la traduction vers le langage Graphviz.
Afin de ne pas surcharger ce programme, nous avons préféré effectuer l’affichage en console du code
généré, plutôt que le le faire passer via des tubes et des sous-process directement à l’utilitaire ’dot’.
De ce fait, afin d’obtenir un graphique sous forme d’image (ici, de type png) la commande d’appel
nécessite d’utiliser un pipe en console afin de router directement les code généré vers l’utilitaire :
1 ./ conv graph1 . txt | dot −Tpng −o t e s t . png
Ce programme utilise une structure de données pour le stockage du graphe basée sur les listes
chainées qui sera détaillée dans la prochaine section.
5
1.3 Structure de donnée liée au stockage du graphe
La structure de donnée ici présentée est celle mise en place dans le programme de conversion
précédent. Elle sera également utilisé lors de l’implémentation de l’algorithme de Djikstra et celui
des k-plus courts chemins.
Pour faire simple, cette structure de donnée se présente sous la forme d’un tableau d’éléments
de type liste correspondant à chaque sommet. Chacun de ces sommets est ensuite lié à tous ses
successeurs via une liste chainée. Cela permet non seulement de donner un sens à un arc, mais
également de pouvoir tirer profit de la simplicité de représentation de cette structure de donnée
pour y adapter tout type d’algorithme issu de la théorie des graphes.
La structure de donnée est la suivante :
1 // Structure de donnee permettant d ’ obtenir l e s l i s t e s chainees
2 typedef struct l i s t e l i s t e ;
3 struct l i s t e
4 {
5 int noeud ;
6 int poid ;
7 l i s t e ∗ suiv ;
8 };
On peut ainsi représenter le stockage du graphe pris en exemple précédemment comme suit :
Figure 1.3 – Représentation du stockage du graphe via des listes chainées
En outre, l’utilisation de cette structure permet de parcourir le graphe de manière intuitive. En
effet, on connait immédiatement tous les successeurs de chaque sommet, et les poids qui les relient.
1.4 Structure de donnée liée à l’algorithme de Dijkstra
Pour l’algorithme de Dijkstra, deux structures sont nécessaire, l’une pour créer le tableau des
distances, l’autre pour créer le tableau des prédécesseurs. Dans la pratique, une seule structure
suffit car on peut référencer la distance ou le prédécesseur comme une simple donnée de type int.
Comme le préconise l’algorithme de Dijkstra, cette structure doit également comporter un verrou,
afin de ne pas écraser des données déjà traitées.
La structure de donnée est la suivante :
1 typedef struct str_dijkstra str_dijkstra ;
6
2 struct str_dijkstra
3 {
4 int noeud ;
5 int data ; // La donnee peut etre : distance , ou n_o du predecesseur
6 int verrou ;
7 };
Ce verrou est présent dans les deux tableau, ce qui constitue une redondance puisque chaque
élément des deux tableaux sont verrouillés en même temps. Mais cela constitue aussi une vérification
quand au bon fonctionnement de l’algorithme.
1.5 Structure de donnée nécessaire à l’algorithme des k-plus
courts chemins
Pour résoudre ce problème nous allons utiliser deux structures de données spécifiques. Une
structure appelée "nœud", qui sera la structure de l’arbre. Cette structure contiendra la valeur
du sommet mis dans l’arbre ainsi que le poids de l’arc avec le sommet précédent (dans l’arbre).
"nœud" contiendra également un pointeur vers son nœud père et, le nombre de fils pouvant varier,
une liste de fils.
1 struct noeud
2 {
3 int valeur_sommet ;
4 int poid_prec_noeurd ;
5 l_Arbre∗ f i l s ;
6 noeud∗ pere ;
7 };
La liste de fils constitue la deuxième structure utilisée. Cette structure contient un pointeur
vers un "nœud" de l’arbre, qui est le fils en question, ainsi qu’un pointeur vers le maillon suivant
de la liste, le fils suivant.
1 struct l_Arbre
2 {
3 noeud∗ noeud_A ;
4 l_Arbre∗ suiv ;
5 };
C’est en combinant l’utilisation de ces deux structures que nous parviendrons à créer l’arbre
représentant les chemins. Voici alors le schémas de la structure de l’arbre :
7
Figure 1.4 – Représentation des structures de donnée nécessaire à la création d’un arbre
8
Chapitre 2
Problème du plus court chemin
2.1 Présentation du problème
Le cheminement dans les graphes, et plus précisément la recherche du plus court chemin, est un
problème récurrent dans l’étude des graphes. Ces applications sont multiples : réseaux électriques
ou réseaux d’information ou encore calcul d’itinéraire via des cartes, plusieurs algorithmes issus
de la théorie des graphes permettent de répondre à ces problèmes mathématiques. Nous allons ici
nous intéresser à l’algorithme de Dijkstra puis tenter de l’implémenter en langage C.
L’algorithme de Dijkstra utilise deux tableaux, l’un de prédécesseurs, l’autre des plus courtes
distances entre deux points quelconques. Avec l’application successive de l’algorithme de Dijkstra,
on finit par obtenir le tableau du plus court chemin reliant la source à tous les autres sommets.
Cela revient donc à effectuer un parcours ordonné du graphe en mettant à jour certaines in-
formation dans les deux tableaux selon un certain nombre de règles.
2.2 Analyse de l’algorithme de Dijkstra
Cet algorithme effectue l’initialisation de ses deux tableaux puis les remplie au fur et à mesure de
son évolution dans le graphe et selon des contraintes bien définies. On peut repésenter l’algorithme
comme suit :
1 Pour k de 1 a n , f a i r e :
2 distances [ k ] <−− cout ( s , k) ;
3 predecesseurs [ k ] <−− s ;
4 FinPour ;
5 M <−− Supprimer ( s , M) ;
6
7 TantQue (M non vide ) Faire :
8 i <−− LePlusProche (M) ;
9 Si ( distances [ i ] =  i n f ) Alors retour ;
10 M <−− Supprimer ( i , M) ;
11
12 Pour k de 1 a d+( i ) Faire :
13 j <−− k−eme_successeur ( i ) ;
14 Si ( EstSupprime ( j , M) <> 1)
15 v <−− distances [ i ] + cout ( i , j ) ;
16 Si (v < distances [ j ] )
17 Alors distances [ j ] <−− v ;
18 Alors predecesseurs [ j ] <−− i ;
19 FinSi
20 FinSi
9
21 FinPour
22 FinTantQue
2.3 Commentaires sur l’implémentation
Pour implémenter cet algorithme, nous avons repris la structure de stockage de graphe vue dans
le programme de conversion de langage, c’est à dire un tableau de listes chainées. Il est donc néces-
saire de ré-implémenter sous forme de fonctions les algorithmes de génération de cette structure de
graphe. Il y a ensuite un certains nombre de fonction à développer pour faire tourner l’algorithme
de Dijkstra. Certaines fonctionnalités trop souvent utilisées seront également isolée en tant que
fonction a part entière pour plus de clarté.
Pour permettre a l’algorithme de Dijkstra de fonctionner, il est nécessaire de quantifier les dis-
tances infinies. Nous avons donc choisi une distance maximale qu’aucun chemin ne doit dépasser
afin que les comparaisons fonctionnent.
1 #define INF 999999999
2.4 Fonctions utiles à l’affichage
2.4.1 Fonction nécessaire à l’obtention du code Graphviz
Reprise de l’utilitaire de conversion, cette petite fonction permet de rendre compte du graphe
avec lequel on travail. Tout étant détaillé dans la partie correspondante au convertisseur, il ne
semble pas nécessaire d’expliquer plus en détail son fonctionnement.
1 int to_graphviz ( l i s t e ∗∗deb , int nbr_noeud )
2 {
3 l i s t e ∗∗ parc_tbl=NULL;
4 l i s t e ∗parc_chaine=NULL;
5 int i =0;
6
7 parc_tbl = deb ;
8
9 p r i n t f ( " digraph G {n" ) ;
10 p r i n t f ( "edge [ color=purple , arrowsize =2];n" ) ;
11 p r i n t f ( "node [ color=pink , s t y l e=f i l l e d ] ;  n" ) ;
12
13 for ( i =0; i<nbr_noeud ; i++)
14 {
15 parc_chaine=∗parc_tbl ;
16
17 while ( parc_chaine!=NULL)
18 {
19 p r i n t f ( "%d −> %d [ l a b e l=%d ] ;  n" , i , parc_chaine−>noeud ,
parc_chaine−>poid ) ;
20 parc_chaine=parc_chaine−>suiv ;
21 }
22
23 parc_tbl++;
24 }
25
10
26 p r i n t f ( "}n" ) ;
27
28 return 1;
29 }
2.4.2 Fonction d’affichage des tableaux liés à la structure de donnée
spécifique à Dijkstra
Cette petite fonction permet de vérifier que l’algorithme de Dijkstra effectue correctement le
remplissage des tableaux en les affichant.
1 void aff_str_dijkstra ( str_dijkstra ∗ str , int nbr_noeud , char∗ mot)
2 {
3
4 int i =0;
5
6 for ( i = 0 ; i < nbr_noeud ; i ++)
7 {
8 p r i n t f ( "Noeud %d a pour %s %d du sommet %d . ( verrou : %d) n" , i ,
mot , ( s t r+i )−>data , ( s t r+i )−>noeud , ( s t r+i )−>verrou ) ;
9 }
10
11 }
2.5 Fonctions spécifiques au structures de données utilisées
2.5.1 Fonction de génération du graphe
Comme pour le passage à Graphviz, cette fonction est issue du convertisseur précédemment
traité. Elle prend en paramètre le fichier de l’utilisateur, et génère la structure de graphe de type
tableau de listes chainées.
1 l i s t e ∗∗ generation_liste (FILE∗ src_graph , int∗ noeuds )
2 {
3 int nbr_noeud=0,no_noeud=0, nbr_successeurs =0;
4 int nbr_successeurs_temp= 0 , no_succ=0, poid_arc=0;
5
6 int i =0;
7
8 l i s t e ∗∗deb=NULL;
9 l i s t e ∗∗ parc_tbl=NULL;
10 l i s t e ∗parc_chaine=NULL;
11 l i s t e ∗ prec=NULL;
12
13 f s c a n f ( src_graph , "%d" , &nbr_noeud ) ;
14
15 ∗noeuds = nbr_noeud ;
16
17 deb = ( l i s t e ∗∗) malloc ( nbr_noeud ∗ sizeof ( l i s t e ∗ ) ) ;
18
19 parc_tbl=deb ;
20
21 for ( i =0; i<nbr_noeud ; i++)
11
22 {
23 f s c a n f ( src_graph , "%d %d" , &no_noeud,& nbr_successeurs ) ;
24 prec = NULL;
25
26 i f ( nbr_successeurs )
27 {
28 nbr_successeurs_temp = nbr_successeurs ;
29 while ( nbr_successeurs != 0)
30 {
31 parc_chaine = ( l i s t e ∗) malloc ( sizeof ( l i s t e ) ) ;
32
33 f s c a n f ( src_graph , "%d %d" , &no_succ ,&poid_arc ) ;
34
35 parc_chaine−>noeud = no_succ ;
36 parc_chaine−>poid = poid_arc ;
37 parc_chaine−>suiv = NULL;
38
39 parc_chaine−>nbr_successeurs = nbr_successeurs_temp ;
40
41 i f ( prec == NULL) ∗ parc_tbl = parc_chaine ;
42 else prec−>suiv = parc_chaine ;
43
44 prec = parc_chaine ;
45 nbr_successeurs −−;
46 }
47 }
48
49 else
50 {
51 ∗ parc_tbl = NULL;
52 }
53
54 parc_tbl++;
55 }
56
57 return deb ;
58 }
Cette fonction retourne le premier élément du tableau afin de pouvoir le parcourir dans les
autres fonctions.
2.5.2 Fonction d’affichage des tableaux liés à la structure de donnée
spécifique à Dijkstra
Cette petite fonction permet de vérifier que l’algorithme de Dijkstra effectue correctement le
remplissage des tableaux en les affichant.
1 void aff_str_dijkstra ( str_dijkstra ∗ str , int nbr_noeud , char∗ mot)
2 {
3
4 int i =0;
5
6 for ( i = 0 ; i < nbr_noeud ; i ++)
7 {
8 p r i n t f ( "Noeud %d a pour %s %d du sommet %d . ( verrou : %d) n" , i ,
mot , ( s t r+i )−>data , ( s t r+i )−>noeud , ( s t r+i )−>verrou ) ;
12
9 }
10
11 }
2.6 Fonctions utiles à l’algorithme de Dijkstra
2.6.1 Fonction retournant le poids de l’arc entre deux sommets
Cette fonction permet de connaitre le poids de l’arc entre deux sommets. Si ces deux sommets
ne sont pas directement reliés par un arc, cette fonction renvoie la valeur de l’infini quantifié comme
expliqué précédemment.
1 int get_poid ( l i s t e ∗∗ deb , int nbr_noeud , int sommet , int suivant )
2 {
3 l i s t e ∗∗ parc_tbl = NULL;
4 l i s t e ∗parc_chaine = NULL;
5 int i =0, poid = INF ;
6
7 parc_tbl = deb ;
8
9 for ( i =0; i<nbr_noeud ; i++)
10 {
11 parc_chaine=∗parc_tbl ;
12
13 while ( parc_chaine!=NULL)
14 {
15 i f ( i == sommet && parc_chaine−>noeud == suivant )
16 {
17 poid = parc_chaine−>poid ;
18 return poid ;
19 }
20
21 parc_chaine=parc_chaine−>suiv ;
22 }
23
24 parc_tbl++;
25 }
26
27 return poid ;
28 }
2.6.2 Trouver la distances minimum depuis le tableau des distances
Cette fonction permet à l’algorithme de Dijkstra de travailler sur le tableau des distances, et
renvoie le sommet correspondant à la distance la plus petite qui n’a pas déjà été verrouillée.
1 int find_dist_min ( str_dijkstra ∗ distances , int nbr_noeud )
2 {
3 // Le premier noeud est toujours l e point source
4 int i = 0 , minimum = INF , sommet = −1;
5
6 for ( i = 0; i < nbr_noeud ; i++)
7 {
13
8 i f (( distances+i )−>data < minimum && ( distances+i )−>verrou == 0)
9 {
10 minimum = ( distances+i )−>data ;
11 sommet = i ;
12 }
13 }
14
15 return sommet ;
16 }
2.6.3 Fonction permettant de retrouver les successeurs d’un sommet
Cette fonction travail sur un tableau temporaire et y stock tous les successeurs d’un sommet
donné. Elle retourne en outre le nombre de successeurs.
1 int find_successeurs ( int sommet , l i s t e ∗∗deb , int nbr_noeud ,
str_dijkstra ∗ temp)
2 {
3 int i = 0;
4 l i s t e ∗parc_chaine = NULL;
5
6 parc_chaine=∗(deb+sommet) ;
7
8 while ( parc_chaine!=NULL)
9 {
10 temp [ parc_chaine−>noeud ] . data = 1;
11 parc_chaine=parc_chaine−>suiv ;
12 i ++;
13 }
14
15 return i ;
16 }
2.6.4 Fonction de verrouillage des deux tableaux
Comme expliqué précédemment, les deux tableau se verrouillent systématiquement ensemble.
Il est donc plus simple de créer une fonction à cet égard.
1 void v e r r o u i l l e r ( int sommet , str_dijkstra ∗ distances , str_dijkstra ∗
predecesseurs )
2 {
3 ( distances+sommet)−>verrou = 1;
4 ( predecesseurs+sommet)−>verrou = 1;
5 }
2.6.5 Initialisation nécessaire à l’algorithme de Dijkstra
L’algorithme de Dijkstra travaille sur deux tableau, comme explicité précédemment, mais il
faut au préalable préparer ces tableaux. Initialiser le tableau des distances ainsi que le tableau des
prédécesseurs et verrouiller le premier élément, le sommet source.
14
1 void i n i t ( l i s t e ∗∗ deb , str_dijkstra ∗ predecesseurs , str_dijkstra ∗
distances , int nbr_noeud )
2 {
3 /∗
4 Permet d ’ i n i t i a l i s e r correctement l e s deux
5 tableaux contenant l e s distances et l e s predecesseurs
6 en parcourant la l i s t e de l i s t e s chainees
7 ∗/
8
9 l i s t e ∗parc_chaine = NULL;
10
11 int i =0, poid = INF ; // INF = 999999999
12
13 // I n i t i a l i s a t i o n des valeurs de verrou et des predecesseurs
14 for ( i = 0 ; i < nbr_noeud ; i ++)
15 {
16 ( distances+i )−>data = poid ;
17 ( predecesseurs+i )−>data = 0;
18
19
20 ( distances+i )−>verrou = 0;
21 ( predecesseurs+i )−>verrou = 0;
22 }
23
24 distances −> verrou = 1; // Verouillage du premier element
25 predecesseurs −> verrou = 1; //
26
27 parc_chaine=∗deb ;
28
29 // i n i t i a l i s a t i o n des valeurs des distances
30 while ( parc_chaine!=NULL)
31 {
32 distances [ parc_chaine−>noeud ] . data = parc_chaine−>poid ;
33 parc_chaine=parc_chaine−>suiv ;
34 }
35 }
2.6.6 L’algorithme en lui même
Ci après le code de l’algorithme de Dijkstra comme défini plus haut, en utilisant la structure
de stockage du graphe donnée.
1 int algo ( l i s t e ∗∗ deb , str_dijkstra ∗ predecesseurs , str_dijkstra ∗
distances , int nbr_noeud )
2 {
3
4 /∗
5 Fonction recursive implementant l ’ algorithme de Dijkstra .
6 Cette fonction remplie correctement l e s deux tableaux
7 de distances et de predecesseurs .
8 Les noeux sans predecesseurs ont une distance a la source de
999999999.
9 ∗/
10
11 str_dijkstra ∗temp = NULL;
15
12 temp = ( str_dijkstra ∗) c a l l o c ( nbr_noeud , sizeof ( str_dijkstra ) ) ;
13
14
15 int noeud_plus_proche = 0;
16 int nbr_successeurs = 0;
17 int i = 0 , temp_int = 0;
18
19 noeud_plus_proche = find_dist_min ( distances , nbr_noeud ) ;
20
21 i f ( noeud_plus_proche == −1)
22 {
23 perror ( "nPas de p o s s i b i l i t e d ’ appliquer l ’ algo encore une f o i s " ) ;
24 return 1;
25 }
26
27 // Le tableau temp contient la data = 1 s i l e sommet correspondant a
la position dans l e tableau est un predecesseur .
28 nbr_successeurs = find_successeurs ( noeud_plus_proche , deb , nbr_noeud ,
temp) ;
29
30 // Remplissage des tabelaux de distances et des predecesseurs .
31 for ( i = 0 ; i < nbr_noeud ; i++ )
32 {
33 i f (( temp+i )−>data == 1 && ( distances+i )−>verrou == 0)
34 {
35 temp_int = ( distances+noeud_plus_proche )−>data + get_poid ( deb ,
nbr_noeud , noeud_plus_proche , i ) ;
36
37 ( predecesseurs+i )−>data = noeud_plus_proche ;
38
39 i f (( distances+i )−>data > temp_int ) ( distances+i )−>data =
temp_int ;
40 }
41 }
42
43 // Verrouillage des noeux concernes .
44 v e r r o u i l l e r ( noeud_plus_proche , distances , predecesseurs ) ;
45
46 // Desallocation de la memoire .
47 f r e e (temp) ;
48
49 return algo ( deb , predecesseurs , distances , nbr_noeud ) ;
50 }
2.6.7 La fonction main
Ci après, la fonction main() donne l’ordre d’appel des différentes fonctions.
1 int main ( int argc , char ∗argv [ ] )
2 {
3 i f ( argv [ 1 ] == NULL)
4 {
5 p r i n t f ( " Error : no input f i l e . n" ) ;
6 return 1;
7 }
16
8
9 FILE∗ src_graph=fopen ( argv [ 1 ] , " r " ) ;
10
11 l i s t e ∗∗deb = NULL;
12
13 str_dijkstra ∗ distances = NULL;
14 str_dijkstra ∗ predecesseurs = NULL;
15
16
17 int nbr_noeud = 0;
18
19 deb = generation_liste ( src_graph , &nbr_noeud ) ;
20
21 distances = ( str_dijkstra ∗) c a l l o c ( nbr_noeud , sizeof ( str_dijkstra ) ) ;
22 predecesseurs = ( str_dijkstra ∗) c a l l o c ( nbr_noeud , sizeof ( str_dijkstra )
) ;
23
24 i n i t ( deb , predecesseurs , distances , nbr_noeud ) ;
25
26 algo ( deb , predecesseurs , distances , nbr_noeud ) ;
27
28 p r i n t f ( "n" ) ;
29 aff_str_dijkstra ( distances , nbr_noeud , " distance " ) ;
30 p r i n t f ( "n" ) ;
31
32 aff_str_dijkstra ( predecesseurs , nbr_noeud , " predecesseur " ) ;
33 p r i n t f ( "n" ) ;
34
35 /∗ to_graphviz ( deb , nbr_noeud ) ; ∗/
36 noeud∗ r=(noeud ∗) malloc ( sizeof ( noeud ) ) ;
37
38 r=algo_k ( r , deb , ( ( ∗ deb )−>nbr_successeurs ) ) ;
39
40 f c l o s e ( src_graph ) ;
41
42 // Desallocation de la memoire .
43 f r e e ( distances ) ;
44 f r e e ( predecesseurs ) ;
45
46 return 0;
47 }
17
Chapitre 3
Problème des K-plus courts chemins
3.1 Présentation du problème
Le but est d’implémenter un algorithme qui permettra d’afficher tous les chemins d’un nœud de
départ à nœud d’arrivée dans un graphe. Pour résoudre ce problème nous avons décider de stocker
ces chemins dans un arbre qui contiendra les numéros des nœuds et le poids de l’arc avec le nœud
parent.
Figure 3.1 – Schéma du graphe considéré
Ainsi ce graphe donnerai :
Figure 3.2 – Arbre du graphe considéré
Cet arbre représente les chemins possibles pour aller de 0 à 3. La branche qui se termine par le
4 est une branche "terminale", c’est à dire qu’elle ne pourra jamais mener à 3, elle ne représente
donc pas un chemin. pour trouver les k plus court chemins il nous suffit de parcourir l’arbre et de
compter la somme des poids de chaque branche. Chaque branche se terminant par une feuille 3
représente un chemin.
18
3.2 Analyse de l’algorithme des k-plus court chemins
Comme dit précédemment, l’algorithme des k-plus court chemins utilisé est un algorithme qui
créé un arbre contenant la liste de tout les chemins possibles d’un point à un autre.
L’algorithme théorique se définit comme suit :
1 Algorithme k plus court ( noeud i n i t i a l , noeud f i n a l )
2 racine de l ’ arbre = noeud i n i t i a l
3 de 0 a nombre de noeud f a i r e :
4 s i nombre de f i l s = 0 f a i r e
5 retourner noeud i n i t i a l
6 sinon f a i r e
7 chaque successeur devient un f i l s .
8 pour chaque f i l s f a i r e :
9 s i f i l s d i f f e r e n d de noeud f i n a l f a i r e
10 f i l s = Algorithme k plus court ( f i l s , noeud f i n a l )
11 sinon s i f i l s = noeud f i n a l f a i r e
12 retourner f i l s
13 f i n de
14 retourner noeud i n i t i a l
15 f i n Algorithme k plus court
L’algorithme consiste à créer, de manière récursive, la liste de fils du nœud actuel (en fonction
des successeurs). Puis pour chacun des fils on répète l’opération, ainsi à la fin on obtient bien une
structure semblable à celle présenté dans la partie structure de données utilisée.
3.3 Commentaires sur l’implémentation
En ce qui concerne l’implémentation de l’algorithme nous n’avons pas réussit à aboutir malgré
plusieurs essais et reprises du code. Nous avons cependant réussit à implémenter la partie qui crée
les fils correspondants aux successeurs. Il manque donc la partie récursive de notre algorithme.
3.3.1 Fonction d’affichage de l’arbre
Cette fonction à simplement pour but d’afficher l’arbre contenant tout les successeurs pour
pouvoir visualiser les chemins.
1 int afficher_arbre_RGD ( noeud∗ racine )
2 {
3 p r i n t f ( "Debut a f f i c h a g e n" ) ;
4 i f ( racine==NULL)
5 {
6 p r i n t f ( " racine null . n" ) ;
7 return 0;
8 }
9 else
10 {
11 l_Arbre∗ parc=(racine −>f i l s ) ;
12 // on a f f i c h e l e pere
13 p r i n t f ( "Sommet %d : " , racine −>valeur_sommet ) ;
14 p r i n t f ( "Poid_prec %d | " , racine −>poid_prec_noeurd ) ;
15 // on passe au f i l s
16 while ( parc−>noeud_A!=NULL )
17 {
18 afficher_arbre_RGD ( parc−>noeud_A) ;
19
19 parc=parc−>suiv ;
20 }
21 return 1;
22
23 }
24 }
3.3.2 Fonction de création des nœuds des successeurs
Celte fonction à pour but de créer la liste des nœuds fils contenant les successeurs du nœud
racine envoyé en paramètre. Elle retourne un pointeur vers cette liste de fils.
1 l_Arbre∗ creerSucc ( noeud∗ racine , l i s t e ∗∗ deb , int nbr_noeud )
2 {
3 int i =0, j =0;
4
5 i f (∗ deb==NULL) // s i la l i s t e des successeurs est vide on ne cree
rien
6 {
7 return NULL;
8 }
9 // on recupere l e nombre de successeurs
10 int nbr_successeurs =((∗deb )−>nbr_successeurs ) ;
11 p r i n t f ( " nbr_successeurs=%dn" , nbr_successeurs ) ;
12
13 racine −>f i l s = ( l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ;
14 l_Arbre∗ parc= racine −>f i l s ;
15 l i s t e ∗ parc_l = ∗deb ;
16
17 while ( i<nbr_successeurs ) // pour chacun des successeurs
18 {
19
20 p r i n t f ( " f i l s %d n" , i ) ;
21 // on cree un noeud f i l s correspondant au successeur
22 noeud∗ temp = ( noeud ∗) malloc ( sizeof ( noeud ) ) ;
23 // on r e l i e ce noeud a son pere
24 parc−>noeud_A = temp ;
25 // on met l e s bonnes valeurs dans ce noeud
26 parc−>noeud_A−>valeur_sommet=parc_l−>noeud ;
27 parc−>noeud_A−>poid_prec_noeurd=parc_l−>poid ;
28 parc−>noeud_A−>pere=racine ;
29 parc−>noeud_A−>f i l s=NULL;
30 p r i n t f ( "%d , %d n" , parc−>noeud_A−>valeur_sommet , parc−>noeud_A−>
poid_prec_noeurd ) ;
31 i f ( i != nbr_successeurs ) // s i ce n ’ est pas l e dernier successeur
32 {
33 // on a l l o u e de la place pour l e noeud suivant
34 parc−>suiv=(l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ;
35 }
36 // on passe au suivant
37 parc=parc−>suiv ;
38 parc_l=parc_l−>suiv ;
39 i ++;
40 }
41 parc=NULL;
20
42
43 return racine −>f i l s ; // on renvoie la l i s t e des f i l s du noeud pere
44
45 }
3.3.3 Fonction algorithme des k plus court chemins
Cette fonction à normalement pour but de dérouler l’algorithme. Mais dans notre cas comme
l’implémentation n’as rien donnée elle ne déroulera l’algorithme que sur le nœud de départ et ses
fils.
1 noeud∗ algo_k ( noeud∗ racine , l i s t e ∗∗ deb , int nbr_noeud )
2 {
3
4 int ret =0, i =0, nbr_succ=0;
5 l_Arbre∗ f i l s =(l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ;
6 l_Arbre∗ tmp=(l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ;
7 l i s t e ∗∗ parc_deb = deb ;
8
9 // i n i t i a l i s a t i o n : sommet 0
10 // on cree l e s f i l s du somet 0
11 f i l s=creerSucc ( racine , parc_deb , nbr_noeud ) ;
12
13 nbr_succ=(∗parc_deb )−>nbr_successeurs ;
14
15 // pour chacun des successeurs
16
17 for ( i =0; i<nbr_succ ; i++)
18 {
19 // successeur i
20 p r i n t f ( "n Sommet : %d n " , f i l s −>noeud_A−>valeur_sommet ) ;
21 parc_deb= ( deb + f i l s −>noeud_A−>valeur_sommet ) ;
22 // on cree l e s f i l s de chacun des sommet correspondant au
successeurs .
23 tmp=creerSucc ( f i l s −>noeud_A , parc_deb , nbr_noeud ) ;
24 f i l s=f i l s −>suiv ;
25 }
26
27 p r i n t f ( "lancement a f f i c h a g e n" ) ;
28
29 // a f f i c h a g e de l ’ arbre
30 ret = afficher_arbre_RGD ( racine ) ;
31 p r i n t f ( "%dn" , ret ) ;
32
33 return racine ;
34 }
21

Contenu connexe

Tendances

Le problème de voyageur de commerce: algorithme génétique
Le problème de voyageur de commerce: algorithme génétiqueLe problème de voyageur de commerce: algorithme génétique
Le problème de voyageur de commerce: algorithme génétique
Rima Lassoued
 
Chapitre iv algorithmes de tri
Chapitre iv algorithmes de triChapitre iv algorithmes de tri
Chapitre iv algorithmes de tri
Sana Aroussi
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite complet
Chahrawoods Dmz
 
Chapitre v algorithmes gloutons
Chapitre v algorithmes gloutonsChapitre v algorithmes gloutons
Chapitre v algorithmes gloutons
Sana Aroussi
 
Reconnaissance faciale
Reconnaissance facialeReconnaissance faciale
Reconnaissance faciale
Aymen Fodda
 

Tendances (20)

Le problème de voyageur de commerce: algorithme génétique
Le problème de voyageur de commerce: algorithme génétiqueLe problème de voyageur de commerce: algorithme génétique
Le problème de voyageur de commerce: algorithme génétique
 
01 correction-td smia-s2-info2
01 correction-td smia-s2-info201 correction-td smia-s2-info2
01 correction-td smia-s2-info2
 
Corrige exercices pascal_fenni_2018
Corrige exercices pascal_fenni_2018Corrige exercices pascal_fenni_2018
Corrige exercices pascal_fenni_2018
 
Chapitre iv algorithmes de tri
Chapitre iv algorithmes de triChapitre iv algorithmes de tri
Chapitre iv algorithmes de tri
 
Algorithmes de jeux
Algorithmes de jeuxAlgorithmes de jeux
Algorithmes de jeux
 
Examen principal - Fondement Multimedia - correction
Examen principal - Fondement Multimedia - correctionExamen principal - Fondement Multimedia - correction
Examen principal - Fondement Multimedia - correction
 
Chapitre 4 heuristiques et méta heuristiques
Chapitre 4 heuristiques et méta heuristiquesChapitre 4 heuristiques et méta heuristiques
Chapitre 4 heuristiques et méta heuristiques
 
TP1 Traitement d'images Génie Logiciel avec Matlab
TP1 Traitement d'images Génie Logiciel avec MatlabTP1 Traitement d'images Génie Logiciel avec Matlab
TP1 Traitement d'images Génie Logiciel avec Matlab
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite complet
 
Travaux dirigés 1: algorithme & structures de données (corrigés)
Travaux dirigés 1: algorithme & structures de données (corrigés)Travaux dirigés 1: algorithme & structures de données (corrigés)
Travaux dirigés 1: algorithme & structures de données (corrigés)
 
Traitement des images avec matlab
Traitement des images avec matlabTraitement des images avec matlab
Traitement des images avec matlab
 
Chapitre v algorithmes gloutons
Chapitre v algorithmes gloutonsChapitre v algorithmes gloutons
Chapitre v algorithmes gloutons
 
Chap2 Les conteneurs en python
Chap2 Les conteneurs en pythonChap2 Les conteneurs en python
Chap2 Les conteneurs en python
 
Exercices pascal fenni_2018
Exercices pascal fenni_2018Exercices pascal fenni_2018
Exercices pascal fenni_2018
 
Vertex cover Problem
Vertex cover ProblemVertex cover Problem
Vertex cover Problem
 
Reconnaissance faciale
Reconnaissance facialeReconnaissance faciale
Reconnaissance faciale
 
Lab1-DB-Cassandra
Lab1-DB-CassandraLab1-DB-Cassandra
Lab1-DB-Cassandra
 
Cours fondement du multimedia
Cours fondement du multimediaCours fondement du multimedia
Cours fondement du multimedia
 
Cryptologie
Cryptologie Cryptologie
Cryptologie
 
Application de Reconnaissance faciale - eigenfaces, fisherfaces et lbph
Application de  Reconnaissance faciale - eigenfaces, fisherfaces et lbphApplication de  Reconnaissance faciale - eigenfaces, fisherfaces et lbph
Application de Reconnaissance faciale - eigenfaces, fisherfaces et lbph
 

En vedette

Tour_du_monde_virtuel._._._._._._._
Tour_du_monde_virtuel._._._._._._._Tour_du_monde_virtuel._._._._._._._
Tour_du_monde_virtuel._._._._._._._
lyago
 
Copiepourdiapo avec rapport activités 2013
Copiepourdiapo avec rapport activités 2013Copiepourdiapo avec rapport activités 2013
Copiepourdiapo avec rapport activités 2013
aveclaruche
 
Tonalidad La Mayor
Tonalidad La MayorTonalidad La Mayor
Tonalidad La Mayor
Jose Catalan
 
Recommendations & Certificates
Recommendations & CertificatesRecommendations & Certificates
Recommendations & Certificates
Dr. Khalaf
 
Question 4 - Qui supporte les frais ?
Question 4 - Qui supporte les frais ?Question 4 - Qui supporte les frais ?
Question 4 - Qui supporte les frais ?
Christophe Boeraeve
 
Réglementation contre l'incendie mai 2010
Réglementation contre l'incendie mai 2010Réglementation contre l'incendie mai 2010
Réglementation contre l'incendie mai 2010
cdtsomme
 

En vedette (20)

Comment nettoyer votre carrelage avec la rotowash
Comment nettoyer votre carrelage avec la rotowashComment nettoyer votre carrelage avec la rotowash
Comment nettoyer votre carrelage avec la rotowash
 
St-Exupery & Le Petit Prince Intro
St-Exupery & Le Petit Prince IntroSt-Exupery & Le Petit Prince Intro
St-Exupery & Le Petit Prince Intro
 
Tour_du_monde_virtuel._._._._._._._
Tour_du_monde_virtuel._._._._._._._Tour_du_monde_virtuel._._._._._._._
Tour_du_monde_virtuel._._._._._._._
 
Radio Summit - Jacqueline Smit, Radio 538, Netherlands
Radio Summit - Jacqueline Smit, Radio 538, NetherlandsRadio Summit - Jacqueline Smit, Radio 538, Netherlands
Radio Summit - Jacqueline Smit, Radio 538, Netherlands
 
Lineas invest
Lineas investLineas invest
Lineas invest
 
The beatles
The beatlesThe beatles
The beatles
 
LA CELULA
LA CELULALA CELULA
LA CELULA
 
Copiepourdiapo avec rapport activités 2013
Copiepourdiapo avec rapport activités 2013Copiepourdiapo avec rapport activités 2013
Copiepourdiapo avec rapport activités 2013
 
EdCamp Québec 2015 - Diaporama d'accueil
EdCamp Québec 2015 - Diaporama d'accueilEdCamp Québec 2015 - Diaporama d'accueil
EdCamp Québec 2015 - Diaporama d'accueil
 
Brochure groupes adultes 2016
Brochure groupes adultes 2016Brochure groupes adultes 2016
Brochure groupes adultes 2016
 
"Apache JMeter, Java et Groovy sont sur un bateau" présentée au Paris JUG
"Apache JMeter, Java et Groovy sont sur un bateau" présentée au Paris JUG"Apache JMeter, Java et Groovy sont sur un bateau" présentée au Paris JUG
"Apache JMeter, Java et Groovy sont sur un bateau" présentée au Paris JUG
 
Tonalidad La Mayor
Tonalidad La MayorTonalidad La Mayor
Tonalidad La Mayor
 
MyFundStore - référentiel Fonds
MyFundStore - référentiel FondsMyFundStore - référentiel Fonds
MyFundStore - référentiel Fonds
 
Recommendations & Certificates
Recommendations & CertificatesRecommendations & Certificates
Recommendations & Certificates
 
Question 4 - Qui supporte les frais ?
Question 4 - Qui supporte les frais ?Question 4 - Qui supporte les frais ?
Question 4 - Qui supporte les frais ?
 
Olivares
OlivaresOlivares
Olivares
 
Fr greensun présentation b2 c
Fr greensun présentation b2 cFr greensun présentation b2 c
Fr greensun présentation b2 c
 
Question 7 photos
Question 7 photosQuestion 7 photos
Question 7 photos
 
Réglementation contre l'incendie mai 2010
Réglementation contre l'incendie mai 2010Réglementation contre l'incendie mai 2010
Réglementation contre l'incendie mai 2010
 
Ortodigital
OrtodigitalOrtodigital
Ortodigital
 

Similaire à Dijkstra kshortest

335105967 support-de-cours-sap2000-version-07-2006-pdf
335105967 support-de-cours-sap2000-version-07-2006-pdf335105967 support-de-cours-sap2000-version-07-2006-pdf
335105967 support-de-cours-sap2000-version-07-2006-pdf
toufik kaidi
 
Création d'une application html5 utilisant canvas, svg et les animations css3
Création d'une application html5 utilisant canvas, svg et les animations css3Création d'une application html5 utilisant canvas, svg et les animations css3
Création d'une application html5 utilisant canvas, svg et les animations css3
davrous
 
Mat lab1
Mat lab1Mat lab1
Mat lab1
fouadDD
 
Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?
Ruau Mickael
 

Similaire à Dijkstra kshortest (20)

L’environnement de programmation fonctionnelle DrRacket
L’environnement de programmation fonctionnelle DrRacketL’environnement de programmation fonctionnelle DrRacket
L’environnement de programmation fonctionnelle DrRacket
 
Réseaux avec NetLogo
Réseaux avec NetLogoRéseaux avec NetLogo
Réseaux avec NetLogo
 
335105967 support-de-cours-sap2000-version-07-2006-pdf
335105967 support-de-cours-sap2000-version-07-2006-pdf335105967 support-de-cours-sap2000-version-07-2006-pdf
335105967 support-de-cours-sap2000-version-07-2006-pdf
 
Impl´ementation d’une copule mutilvari´ee.pdf
Impl´ementation d’une copule mutilvari´ee.pdfImpl´ementation d’une copule mutilvari´ee.pdf
Impl´ementation d’une copule mutilvari´ee.pdf
 
Introduction à MATLAB
Introduction à MATLABIntroduction à MATLAB
Introduction à MATLAB
 
Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017)
Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017) Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017)
Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017)
 
Coursmp
CoursmpCoursmp
Coursmp
 
Support tutoriel : Créer votre jeu en HTML5
Support tutoriel : Créer votre jeu en HTML5Support tutoriel : Créer votre jeu en HTML5
Support tutoriel : Créer votre jeu en HTML5
 
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
 
R Devtools
R DevtoolsR Devtools
R Devtools
 
Tutorial GGPlot2
Tutorial GGPlot2Tutorial GGPlot2
Tutorial GGPlot2
 
Visualisation graphique R avec ggplot2
Visualisation graphique R avec ggplot2Visualisation graphique R avec ggplot2
Visualisation graphique R avec ggplot2
 
Création d'une application html5 utilisant canvas, svg et les animations css3
Création d'une application html5 utilisant canvas, svg et les animations css3Création d'une application html5 utilisant canvas, svg et les animations css3
Création d'une application html5 utilisant canvas, svg et les animations css3
 
Cours de Matlab
Cours de MatlabCours de Matlab
Cours de Matlab
 
Mat lab1
Mat lab1Mat lab1
Mat lab1
 
L'impact des incriments des séquences de tri Shell. Expérimentation des séque...
L'impact des incriments des séquences de tri Shell. Expérimentation des séque...L'impact des incriments des séquences de tri Shell. Expérimentation des séque...
L'impact des incriments des séquences de tri Shell. Expérimentation des séque...
 
Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?
 
Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)
 
Matlab for engineer
Matlab for engineer Matlab for engineer
Matlab for engineer
 
ALT.NET Modéliser Parallèle avec C# 4.0
ALT.NET Modéliser Parallèle avec C# 4.0ALT.NET Modéliser Parallèle avec C# 4.0
ALT.NET Modéliser Parallèle avec C# 4.0
 

Plus de ابو محمدوعبدالرحمن عبد الملك (12)

Odoo new-api-guide-line
Odoo new-api-guide-lineOdoo new-api-guide-line
Odoo new-api-guide-line
 
Macros
MacrosMacros
Macros
 
Lecon5
Lecon5Lecon5
Lecon5
 
La communauté-open erp
La communauté-open erpLa communauté-open erp
La communauté-open erp
 
Kaprykowsky rapport
Kaprykowsky rapportKaprykowsky rapport
Kaprykowsky rapport
 
Installation open erp-sous-windows1
Installation open erp-sous-windows1Installation open erp-sous-windows1
Installation open erp-sous-windows1
 
Installation d openerp
Installation d openerpInstallation d openerp
Installation d openerp
 
Guide technique-open erp
Guide technique-open erpGuide technique-open erp
Guide technique-open erp
 
Gloutons
GloutonsGloutons
Gloutons
 
Gestion de la_production
Gestion de la_productionGestion de la_production
Gestion de la_production
 
Criteres evalformatscompressioncicmhd3d
Criteres evalformatscompressioncicmhd3dCriteres evalformatscompressioncicmhd3d
Criteres evalformatscompressioncicmhd3d
 
Cours implementation-crypto
Cours implementation-cryptoCours implementation-crypto
Cours implementation-crypto
 

Dijkstra kshortest

  • 1. Graphs & Algorithmie : Recherches sur l’implémentation des algorithmes liés à Dijkstra et au problème des K-plus courts chemins Arthur Van de Wiele Louis Thibon 25 Janvier 2011
  • 2. Table des matières 1 Structures de donnée et outils divers 2 1.1 Graphviz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Conversion d’une méthode de saisie simple vers graphviz . . . . . . . . . . . . . . . 3 1.3 Structure de donnée liée au stockage du graphe . . . . . . . . . . . . . . . . . . . . 6 1.4 Structure de donnée liée à l’algorithme de Dijkstra . . . . . . . . . . . . . . . . . . 6 1.5 Structure de donnée nécessaire à l’algorithme des k-plus courts chemins . . . . . . 7 2 Problème du plus court chemin 9 2.1 Présentation du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.2 Analyse de l’algorithme de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3 Commentaires sur l’implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4 Fonctions utiles à l’affichage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4.1 Fonction nécessaire à l’obtention du code Graphviz . . . . . . . . . . . . . . 10 2.4.2 Fonction d’affichage des tableaux liés à la structure de donnée spécifique à Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.5 Fonctions spécifiques au structures de données utilisées . . . . . . . . . . . . . . . . 11 2.5.1 Fonction de génération du graphe . . . . . . . . . . . . . . . . . . . . . . . . 11 2.5.2 Fonction d’affichage des tableaux liés à la structure de donnée spécifique à Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.6 Fonctions utiles à l’algorithme de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . 13 2.6.1 Fonction retournant le poids de l’arc entre deux sommets . . . . . . . . . . 13 2.6.2 Trouver la distances minimum depuis le tableau des distances . . . . . . . . 13 2.6.3 Fonction permettant de retrouver les successeurs d’un sommet . . . . . . . 14 2.6.4 Fonction de verrouillage des deux tableaux . . . . . . . . . . . . . . . . . . 14 2.6.5 Initialisation nécessaire à l’algorithme de Dijkstra . . . . . . . . . . . . . . . 14 2.6.6 L’algorithme en lui même . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.6.7 La fonction main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3 Problème des K-plus courts chemins 18 3.1 Présentation du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.2 Analyse de l’algorithme des k-plus court chemins . . . . . . . . . . . . . . . . . . . 19 3.3 Commentaires sur l’implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.3.1 Fonction d’affichage de l’arbre . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.3.2 Fonction de création des nœuds des successeurs . . . . . . . . . . . . . . . . 20 3.3.3 Fonction algorithme des k plus court chemins . . . . . . . . . . . . . . . . . 21 1
  • 3. Chapitre 1 Structures de donnée et outils divers 1.1 Graphviz Graphviz est une suite d’utilitaires sous système Unix qui permet de tracer le visuel d’un graphe donné à partir d’un structure de donnée (langage) propre à Graphviz. Il est donc possible de créer un utilitaire simple pour convertir une structure de graphe simpliste en langage interprétable par un des programmes de Graphviz : “dot”. Le langage interprétable par Graphviz se présente comme suite : 1 digraph G 2 { 3 edge [ color=purple , arrowsize =2]; 4 node [ color=pink , s t y l e=f i l l e d ] ; 5 0 −> 1 [ l a b e l =1]; 6 0 −> 3 [ l a b e l =2]; 7 1 −> 2 [ l a b e l =3]; 8 1 −> 3 [ l a b e l =4]; 9 2 −> 3 [ l a b e l =5]; 10 } Ce qui permet d’obtenir le tracé suivant : Figure 1.1 – Exemple de grape obtenu à l’aide des outils de Graphviz 2
  • 4. Mais cet utilitaire prend tous son sens lors de tracés de graphes plus importants, lorsque le tracé devient réellement fastidieux, comme dans cet exemple : Figure 1.2 – Second exemple de graphe obtenu à l’aide des outils de Graphviz 1.2 Conversion d’une méthode de saisie simple vers graphviz Le langage qu’interprète Graphviz implique certaines redondances dans son écriture. Afin de faciliter l’écriture d’un graphe, nous avons développé un petit utilitaire travaillant sur une méthode de saisie simple qui permet d’obtenir instantanément un code de type Graphviz. Le méthode de saisie que nous avons souhaité utilisé se construit comme suit : Chaque ligne cor- respond à un sommet suivi du nombre et de la liste de ses successeurs avec l’affectation du poids de l’arc entre eux. Pour plus de facilité, la première ligne doit comporter le nombre de sommets du graphe. Ce qui se traduit par l’écriture suivante pour le cas de la figure 1.1 : 1 4 2 0 2 1 1 3 2 3 1 2 2 3 3 4 4 2 1 3 5 5 3 0 Le code source de ce programme est donné ci après. Les explications se trouvent à la suite du code. 3
  • 5. 1 #include <stdio . h> 2 #include <s t d l i b . h> 3 #include <s t r i n g . h> 4 5 // Structure de donnee permettant d ’ obtenir des l i s t e s chainees 6 typedef struct l i s t e l i s t e ; 7 struct l i s t e 8 { 9 int noeud ; 10 int poid ; 11 l i s t e ∗ suiv ; 12 }; 13 14 int main ( int argc , char ∗argv [ ] ) 15 { 16 17 // Ouverture du f i c h i e r comportant l e code s i m p l i f i e du graphe . 18 FILE∗ src_graph=fopen ( argv [ 1 ] , " r " ) ; 19 20 // Afin de ne pas surcharger l e code , l e t e s t l i e a l ’ existence du parametre ou du f i c h i e r n ’ apparait pas . 21 22 // L ’ u t i l i s a t i o n des l i s t e s chainees et de l ’ a l l o c a t i o n memoire via des malloc permet d ’ optimiser l ’ espace memoire u t i l i s e pour stocker un graphe . Ceci permet egalement de t r a i t e r toute t a i l l e de graphe . 23 24 l i s t e ∗∗deb=NULL; 25 l i s t e ∗∗ parc_tbl=NULL; 26 27 l i s t e ∗parc_chaine=NULL; 28 l i s t e ∗ prec=NULL; 29 30 int nbr_noeud=0,no_noeud=0, nbr_successeurs =0; 31 int no_succ=0, poid_arc=0; 32 33 int i =0; 34 35 f s c a n f ( src_graph , "%d" , &nbr_noeud ) ; 36 37 deb = ( l i s t e ∗∗) malloc ( nbr_noeud ∗ sizeof ( l i s t e ∗ ) ) ; 38 parc_tbl=deb ; 39 40 for ( i =0; i<nbr_noeud ; i++) 41 { 42 43 f s c a n f ( src_graph , "%d %d" , &no_noeud,& nbr_successeurs ) ; 44 prec = NULL; 45 46 i f ( nbr_successeurs ) 47 { 48 while ( nbr_successeurs != 0) 49 { 50 parc_chaine = ( l i s t e ∗) malloc ( sizeof ( l i s t e ) ) ; 51 f s c a n f ( src_graph , "%d %d" , &no_succ ,&poid_arc ) ; 52 parc_chaine−>noeud = no_succ ; 4
  • 6. 53 parc_chaine−>poid = poid_arc ; 54 parc_chaine−>suiv = NULL; 55 i f ( prec == NULL) ∗ parc_tbl = parc_chaine ; 56 else prec−>suiv = parc_chaine ; 57 prec = parc_chaine ; 58 nbr_successeurs −−; 59 } 60 } 61 else 62 { 63 ∗ parc_tbl = NULL; 64 } 65 parc_tbl++; 66 } 67 68 // Ci apres , la l e c t u r e du graphe donnant l e code necessaire au bon fonctionnement des u t i l i t a i r e s de graphviz . 69 70 // Cet algorithme revient a parcourir simplement la structure de donnee u t i l i s e e pour stocker l e graphe . Cette structure est presentee dans un autre paragraphe . 71 72 parc_tbl = deb ; 73 p r i n t f ( " digraph G {n" ) ; 74 p r i n t f ( "edge [ color=purple , arrowsize =2];n" ) ; 75 p r i n t f ( "node [ color=pink , s t y l e=f i l l e d ] ; n" ) ; 76 for ( i =0; i<nbr_noeud ; i++) 77 { 78 parc_chaine=∗parc_tbl ; 79 while ( parc_chaine!=NULL) 80 { 81 p r i n t f ( "%d −> %d [ l a b e l=%d ] ; n" , i , parc_chaine−>noeud , parc_chaine−>poid ) ; 82 parc_chaine=parc_chaine−>suiv ; 83 } 84 parc_tbl++; 85 } 86 p r i n t f ( "}n" ) ; 87 88 f c l o s e ( src_graph ) ; 89 90 return 0; 91 } Le fonctionnement de ce programme est simple, il prend en paramètre (lors de l’appel de l’exécutable) un nom de fichier (lien relatif) et en effectue la traduction vers le langage Graphviz. Afin de ne pas surcharger ce programme, nous avons préféré effectuer l’affichage en console du code généré, plutôt que le le faire passer via des tubes et des sous-process directement à l’utilitaire ’dot’. De ce fait, afin d’obtenir un graphique sous forme d’image (ici, de type png) la commande d’appel nécessite d’utiliser un pipe en console afin de router directement les code généré vers l’utilitaire : 1 ./ conv graph1 . txt | dot −Tpng −o t e s t . png Ce programme utilise une structure de données pour le stockage du graphe basée sur les listes chainées qui sera détaillée dans la prochaine section. 5
  • 7. 1.3 Structure de donnée liée au stockage du graphe La structure de donnée ici présentée est celle mise en place dans le programme de conversion précédent. Elle sera également utilisé lors de l’implémentation de l’algorithme de Djikstra et celui des k-plus courts chemins. Pour faire simple, cette structure de donnée se présente sous la forme d’un tableau d’éléments de type liste correspondant à chaque sommet. Chacun de ces sommets est ensuite lié à tous ses successeurs via une liste chainée. Cela permet non seulement de donner un sens à un arc, mais également de pouvoir tirer profit de la simplicité de représentation de cette structure de donnée pour y adapter tout type d’algorithme issu de la théorie des graphes. La structure de donnée est la suivante : 1 // Structure de donnee permettant d ’ obtenir l e s l i s t e s chainees 2 typedef struct l i s t e l i s t e ; 3 struct l i s t e 4 { 5 int noeud ; 6 int poid ; 7 l i s t e ∗ suiv ; 8 }; On peut ainsi représenter le stockage du graphe pris en exemple précédemment comme suit : Figure 1.3 – Représentation du stockage du graphe via des listes chainées En outre, l’utilisation de cette structure permet de parcourir le graphe de manière intuitive. En effet, on connait immédiatement tous les successeurs de chaque sommet, et les poids qui les relient. 1.4 Structure de donnée liée à l’algorithme de Dijkstra Pour l’algorithme de Dijkstra, deux structures sont nécessaire, l’une pour créer le tableau des distances, l’autre pour créer le tableau des prédécesseurs. Dans la pratique, une seule structure suffit car on peut référencer la distance ou le prédécesseur comme une simple donnée de type int. Comme le préconise l’algorithme de Dijkstra, cette structure doit également comporter un verrou, afin de ne pas écraser des données déjà traitées. La structure de donnée est la suivante : 1 typedef struct str_dijkstra str_dijkstra ; 6
  • 8. 2 struct str_dijkstra 3 { 4 int noeud ; 5 int data ; // La donnee peut etre : distance , ou n_o du predecesseur 6 int verrou ; 7 }; Ce verrou est présent dans les deux tableau, ce qui constitue une redondance puisque chaque élément des deux tableaux sont verrouillés en même temps. Mais cela constitue aussi une vérification quand au bon fonctionnement de l’algorithme. 1.5 Structure de donnée nécessaire à l’algorithme des k-plus courts chemins Pour résoudre ce problème nous allons utiliser deux structures de données spécifiques. Une structure appelée "nœud", qui sera la structure de l’arbre. Cette structure contiendra la valeur du sommet mis dans l’arbre ainsi que le poids de l’arc avec le sommet précédent (dans l’arbre). "nœud" contiendra également un pointeur vers son nœud père et, le nombre de fils pouvant varier, une liste de fils. 1 struct noeud 2 { 3 int valeur_sommet ; 4 int poid_prec_noeurd ; 5 l_Arbre∗ f i l s ; 6 noeud∗ pere ; 7 }; La liste de fils constitue la deuxième structure utilisée. Cette structure contient un pointeur vers un "nœud" de l’arbre, qui est le fils en question, ainsi qu’un pointeur vers le maillon suivant de la liste, le fils suivant. 1 struct l_Arbre 2 { 3 noeud∗ noeud_A ; 4 l_Arbre∗ suiv ; 5 }; C’est en combinant l’utilisation de ces deux structures que nous parviendrons à créer l’arbre représentant les chemins. Voici alors le schémas de la structure de l’arbre : 7
  • 9. Figure 1.4 – Représentation des structures de donnée nécessaire à la création d’un arbre 8
  • 10. Chapitre 2 Problème du plus court chemin 2.1 Présentation du problème Le cheminement dans les graphes, et plus précisément la recherche du plus court chemin, est un problème récurrent dans l’étude des graphes. Ces applications sont multiples : réseaux électriques ou réseaux d’information ou encore calcul d’itinéraire via des cartes, plusieurs algorithmes issus de la théorie des graphes permettent de répondre à ces problèmes mathématiques. Nous allons ici nous intéresser à l’algorithme de Dijkstra puis tenter de l’implémenter en langage C. L’algorithme de Dijkstra utilise deux tableaux, l’un de prédécesseurs, l’autre des plus courtes distances entre deux points quelconques. Avec l’application successive de l’algorithme de Dijkstra, on finit par obtenir le tableau du plus court chemin reliant la source à tous les autres sommets. Cela revient donc à effectuer un parcours ordonné du graphe en mettant à jour certaines in- formation dans les deux tableaux selon un certain nombre de règles. 2.2 Analyse de l’algorithme de Dijkstra Cet algorithme effectue l’initialisation de ses deux tableaux puis les remplie au fur et à mesure de son évolution dans le graphe et selon des contraintes bien définies. On peut repésenter l’algorithme comme suit : 1 Pour k de 1 a n , f a i r e : 2 distances [ k ] <−− cout ( s , k) ; 3 predecesseurs [ k ] <−− s ; 4 FinPour ; 5 M <−− Supprimer ( s , M) ; 6 7 TantQue (M non vide ) Faire : 8 i <−− LePlusProche (M) ; 9 Si ( distances [ i ] = i n f ) Alors retour ; 10 M <−− Supprimer ( i , M) ; 11 12 Pour k de 1 a d+( i ) Faire : 13 j <−− k−eme_successeur ( i ) ; 14 Si ( EstSupprime ( j , M) <> 1) 15 v <−− distances [ i ] + cout ( i , j ) ; 16 Si (v < distances [ j ] ) 17 Alors distances [ j ] <−− v ; 18 Alors predecesseurs [ j ] <−− i ; 19 FinSi 20 FinSi 9
  • 11. 21 FinPour 22 FinTantQue 2.3 Commentaires sur l’implémentation Pour implémenter cet algorithme, nous avons repris la structure de stockage de graphe vue dans le programme de conversion de langage, c’est à dire un tableau de listes chainées. Il est donc néces- saire de ré-implémenter sous forme de fonctions les algorithmes de génération de cette structure de graphe. Il y a ensuite un certains nombre de fonction à développer pour faire tourner l’algorithme de Dijkstra. Certaines fonctionnalités trop souvent utilisées seront également isolée en tant que fonction a part entière pour plus de clarté. Pour permettre a l’algorithme de Dijkstra de fonctionner, il est nécessaire de quantifier les dis- tances infinies. Nous avons donc choisi une distance maximale qu’aucun chemin ne doit dépasser afin que les comparaisons fonctionnent. 1 #define INF 999999999 2.4 Fonctions utiles à l’affichage 2.4.1 Fonction nécessaire à l’obtention du code Graphviz Reprise de l’utilitaire de conversion, cette petite fonction permet de rendre compte du graphe avec lequel on travail. Tout étant détaillé dans la partie correspondante au convertisseur, il ne semble pas nécessaire d’expliquer plus en détail son fonctionnement. 1 int to_graphviz ( l i s t e ∗∗deb , int nbr_noeud ) 2 { 3 l i s t e ∗∗ parc_tbl=NULL; 4 l i s t e ∗parc_chaine=NULL; 5 int i =0; 6 7 parc_tbl = deb ; 8 9 p r i n t f ( " digraph G {n" ) ; 10 p r i n t f ( "edge [ color=purple , arrowsize =2];n" ) ; 11 p r i n t f ( "node [ color=pink , s t y l e=f i l l e d ] ; n" ) ; 12 13 for ( i =0; i<nbr_noeud ; i++) 14 { 15 parc_chaine=∗parc_tbl ; 16 17 while ( parc_chaine!=NULL) 18 { 19 p r i n t f ( "%d −> %d [ l a b e l=%d ] ; n" , i , parc_chaine−>noeud , parc_chaine−>poid ) ; 20 parc_chaine=parc_chaine−>suiv ; 21 } 22 23 parc_tbl++; 24 } 25 10
  • 12. 26 p r i n t f ( "}n" ) ; 27 28 return 1; 29 } 2.4.2 Fonction d’affichage des tableaux liés à la structure de donnée spécifique à Dijkstra Cette petite fonction permet de vérifier que l’algorithme de Dijkstra effectue correctement le remplissage des tableaux en les affichant. 1 void aff_str_dijkstra ( str_dijkstra ∗ str , int nbr_noeud , char∗ mot) 2 { 3 4 int i =0; 5 6 for ( i = 0 ; i < nbr_noeud ; i ++) 7 { 8 p r i n t f ( "Noeud %d a pour %s %d du sommet %d . ( verrou : %d) n" , i , mot , ( s t r+i )−>data , ( s t r+i )−>noeud , ( s t r+i )−>verrou ) ; 9 } 10 11 } 2.5 Fonctions spécifiques au structures de données utilisées 2.5.1 Fonction de génération du graphe Comme pour le passage à Graphviz, cette fonction est issue du convertisseur précédemment traité. Elle prend en paramètre le fichier de l’utilisateur, et génère la structure de graphe de type tableau de listes chainées. 1 l i s t e ∗∗ generation_liste (FILE∗ src_graph , int∗ noeuds ) 2 { 3 int nbr_noeud=0,no_noeud=0, nbr_successeurs =0; 4 int nbr_successeurs_temp= 0 , no_succ=0, poid_arc=0; 5 6 int i =0; 7 8 l i s t e ∗∗deb=NULL; 9 l i s t e ∗∗ parc_tbl=NULL; 10 l i s t e ∗parc_chaine=NULL; 11 l i s t e ∗ prec=NULL; 12 13 f s c a n f ( src_graph , "%d" , &nbr_noeud ) ; 14 15 ∗noeuds = nbr_noeud ; 16 17 deb = ( l i s t e ∗∗) malloc ( nbr_noeud ∗ sizeof ( l i s t e ∗ ) ) ; 18 19 parc_tbl=deb ; 20 21 for ( i =0; i<nbr_noeud ; i++) 11
  • 13. 22 { 23 f s c a n f ( src_graph , "%d %d" , &no_noeud,& nbr_successeurs ) ; 24 prec = NULL; 25 26 i f ( nbr_successeurs ) 27 { 28 nbr_successeurs_temp = nbr_successeurs ; 29 while ( nbr_successeurs != 0) 30 { 31 parc_chaine = ( l i s t e ∗) malloc ( sizeof ( l i s t e ) ) ; 32 33 f s c a n f ( src_graph , "%d %d" , &no_succ ,&poid_arc ) ; 34 35 parc_chaine−>noeud = no_succ ; 36 parc_chaine−>poid = poid_arc ; 37 parc_chaine−>suiv = NULL; 38 39 parc_chaine−>nbr_successeurs = nbr_successeurs_temp ; 40 41 i f ( prec == NULL) ∗ parc_tbl = parc_chaine ; 42 else prec−>suiv = parc_chaine ; 43 44 prec = parc_chaine ; 45 nbr_successeurs −−; 46 } 47 } 48 49 else 50 { 51 ∗ parc_tbl = NULL; 52 } 53 54 parc_tbl++; 55 } 56 57 return deb ; 58 } Cette fonction retourne le premier élément du tableau afin de pouvoir le parcourir dans les autres fonctions. 2.5.2 Fonction d’affichage des tableaux liés à la structure de donnée spécifique à Dijkstra Cette petite fonction permet de vérifier que l’algorithme de Dijkstra effectue correctement le remplissage des tableaux en les affichant. 1 void aff_str_dijkstra ( str_dijkstra ∗ str , int nbr_noeud , char∗ mot) 2 { 3 4 int i =0; 5 6 for ( i = 0 ; i < nbr_noeud ; i ++) 7 { 8 p r i n t f ( "Noeud %d a pour %s %d du sommet %d . ( verrou : %d) n" , i , mot , ( s t r+i )−>data , ( s t r+i )−>noeud , ( s t r+i )−>verrou ) ; 12
  • 14. 9 } 10 11 } 2.6 Fonctions utiles à l’algorithme de Dijkstra 2.6.1 Fonction retournant le poids de l’arc entre deux sommets Cette fonction permet de connaitre le poids de l’arc entre deux sommets. Si ces deux sommets ne sont pas directement reliés par un arc, cette fonction renvoie la valeur de l’infini quantifié comme expliqué précédemment. 1 int get_poid ( l i s t e ∗∗ deb , int nbr_noeud , int sommet , int suivant ) 2 { 3 l i s t e ∗∗ parc_tbl = NULL; 4 l i s t e ∗parc_chaine = NULL; 5 int i =0, poid = INF ; 6 7 parc_tbl = deb ; 8 9 for ( i =0; i<nbr_noeud ; i++) 10 { 11 parc_chaine=∗parc_tbl ; 12 13 while ( parc_chaine!=NULL) 14 { 15 i f ( i == sommet && parc_chaine−>noeud == suivant ) 16 { 17 poid = parc_chaine−>poid ; 18 return poid ; 19 } 20 21 parc_chaine=parc_chaine−>suiv ; 22 } 23 24 parc_tbl++; 25 } 26 27 return poid ; 28 } 2.6.2 Trouver la distances minimum depuis le tableau des distances Cette fonction permet à l’algorithme de Dijkstra de travailler sur le tableau des distances, et renvoie le sommet correspondant à la distance la plus petite qui n’a pas déjà été verrouillée. 1 int find_dist_min ( str_dijkstra ∗ distances , int nbr_noeud ) 2 { 3 // Le premier noeud est toujours l e point source 4 int i = 0 , minimum = INF , sommet = −1; 5 6 for ( i = 0; i < nbr_noeud ; i++) 7 { 13
  • 15. 8 i f (( distances+i )−>data < minimum && ( distances+i )−>verrou == 0) 9 { 10 minimum = ( distances+i )−>data ; 11 sommet = i ; 12 } 13 } 14 15 return sommet ; 16 } 2.6.3 Fonction permettant de retrouver les successeurs d’un sommet Cette fonction travail sur un tableau temporaire et y stock tous les successeurs d’un sommet donné. Elle retourne en outre le nombre de successeurs. 1 int find_successeurs ( int sommet , l i s t e ∗∗deb , int nbr_noeud , str_dijkstra ∗ temp) 2 { 3 int i = 0; 4 l i s t e ∗parc_chaine = NULL; 5 6 parc_chaine=∗(deb+sommet) ; 7 8 while ( parc_chaine!=NULL) 9 { 10 temp [ parc_chaine−>noeud ] . data = 1; 11 parc_chaine=parc_chaine−>suiv ; 12 i ++; 13 } 14 15 return i ; 16 } 2.6.4 Fonction de verrouillage des deux tableaux Comme expliqué précédemment, les deux tableau se verrouillent systématiquement ensemble. Il est donc plus simple de créer une fonction à cet égard. 1 void v e r r o u i l l e r ( int sommet , str_dijkstra ∗ distances , str_dijkstra ∗ predecesseurs ) 2 { 3 ( distances+sommet)−>verrou = 1; 4 ( predecesseurs+sommet)−>verrou = 1; 5 } 2.6.5 Initialisation nécessaire à l’algorithme de Dijkstra L’algorithme de Dijkstra travaille sur deux tableau, comme explicité précédemment, mais il faut au préalable préparer ces tableaux. Initialiser le tableau des distances ainsi que le tableau des prédécesseurs et verrouiller le premier élément, le sommet source. 14
  • 16. 1 void i n i t ( l i s t e ∗∗ deb , str_dijkstra ∗ predecesseurs , str_dijkstra ∗ distances , int nbr_noeud ) 2 { 3 /∗ 4 Permet d ’ i n i t i a l i s e r correctement l e s deux 5 tableaux contenant l e s distances et l e s predecesseurs 6 en parcourant la l i s t e de l i s t e s chainees 7 ∗/ 8 9 l i s t e ∗parc_chaine = NULL; 10 11 int i =0, poid = INF ; // INF = 999999999 12 13 // I n i t i a l i s a t i o n des valeurs de verrou et des predecesseurs 14 for ( i = 0 ; i < nbr_noeud ; i ++) 15 { 16 ( distances+i )−>data = poid ; 17 ( predecesseurs+i )−>data = 0; 18 19 20 ( distances+i )−>verrou = 0; 21 ( predecesseurs+i )−>verrou = 0; 22 } 23 24 distances −> verrou = 1; // Verouillage du premier element 25 predecesseurs −> verrou = 1; // 26 27 parc_chaine=∗deb ; 28 29 // i n i t i a l i s a t i o n des valeurs des distances 30 while ( parc_chaine!=NULL) 31 { 32 distances [ parc_chaine−>noeud ] . data = parc_chaine−>poid ; 33 parc_chaine=parc_chaine−>suiv ; 34 } 35 } 2.6.6 L’algorithme en lui même Ci après le code de l’algorithme de Dijkstra comme défini plus haut, en utilisant la structure de stockage du graphe donnée. 1 int algo ( l i s t e ∗∗ deb , str_dijkstra ∗ predecesseurs , str_dijkstra ∗ distances , int nbr_noeud ) 2 { 3 4 /∗ 5 Fonction recursive implementant l ’ algorithme de Dijkstra . 6 Cette fonction remplie correctement l e s deux tableaux 7 de distances et de predecesseurs . 8 Les noeux sans predecesseurs ont une distance a la source de 999999999. 9 ∗/ 10 11 str_dijkstra ∗temp = NULL; 15
  • 17. 12 temp = ( str_dijkstra ∗) c a l l o c ( nbr_noeud , sizeof ( str_dijkstra ) ) ; 13 14 15 int noeud_plus_proche = 0; 16 int nbr_successeurs = 0; 17 int i = 0 , temp_int = 0; 18 19 noeud_plus_proche = find_dist_min ( distances , nbr_noeud ) ; 20 21 i f ( noeud_plus_proche == −1) 22 { 23 perror ( "nPas de p o s s i b i l i t e d ’ appliquer l ’ algo encore une f o i s " ) ; 24 return 1; 25 } 26 27 // Le tableau temp contient la data = 1 s i l e sommet correspondant a la position dans l e tableau est un predecesseur . 28 nbr_successeurs = find_successeurs ( noeud_plus_proche , deb , nbr_noeud , temp) ; 29 30 // Remplissage des tabelaux de distances et des predecesseurs . 31 for ( i = 0 ; i < nbr_noeud ; i++ ) 32 { 33 i f (( temp+i )−>data == 1 && ( distances+i )−>verrou == 0) 34 { 35 temp_int = ( distances+noeud_plus_proche )−>data + get_poid ( deb , nbr_noeud , noeud_plus_proche , i ) ; 36 37 ( predecesseurs+i )−>data = noeud_plus_proche ; 38 39 i f (( distances+i )−>data > temp_int ) ( distances+i )−>data = temp_int ; 40 } 41 } 42 43 // Verrouillage des noeux concernes . 44 v e r r o u i l l e r ( noeud_plus_proche , distances , predecesseurs ) ; 45 46 // Desallocation de la memoire . 47 f r e e (temp) ; 48 49 return algo ( deb , predecesseurs , distances , nbr_noeud ) ; 50 } 2.6.7 La fonction main Ci après, la fonction main() donne l’ordre d’appel des différentes fonctions. 1 int main ( int argc , char ∗argv [ ] ) 2 { 3 i f ( argv [ 1 ] == NULL) 4 { 5 p r i n t f ( " Error : no input f i l e . n" ) ; 6 return 1; 7 } 16
  • 18. 8 9 FILE∗ src_graph=fopen ( argv [ 1 ] , " r " ) ; 10 11 l i s t e ∗∗deb = NULL; 12 13 str_dijkstra ∗ distances = NULL; 14 str_dijkstra ∗ predecesseurs = NULL; 15 16 17 int nbr_noeud = 0; 18 19 deb = generation_liste ( src_graph , &nbr_noeud ) ; 20 21 distances = ( str_dijkstra ∗) c a l l o c ( nbr_noeud , sizeof ( str_dijkstra ) ) ; 22 predecesseurs = ( str_dijkstra ∗) c a l l o c ( nbr_noeud , sizeof ( str_dijkstra ) ) ; 23 24 i n i t ( deb , predecesseurs , distances , nbr_noeud ) ; 25 26 algo ( deb , predecesseurs , distances , nbr_noeud ) ; 27 28 p r i n t f ( "n" ) ; 29 aff_str_dijkstra ( distances , nbr_noeud , " distance " ) ; 30 p r i n t f ( "n" ) ; 31 32 aff_str_dijkstra ( predecesseurs , nbr_noeud , " predecesseur " ) ; 33 p r i n t f ( "n" ) ; 34 35 /∗ to_graphviz ( deb , nbr_noeud ) ; ∗/ 36 noeud∗ r=(noeud ∗) malloc ( sizeof ( noeud ) ) ; 37 38 r=algo_k ( r , deb , ( ( ∗ deb )−>nbr_successeurs ) ) ; 39 40 f c l o s e ( src_graph ) ; 41 42 // Desallocation de la memoire . 43 f r e e ( distances ) ; 44 f r e e ( predecesseurs ) ; 45 46 return 0; 47 } 17
  • 19. Chapitre 3 Problème des K-plus courts chemins 3.1 Présentation du problème Le but est d’implémenter un algorithme qui permettra d’afficher tous les chemins d’un nœud de départ à nœud d’arrivée dans un graphe. Pour résoudre ce problème nous avons décider de stocker ces chemins dans un arbre qui contiendra les numéros des nœuds et le poids de l’arc avec le nœud parent. Figure 3.1 – Schéma du graphe considéré Ainsi ce graphe donnerai : Figure 3.2 – Arbre du graphe considéré Cet arbre représente les chemins possibles pour aller de 0 à 3. La branche qui se termine par le 4 est une branche "terminale", c’est à dire qu’elle ne pourra jamais mener à 3, elle ne représente donc pas un chemin. pour trouver les k plus court chemins il nous suffit de parcourir l’arbre et de compter la somme des poids de chaque branche. Chaque branche se terminant par une feuille 3 représente un chemin. 18
  • 20. 3.2 Analyse de l’algorithme des k-plus court chemins Comme dit précédemment, l’algorithme des k-plus court chemins utilisé est un algorithme qui créé un arbre contenant la liste de tout les chemins possibles d’un point à un autre. L’algorithme théorique se définit comme suit : 1 Algorithme k plus court ( noeud i n i t i a l , noeud f i n a l ) 2 racine de l ’ arbre = noeud i n i t i a l 3 de 0 a nombre de noeud f a i r e : 4 s i nombre de f i l s = 0 f a i r e 5 retourner noeud i n i t i a l 6 sinon f a i r e 7 chaque successeur devient un f i l s . 8 pour chaque f i l s f a i r e : 9 s i f i l s d i f f e r e n d de noeud f i n a l f a i r e 10 f i l s = Algorithme k plus court ( f i l s , noeud f i n a l ) 11 sinon s i f i l s = noeud f i n a l f a i r e 12 retourner f i l s 13 f i n de 14 retourner noeud i n i t i a l 15 f i n Algorithme k plus court L’algorithme consiste à créer, de manière récursive, la liste de fils du nœud actuel (en fonction des successeurs). Puis pour chacun des fils on répète l’opération, ainsi à la fin on obtient bien une structure semblable à celle présenté dans la partie structure de données utilisée. 3.3 Commentaires sur l’implémentation En ce qui concerne l’implémentation de l’algorithme nous n’avons pas réussit à aboutir malgré plusieurs essais et reprises du code. Nous avons cependant réussit à implémenter la partie qui crée les fils correspondants aux successeurs. Il manque donc la partie récursive de notre algorithme. 3.3.1 Fonction d’affichage de l’arbre Cette fonction à simplement pour but d’afficher l’arbre contenant tout les successeurs pour pouvoir visualiser les chemins. 1 int afficher_arbre_RGD ( noeud∗ racine ) 2 { 3 p r i n t f ( "Debut a f f i c h a g e n" ) ; 4 i f ( racine==NULL) 5 { 6 p r i n t f ( " racine null . n" ) ; 7 return 0; 8 } 9 else 10 { 11 l_Arbre∗ parc=(racine −>f i l s ) ; 12 // on a f f i c h e l e pere 13 p r i n t f ( "Sommet %d : " , racine −>valeur_sommet ) ; 14 p r i n t f ( "Poid_prec %d | " , racine −>poid_prec_noeurd ) ; 15 // on passe au f i l s 16 while ( parc−>noeud_A!=NULL ) 17 { 18 afficher_arbre_RGD ( parc−>noeud_A) ; 19
  • 21. 19 parc=parc−>suiv ; 20 } 21 return 1; 22 23 } 24 } 3.3.2 Fonction de création des nœuds des successeurs Celte fonction à pour but de créer la liste des nœuds fils contenant les successeurs du nœud racine envoyé en paramètre. Elle retourne un pointeur vers cette liste de fils. 1 l_Arbre∗ creerSucc ( noeud∗ racine , l i s t e ∗∗ deb , int nbr_noeud ) 2 { 3 int i =0, j =0; 4 5 i f (∗ deb==NULL) // s i la l i s t e des successeurs est vide on ne cree rien 6 { 7 return NULL; 8 } 9 // on recupere l e nombre de successeurs 10 int nbr_successeurs =((∗deb )−>nbr_successeurs ) ; 11 p r i n t f ( " nbr_successeurs=%dn" , nbr_successeurs ) ; 12 13 racine −>f i l s = ( l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ; 14 l_Arbre∗ parc= racine −>f i l s ; 15 l i s t e ∗ parc_l = ∗deb ; 16 17 while ( i<nbr_successeurs ) // pour chacun des successeurs 18 { 19 20 p r i n t f ( " f i l s %d n" , i ) ; 21 // on cree un noeud f i l s correspondant au successeur 22 noeud∗ temp = ( noeud ∗) malloc ( sizeof ( noeud ) ) ; 23 // on r e l i e ce noeud a son pere 24 parc−>noeud_A = temp ; 25 // on met l e s bonnes valeurs dans ce noeud 26 parc−>noeud_A−>valeur_sommet=parc_l−>noeud ; 27 parc−>noeud_A−>poid_prec_noeurd=parc_l−>poid ; 28 parc−>noeud_A−>pere=racine ; 29 parc−>noeud_A−>f i l s=NULL; 30 p r i n t f ( "%d , %d n" , parc−>noeud_A−>valeur_sommet , parc−>noeud_A−> poid_prec_noeurd ) ; 31 i f ( i != nbr_successeurs ) // s i ce n ’ est pas l e dernier successeur 32 { 33 // on a l l o u e de la place pour l e noeud suivant 34 parc−>suiv=(l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ; 35 } 36 // on passe au suivant 37 parc=parc−>suiv ; 38 parc_l=parc_l−>suiv ; 39 i ++; 40 } 41 parc=NULL; 20
  • 22. 42 43 return racine −>f i l s ; // on renvoie la l i s t e des f i l s du noeud pere 44 45 } 3.3.3 Fonction algorithme des k plus court chemins Cette fonction à normalement pour but de dérouler l’algorithme. Mais dans notre cas comme l’implémentation n’as rien donnée elle ne déroulera l’algorithme que sur le nœud de départ et ses fils. 1 noeud∗ algo_k ( noeud∗ racine , l i s t e ∗∗ deb , int nbr_noeud ) 2 { 3 4 int ret =0, i =0, nbr_succ=0; 5 l_Arbre∗ f i l s =(l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ; 6 l_Arbre∗ tmp=(l_Arbre ∗) malloc ( sizeof ( l_Arbre ) ) ; 7 l i s t e ∗∗ parc_deb = deb ; 8 9 // i n i t i a l i s a t i o n : sommet 0 10 // on cree l e s f i l s du somet 0 11 f i l s=creerSucc ( racine , parc_deb , nbr_noeud ) ; 12 13 nbr_succ=(∗parc_deb )−>nbr_successeurs ; 14 15 // pour chacun des successeurs 16 17 for ( i =0; i<nbr_succ ; i++) 18 { 19 // successeur i 20 p r i n t f ( "n Sommet : %d n " , f i l s −>noeud_A−>valeur_sommet ) ; 21 parc_deb= ( deb + f i l s −>noeud_A−>valeur_sommet ) ; 22 // on cree l e s f i l s de chacun des sommet correspondant au successeurs . 23 tmp=creerSucc ( f i l s −>noeud_A , parc_deb , nbr_noeud ) ; 24 f i l s=f i l s −>suiv ; 25 } 26 27 p r i n t f ( "lancement a f f i c h a g e n" ) ; 28 29 // a f f i c h a g e de l ’ arbre 30 ret = afficher_arbre_RGD ( racine ) ; 31 p r i n t f ( "%dn" , ret ) ; 32 33 return racine ; 34 } 21