les graphes. graphes un graphe g = (v, e) consiste en un ensemble v de noeud, et un ensemble e...

Post on 04-Apr-2015

105 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Les Graphes

Graphes

Un graphe G = (V, E) consiste en un ensemble V de noeud, et un ensemble E d’arêtes, tels que chaque arête dans E relie une paire de nœuds dans V.

Le nombre de nœuds est dénoté |V|, et le nombre d’arêtes est dénoté |E|.

Graphes (2)

Un graphe peut être dirigé ou non dirigé.

Chemins et cyclesChemin (de longueur n): Une séquence de

noeuds v0, v1, …, vn avec une arête de vi à vi+1 pour chaque 0 <= i < n.

Un chemin est simple si tous les nœuds dans le chemin sont distincts.

Un cycle est un chemin de longueur 3 ou plus reliant un nœud vi à lui même.

Un cycle est simple si le chemin est simple, sauf que les premiers et derniers nœuds sont les même.

Composantes connexes

Un graphe non dirigé est connexe s’il existe un chemin entre toutes les paires de nœuds.

Les sous-graphes connexes maximaux sont appelés composantes connexes

Représentation (dirigé)

Représentation (non dirigé)

Coût de la représentation

Matrice d’adjacence:

Listes d’adjacence:

|)|(| 2V

|)||(| EV

Graphe: Type de donnée abstrait class Graph { // Classe abstraitepublic: virtual int n() =0; // # de noeuds virtual int e() =0; // # d’arêtes // Retourne l’indice du premier voisin virtual int first(int) =0;// Retourne l’indice de prochain voisin

virtual int next(int, int) =0; // Insère une nouvelle arête virtual void setEdge(int, int, int) =0; // Enlève une arête virtual void delEdge(int, int) =0; // Retourne la longueur de l’arête virtual int weight(int, int) =0;// Retourne la valeur d’un noeud

virtual int getMark(int) =0;// Assigne une valeur à un noeudvirtual void setMark(int, int) =0;

};

Implémentation(matrice d’adjacence)

#define UNVISITED 0#define VISITED 1

class Graphm : public Graph { private: int numVertex, numEdge; int **matrix; int *mark;

public:

Graphm(int numVert) { int i, j; numVertex = numVert; numEdge = 0; mark = new int[numVert]; for (i=0; i<numVertex; i++) mark[i] = UNVISITED; matrix = (int**) new int*[numVertex]; for (i=0; i<numVertex; i++) matrix[i] = new int[numVertex]; for (i=0; i< numVertex; i++) for (int j=0; j<numVertex; j++) matrix[i][j] = 0; }

~Graphm() { delete [] mark; for (int i=0; i<numVertex; i++) delete [] matrix[i]; delete [] matrix; }

int n() { return numVertex; }

int e() { return numEdge; }

int first(int v) { int i; for (i=0; i<numVertex; i++) if (matrix[v][i] != 0) return i; return i; }

// Donne le voisin de v1 après v2 int next(int v1, int v2) { int i; for(i=v2+1; i<numVertex; i++) if (matrix[v1][i] != 0) return i; return i; }

void setEdge(int v1, int v2, int wgt) { if (matrix[v1][v2] == 0) numEdge++; matrix[v1][v2] = wgt; }

void delEdge(int v1, int v2) { if (matrix[v1][v2] != 0) numEdge--; matrix[v1][v2] = 0; }

int weight(int v1, int v2) { return matrix[v1][v2]; }

int getMark(int v) { return mark[v]; }

void setMark(int v, int val) { mark[v] = val; }};

class Edge {public: int vertex, weight; Edge() { vertex = -1; weight = -1; } Edge(int v, int w) { vertex = v; weight = w; }};

Implémentation(liste d’adjacence)

class Graphl : public Graph { private: int numVertex, numEdge; List<Edge>** vertex; int *mark; public: Graphl(int numVert) { int i, j; numVertex = numVert; numEdge = 0; mark = new int[numVert]; for (i=0; i<numVertex; i++) mark[i] = UNVISITED; // Crée et initialise la liste d’adjacence vertex = (List<Edge>**) new List<Edge>*[numVertex]; for (i=0; i<numVertex; i++) vertex[i] = new LList<Edge>(); }

~Graphl() { delete [] mark; for (int i=0; i<numVertex; i++) delete [] vertex[i]; delete [] vertex; }

int n() { return numVertex; } int e() { return numEdge; }

int first(int v) { Edge it; vertex[v]->setStart(); if (vertex[v]->getValue(it)) return it.vertex; else return numVertex; }

int next(int v1, int v2) { Edge it; vertex[v1]->getValue(it); if (it.vertex == v2) vertex[v1]->next(); else { vertex[v1]->setStart(); while (vertex[v1]->getValue(it) && (it.vertex <= v2)) vertex[v1]->next(); } if (vertex[v1]->getValue(it)) return it.vertex; else return numVertex; }

void setEdge(int v1, int v2, int wgt) { Edge it(v2, wgt); Edge curr; vertex[v1]->getValue(curr); if (curr.vertex != v2) for (vertex[v1]->setStart(); vertex[v1]->getValue(curr); vertex[v1]->next()) if (curr.vertex >= v2) break; if (curr.vertex == v2) vertex[v1]->remove(curr); else numEdge++; vertex[v1]->insert(it); }

void delEdge(int v1, int v2) { Edge curr; vertex[v1]->getValue(curr); if (curr.vertex != v2) for (vertex[v1]->setStart(); vertex[v1]->getValue(curr); vertex[v1]->next()) if (curr.vertex >= v2) break; if (curr.vertex == v2) { vertex[v1]->remove(curr); numEdge--; } }

int weight(int v1, int v2) { Edge curr; vertex[v1]->getValue(curr); if (curr.vertex != v2) for (vertex[v1]->setStart(); vertex[v1]->getValue(curr); vertex[v1]->next()) if (curr.vertex >= v2) break; if (curr.vertex == v2) return curr.weight; else return 0; }

int getMark(int v) { return mark[v]; } void setMark(int v, int val) { mark[v] = val; }};

Parcours d’un graphe

Certaines applications nécessitent de visiter chaque nœuds exactement une fois.

Une application peut demander de visiter les nœuds dans un ordre particulier en accord avec la topologie du graphe.

Exemples:• Jeu d’échec• Chemin le plus court

Parcours d’un graphe(2)

Pour s’assurer de visiter tous les noeuds:

void graphTraverse(const Graph* G) { for (v=0; v<G->n(); v++) G->setMark(v, UNVISITED); //Initialisation for (v=0; v<G->n(); v++) if (G->getMark(v) == UNVISITED) doTraverse(G, v);}

Parcours en profondeur (1)

void DFS(Graph* G, int v) { PreVisit(G, v); G->setMark(v, VISITED); for (int w=G->first(v); w<G->n(); w = G->next(v,w)) if (G->getMark(w) == UNVISITED) DFS(G, w); PostVisit(G, v); }

Fouille en profondeur(2)

Coût: (|V| + |E|).

Parcours en largeur (1)

Comme la fouille en profondeur, sauf qu’on remplace la pile par une file d’attente:

– On visite les voisins d’un nœuds avant d’aller plus en profondeur dans le graphe.

Parcours en largeur (2)

void BFS(Graph* G, int start,Queue<int>*Q) { int v, w; Q->enqueue(start); G->setMark(start, VISITED); while (Q->length() != 0) { Q->dequeue(v); PreVisit(G, v); for(w=G->first(v);w<G->n();w=G->next(v,w)) if (G->getMark(w) == UNVISITED) { G->setMark(w, VISITED); Q->enqueue(w); } PostVisit(G, v); }}

Parcours en largeur (3)

Tri topologique(1)

Problème: Étant donné un ensemble de tâches à accomplir (certaines tâches devant être effectuées avant d’autres), afficher les tâches dans un ordre qui respecte leur ordonnancement.

Tri topologique(2)void topsort(Graph* G) { // Tri topologique int i; for (i=0; i<G->n(); i++) // Initialisation G->setMark(i, UNVISITED); for (i=0; i<G->n(); i++) // traiter chaque

// composante connexe if (G->getMark(i) == UNVISITED) tophelp(G, i); }

void tophelp(Graph* G, int v) { G->setMark(v, VISITED); for (int w=G->first(v); w<G->n(); w = G->next(v,w)) if (G->getMark(w) == UNVISITED) tophelp(G, w); printout(v); // PostVisite}

Tri topologique (3)

Utiliser une filevoid topsort(Graph* G, Queue<int>* Q) { int Count[G->n()]; int v, w; for (v=0; v<G->n(); v++) Count[v] = 0; for (v=0; v<G->n(); v++) for (w=G->first(v); w<G->n(); w = G->next(v,w)) Count[w]++; // Add to v2's count for (v=0; v<G->n(); v++) // Initialise Q if (Count[v] == 0) Q->enqueue(v); while (Q->length() != 0) { Q->dequeue(v) printout(v); // PréVisite de V for (w=G->first(v); w<G->n(); w = G->next(v,w)) { Count[w]--; if (Count[w] == 0) Q->enqueue(w); }}}

top related