Chap 8 Graph
Chap 8 Graph
Algorithms
Bin Chen
2023 Fall
Outline——Graph
A graph is an abstract data type for storing adjacency relations
• We start with definitions:
• Vertices, edges, degree and sub-graphs
• We will describe paths in graphs
• Simple paths and cycles
• Definition of connectedness
• Weighted graphs
• We will then reinterpret these in terms of directed graphs
• Directed acyclic graphs
Outline
We will define an Undirected Graph ADT as a collection of vertices
V = {v1, v2, ..., vn}
• The number of vertices is denoted by
|V| = n
• Associated with this is a collection E of unordered pairs {vi, vj} termed edges
which connect the vertices
V V 1
V
E
2
2
O V
2
An undirected graph
Example: given the |V| = 7 vertices
V = {A, B, C, D, E, F, G}
and the |E| = 9 edges
E = {{A, B}, {A, D}, {A, E}, {B, C}, {B, D}, {B, E}, {C, E}, {C, F}, {D, E}}
Degree
The degree of a vertex is defined as the number of adjacent vertices
degree(A) = degree(D) = degree(C) = 3
degree(B) = degree(E) = 4
degree(F) = 1
degree(G) = 0
Consequences:
• The number of edges is |E| = |V| – 1
• The graph is acyclic, that is, it does not contain any cycles
• Adding one more edge must create a cycle
• Removing any one edge creates two disjoint non-empty sub-graphs
Trees
Any tree can be converted into a rooted tree by:
• Choosing any vertex to be the root
• Defining its neighboring vertices as its children
and then recursively defining:
• All neighboring vertices other than that one designated its parent are now
defined to be that vertices children
Given this tree, here are three rooted trees associated with it
Forests
A forest is any graph that has no cycles
Consequences:
• The number of edges is |E| < |V|
• The number of trees is |V| – |E|
• Removing any one edge adds one more tree to the forest
In this graph:
in_degree(v1) = 0 out_degree(v1) = 2
in_degree(v5) = 2 out_degree(v5) = 3
Sources and sinks
Some definitions:
• Vertices with an in-degree of zero are described as sources
• Vertices with an out-degree of zero are described as sinks
In this graph:
• Sources: v1 , v6 , v7
• Sinks: v2, v9
Paths
A path in a directed graph is an ordered sequence of vertices
(v0, v1, v2, ..., vk)
where (vj – 1, vj) is an edge for j = 1, ..., k
In this graph:
• The sub-graph {v3, v4, v5, v8} is strongly
connected
• The sub-graph {v1, v2, v3, v4, v5, v8} is
weakly connected
Weighted directed graphs
In a weighted directed graphs, each edge is associated with a
value
Unlike weighted undirected graphs, if both (vj, vk) and (vj, vk) are
edges, it is not required that they have the same weight
6.4
1 2 3 4 5 6 7 8 9
1 T T
2
3 T
4 T T
5 T T T
6 T
7 T
8 T
9
• Modifications include:
• Inserting or removing an edge
• Inserting or removing a vertex (and all edges containing that vertex)
n n(n 1) 2
O(n )
edges 2 2
C++ does not have native support for anything more than one-dimensional arrays, thus how do
we store a two-dimensional array?
• as an array of arrays
Adjacency Matrix
Suppose we require a 16 × 16 matrix of double-precision floating-point numbers
First, we must allocate the memory for the array of pointers to doubles:
matrix = new double * [16];
Adjacency Matrix
Next, to each entry of this matrix, we must assign the memory allocated for an array of doubles
Try it:
int i = (3, 4);
cout << i << endl;
C++ Notation Warning
Many things will compile if you try to use this notation:
matrix = new double[N, N];
will allocate an array of N doubles, just like:
matrix = new double[N];
The last is the most logical, in that it makes sense that two vertices which are not connected have
an infinite distance between them
Default Values
To use infinity, you may declare a constant static member variable INF:
#include <limits>
class Weighted_graph {
private:
static const double INF;
// ...
// ...
};
matrix[i][i] = 0;
}
matrix[i][i] = true;
}
Then, assign to the 16 pointers in the first array the addresses of entries
0, 16, 32, 48, 64, ..., 240
Adjacency Matrix Improvement
First, we allocate memory:
matrix = new double * [16];
double * tmp = new double[256];
Adjacency Matrix Improvement
Next, we allocate the addresses:
matrix = new double * [16];
double * tmp = new double[256];
class Pair {
private:
double edge_weight;
int adacent_vertex;
public:
Pair( int, double );
double weight() const;
int vertex() const;
};
We each case, we will have to track which vertices have been visited requiring Q(|V|)
memory
• One option is a hash table
• If we can use a bit array, this requires only |V|/8 bytes
The time complexity cannot be better than and should not be worse than Q(|V| + |E|)
• Connected graphs simplify this to Q(|E|)
• Worst case: Q(|V|2)
Breadth-first traversal
Consider implementing a breadth-first traversal on a graph:
• Choose any vertex, mark it as visited and push it onto queue
• While the queue is not empty:
• Pop to top vertex v from the queue
• For each vertex adjacent to v that has not been visited:
• Mark it visited, and
• Push it onto the queue
while ( !queue.empty() ) {
Vertex *v = queue.front();
queue.pop();
// Perform an operation on v
Two implementations:
• Recursive
• Iterative
Recursive depth-first traversal
A recursive implementation uses the call stack for memory:
void Graph::depth_first_traversal( Vertex *first ) const {
std::unordered_map<Vertex *, int> hash;
hash.insert( first );
first->depth_first_traversal( hash );
}
while ( !stack.empty() ) {
Vertex *v = stack.top();
stack.pop();
// Perform an operation on v
T={};
TV={0};
while (T contains fewer than n-1 edges)
{
let (u,v) be a least cost edge such
u TV v TV
that and
if (there is no such edge ) break;
add v to TV;
add (u,v) to T;
}
if (T contains fewer than n-1 edges)
printf(“No spanning tree\n”);
Shortest Paths
• Given a directed graph G=(V,E), a weighted function, w(e).
• How to find the shortest path from u to v?
Example:
3 1000 800 0
4 1200 0
5 1500 0 250
6 1000 0 900 1400
7 0 1000
8 1700 0
Vertex
Iteration S Selected (1) (2) (3) (4) (5) (6) (7) (8)
Initial ----
1 5 6 + + + 1500 0 250 + +
2 5,6 7 + + + 1250 0 250 1150 1650
3 5,6,7 4 + + + 1250 0 250 1150 1650
4 5,6,7,4 8 + + 2450 1250 0 250 1150 1650
5 5,6,7,4,8 3 3350 + 2450 1250 0 250 1150 1650
6 5,6,7,4,8,3 2 3350 3250 2450 1250 0 250 1150 1650
5,6,7,4,8,3,2 3350 3250 2450 1250 0 250 1150 1650
int[][] graph = new int[][]{
{0 , 2, ∞, 6}
Dijkstra Algorithm {2 , 0, 3, 2}
{∞ , 3, 0, 2}
{6 , 2, 2, 0}};
v0 v1 A0 0 1 2
4 0 0 4 11
11 1 6 0 2
3 2
v2 2 3 7 0
Example cont.
6
A1 0 1 2
v0 v1
0 0 4 6
4
11 1 6 0 2
3 2
2 3 7 0
v2
6
A2 0 1 2
v0 v1
0 0 4 6
4
11 1 5 0 2
3 2
2 3 7 0
v2
void floyd(int[][] graph) {
distance = graph; // 初始化距离矩阵 distance
// 初始化路径
path = new int[graph.length][graph.length];
for (int i = 0; i < graph.length; i++) {
for (int j = 0; j < graph[i].length; j++) {
path[i][j] = j;
}
}
for (int i = 0; i < graph.length; i++) {// 开始 Floyd 算法 // 每个点为中转 // 所有入度
for (int j = 0; j < graph.length; j++) { // 所有出度
for (int k = 0; k < graph[j].length; k++) {
// 以每个点为「中转」,刷新所有出度和入度之间的距离 例如 AB + BC < AC 就刷新距离
if (graph[j][i] != -1 && graph[i][k] != -1) {
int newDistance = graph[j][i] + graph[i][k];
if (newDistance < graph[j][k] || graph[j][k] == -1) {
// 刷新距离
graph[j][k] = newDistance;
// 刷新路径
path[j][k] = i;
}
}
}
}
}
}
https://www.cnblogs.com/skywang12345/p/
3711526.html