For y in Neighbors(X)

advertisement
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
• N=7 vertices (nodes)
• Edges
0
1
2
3
4
5
6
–
–
–
–
–
–
–
–
(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)
for (i = 0; i < N; i++)
for (j = 0; j < N; j++) A[i][j] = 0;
#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;
// 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;
}
N = numNodes;
// allocate the adjacency matrix
A = new char*[N];
for (i = 0; i < N; i++)
A[i] = new char[N];
TnodeInfo getNodeInfo(int i) {
return nodeInfo[i];
}
void addEdge(int i, int j) {
A[i][j] = A[j][i] = 1; }
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; }
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);
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;
}
int *dist;
void bfs(int S) {
Queue<int> Q;
int x, y;
Q.enqueue(S);
visited[S] = 1;
dist[S] = 0;
};
Graph<int, int> g(7);
char* visited;
while (!Q.isEmpty()) {
x = Q.dequeue();
printf("%d: dist=%d\n", x, dist[x]);
Using the Adjacency Matrix (cont.)
visited = new char[g.N];
for (i = 0; i < g.N; i++)
visited[i] = 0;
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);
}
printf("DFS:\n");
dfs(4);
}
}
for (i = 0; i < g.N; i++)
visited[i] = 0;
int main() {
int i;
dist = new int[g.N];
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);
printf("BFS:\n");
bfs(4);
return 0;
}
Using the Lists of Neighbors
(Undirected Graph)
#include <stdio.h>
#include "linked_list.h"
#include "queue1.h"
void setNodeInfo(int i, TnodeInfo info) {
nodeInfo[i] = info;
}
template<typename TedgeInfo> struct list_elem_info {
int node;
TedgeInfo edgeInfo;
};
TnodeInfo getNodeInfo(int i) {
return nodeInfo[i];
}
template<typename TnodeInfo, typename TedgeInfo>
class Graph {
public:
int N;
LinkedList<struct list_elem_info<TedgeInfo> > *L;
TnodeInfo *nodeInfo;
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;
Using the Lists of Neighbors (cont.)
p = L[i].pfirst;
while (p != NULL) {
if (p->info.node == j)
break;
p = p->next;
}
p->info.edgeInfo = info;
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[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;
}
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;
return p->info.edgeInfo;
while (p != NULL) {
y = p->info.node;
if (!visited[y])
dfs(y);
p = p->next;
}
}
~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;
}
int *dist;
void bfs(int S) {
Queue<int> Q;
int x, y;
struct list_elem<struct list_elem_info<int> > *p;
Using the Lists of Neighbors (cont.)
Q.enqueue(S);
visited[S] = 1;
dist[S] = 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);
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);
}
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);
p = p->next;
}
}
}
return 0;
}
Implementing Directed Graphs
• What needs to be changed in the previous
two implementations in order to have
directed graphs instead of undirected
graphs ?
Download