Вы находитесь на странице: 1из 13

The Graph Data Structure

Mugurel Ionu Andreica


Spring 2012

The Elements of a Graph


Vertices (nodes)
Numbered from 0 to N-1 (N=total number of vertices)

Edges
Each edge connects two vertices: (i,j) = edge between i and j Undirected graphs: the edge (i,j) is equivalent to the edge (j,i) Directed graphs: the edges are directed (they are sometimes called arcs) => i->j is different from j->i (although they both connect i and j) We will only consider graphs where no edge occurs twice (and there are no loops)

Both vertices and edges can have extra information associated to them (e.g. name, cost) Graphs can be used for modeling many structures, for example:
Road networks Social relationships

Undirected Graph - example


0

N=7 vertices (nodes) Edges


(0,1) (0,2) (0,3) (1,5) (1,6) (2,5) (3,4) (4,6)

Graph Representations
Adjacency matrix
A = an NxN matrix A[i][j] = 1 if the edge (i,j) occurs in the graph (i.e. the vertices i and j are connected by an edge), and 0 otherwise for undirected graphs A[i][j] = 1 if there is a directed arc from i to j for directed graphs A is symmetrical (A[i][j] == A[j][i]) for undirected graphs

Lists of neighbors
An array of N linked-lists The list L[i] contains all the neighbors of the vertex i In the case of directed graphs, the neighbors of a vertex are considered to be those nodes j such that the arch i->j exists

(Simplifying) Assumptions
No multiple edges (i,j) No loops (i,i)

Graph Traversals
Depth-First Search (DFS)
Mark all the vertices as not visited Starting vertex S => call dfs(S) dfs(x)
Mark x as visited For y in Neighbors(X):
If (y has not been marked as visited) then call dfs(y)

DFS is the building block for many more advanced algorithms


A simple application: check if a graph is connected

Breadth-First Search (BFS)


Mark all the vertices as not visited and initialize an empty queue Q Starting vertex S => insert S into a queue Q (Q.enqueue(S)) and mark S as visited While Q is not empty:
x = Q.dequeue() For y in Neighbors(X):
If (y has not been marked as visited) then Mark y as visited Q.enqueue(y)

BFS can be used for computing shortest paths in the graph

Using the Adjacency Matrix (Undirected Graph)


#include <stdio.h> #include "queue1.h" template<typename TnodeInfo, typenameTedgeInfo> class Graph { public: int N; char **A; TnodeInfo *nodeInfo; TedgeInfo **edgeInfo; Graph(int numNodes) { int i, j; for (i = 0; i < N; i++) for (j = 0; j < N; j++) A[i][j] = 0; // allocate the array with node information nodeInfo = new TnodeInfo[N]; // allocate the matrix of edge information edgeInfo = new TedgeInfo*[N]; for (i = 0; i < N; i++) edgeInfo[i] = new TedgeInfo[N]; } void setNodeInfo(int i, TnodeInfo info) { nodeInfo[i] = info; } TnodeInfo getNodeInfo(int i) { return nodeInfo[i]; } void addEdge(int i, int j) { A[i][j] = A[j][i] = 1; }

N = numNodes;
// allocate the adjacency matrix A = new char*[N]; for (i = 0; i < N; i++) A[i] = new char[N];

Using the Adjacency Matrix (cont.)


void removeEdge(int i, int j) { A[i][j] = A[j][i] = 0; } void setEdgeInfo(int i, int j, TedgeInfo info) { edgeInfo[i][j] = edgeInfo[j][i] = info; } TedgeInfo getEdgeInfo(int i, int j) { return edgeInfo[i][j]; } } ~Graph() { int i; for (i = 0; i < N; i++) { delete A[i]; delete edgeInfo[i]; } delete A; delete edgeInfo; delete nodeInfo; } }; Graph<int, int> g(7); char* visited; while (!Q.isEmpty()) { x = Q.dequeue(); printf("%d: dist=%d\n", x, dist[x]); int *dist; void bfs(int S) { Queue<int> Q; int x, y; void dfs(int x) { int y; printf("%d\n", x); visited[x] = 1; for (y = 0; y < g.N; y++) if (g.A[x][y] && !visited[y]) dfs(y);

Q.enqueue(S); visited[S] = 1; dist[S] = 0;

Using the Adjacency Matrix (cont.)


for (y = 0; y < g.N; y++) if (g.A[x][y] && !visited[y]) { visited[y] = 1; dist[y] = dist[x] + 1; Q.enqueue(y); } } } int main() { int i; g.addEdge(0, 1); g.addEdge(0, 2); g.addEdge(0, 3); g.addEdge(1, 6); g.addEdge(2, 5); g.addEdge(3, 4); g.addEdge(4, 6); g.addEdge(5, 1); for (i = 0; i < g.N; i++) visited[i] = 0; dist = new int[g.N]; printf("BFS:\n"); bfs(4); return 0; } visited = new char[g.N]; for (i = 0; i < g.N; i++) visited[i] = 0; printf("DFS:\n"); dfs(4);

Using the Lists of Neighbors (Undirected Graph)


#include <stdio.h> #include "linked_list.h" #include "queue1.h" template<typename TedgeInfo> struct list_elem_info { int node; TedgeInfo edgeInfo; }; void setNodeInfo(int i, TnodeInfo info) { nodeInfo[i] = info; } TnodeInfo getNodeInfo(int i) { return nodeInfo[i]; } void addEdge(int i, int j) { struct list_elem_info<TedgeInfo> lei_i, lei_j; lei_i.node = j; lei_j.node = i; L[i].addFirst(lei_i); L[j].addFirst(lei_j); } Graph(int numNodes) { N = numNodes; L = new LinkedList<struct list_elem_info<TedgeInfo> > [N]; nodeInfo = new TnodeInfo[N]; } void removeEdge(int i, int j) { struct list_elem<struct list_elem_info<TedgeInfo> > *p;

template<typename TnodeInfo, typename TedgeInfo> class Graph { public: int N; LinkedList<struct list_elem_info<TedgeInfo> > *L; TnodeInfo *nodeInfo;

Using the Lists of Neighbors (cont.)


p = L[i].pfirst; while (p != NULL) { if (p->info.node == j) break; p = p->next; } // remove the element pointed to by p from L[i] -- code ommitted p = L[i].pfirst; while (p != NULL) { if (p->info.node == j) break; p = p->next; } p->info.edgeInfo = info; p = L[j].pfirst; while (p != NULL) { if (p->info.node == i) break; p = p->next; } p->info.edgeInfo = info;

p = L[j].pfirst; while (p != NULL) { if (p->info.node == i) break; p = p->next; } }


// remove the element pointed to by p from L[j] -- code ommitted } void setEdgeInfo(int i, int j, TedgeInfo info) { struct list_elem<struct list_elem_info<TedgeInfo> > *p;

TedgeInfo getEdgeInfo(int i, int j) { struct list_elem<struct list_elem_info<TedgeInfo> > *p;

Using the Lists of Neighbors (cont.)


p = L[i].pfirst; while (p != NULL) { if (p->info.node == j) break; p = p->next; } return p->info.edgeInfo; } ~Graph() { int i; delete nodeInfo; for (i = 0; i < N; i++) while (!L[i].isEmpty()) L[i].removeFirst(); delete L; } }; Graph<int, int> g(7); char* visited; while (p != NULL) { y = p->info.node; if (!visited[y]) dfs(y); p = p->next; } } int *dist; void bfs(int S) { Queue<int> Q; int x, y; struct list_elem<struct list_elem_info<int> > *p; void dfs(int x) { int y; struct list_elem<struct list_elem_info<int> > *p; printf("%d\n", x); visited[x] = 1; p = g.L[x].pfirst;

Using the Lists of Neighbors (cont.)


Q.enqueue(S); visited[S] = 1; dist[S] = 0; while (!Q.isEmpty()) { x = Q.dequeue(); printf("%d: dist=%d\n", x, dist[x]); p = g.L[x].pfirst; while (p != NULL) { y = p->info.node; if (!visited[y]) { visited[y] = 1; dist[y] = dist[x] + 1; Q.enqueue(y); } p = p->next; } } } } return 0; int main() { int i; g.addEdge(0, 1); g.addEdge(0, 2); g.addEdge(0, 3); g.addEdge(1, 6); g.addEdge(2, 5); g.addEdge(3, 4); g.addEdge(4, 6); g.addEdge(5, 1); visited = new char[g.N]; for (i = 0; i < g.N; i++) visited[i] = 0; printf("DFS:\n"); dfs(4); for (i = 0; i < g.N; i++) visited[i] = 0; dist = new int[g.N]; printf("BFS:\n"); bfs(4);

Implementing Directed Graphs


What needs to be changed in the previous two implementations in order to have directed graphs instead of undirected graphs ?

Вам также может понравиться