Notes
- 数据结构:图 的操作集 C/C++代码实现
1. 图 - 邻接矩阵
using namespace std;
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
MGraph CreateGraph(int VertexNum); // 初始化图
void InsertEdge(MGraph Graph, Edge E); // 插入边
MGraph BuildGraph(); // 建图
MGraph CreateGraph(int VertexNum)
{
Vertex v, w;
MGraph Graph = new struct GNode;
Graph->Nv = VertexNum;
Graph->Ne = 0;
for(v=0; v<VertexNum; v++)
for(w=0; w<VertexNum; w++) Graph->G[v][w] = 0;
return Graph;
}
void InsertEdge(MGraph Graph, Edge E)
{
Graph->G[E->V1][E->V2] = E->Weight;
// 若为无向图,需要插入下面那行
Graph->G[E->V2][E->V1] = E->Weight;
}
MGraph BuildGraph()
{
MGraph Graph;
Edge E;
Vertex V;
int Nv;
cin >> Nv;
Graph = CreateGraph(Nv);
cin >> Graph->Ne;
if(Graph->Ne != 0)
{
E = new struct ENode;
for(int i=0; i<Graph->Ne; i++)
{
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(Graph, E);
}
}
return Graph;
}
2. 图 - 邻接表
using namespace std;
typedef int Vertex; // 顶点
typedef int WeightType; // 边的权值
typedef int DataType; // 数据
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // 有向边 <V1, V2>
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 邻接点
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
Vertex ADjV; // 邻接点下标
WeightType Weight; // 边权重
PtrToAdjVNode Next; // 指针
};
// 顶点表头结点
typedef struct VNode{
PtrToAdjVNode FirstEdge; // 边表头结点
DataType Data; // 数据
}AdjList[MaxVertexNum]; // 邻接表类型
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 邻接表-图类型
// 操作集
LGraph CreateGraph(int VertexNum); // 初始化图
void InsertEdge(LGraph Graph, Edge E); // 插入边
LGraph BuildGraph(); // 建图
// 操作集实现
LGraph CreateGraph(int VertexNum)
{
Vertex v, w;
LGraph Graph = new struct GNode;
Graph->Nv = VertexNum;
Graph->Ne = 0;
for(v=0; v<Graph->Nv; v++) Graph->G[v].FirstEdge = NULL;
return Graph;
}
void InsertEdge(LGraph Graph, Edge E)
{
PtrToAdjVNode newNode;
newNode = new struct AdjVNode;
// 插入 <V1, V2>
newNode->ADjV = E->V2;
newNode->Weight = E->Weight;
newNode->Next = Graph->G[E->V1].FirstEdge; // 旧表头接在新结点的后面
Graph->G[E->V1].FirstEdge = newNode; // 新结点成为新的表头
// 插入 <V2, V1> <---- 无向图
newNode = new struct AdjVNode;
newNode->ADjV = E->V1;
newNode->Weight = E->Weight;
newNode->Next = Graph->G[E->V2].FirstEdge; // 旧表头接在新结点的后面
Graph->G[E->V2].FirstEdge = newNode; // 新结点成为新的表头
}
LGraph BuildGraph()
{
LGraph Graph;
Edge E;
Vertex V;
int Nv;
cin >> Nv;
Graph = CreateGraph(Nv);
cin >> Graph->Ne;
if(Graph->Ne)
for(int i=0; i<Graph->Ne; i++)
{
E = new struct ENode;
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(Graph, E);
}
return Graph;
}
3. DFS - 深度优先搜索
using namespace std;
// DFS 深度优先搜索 算法
bool Visited[10] = {0};
typedef int Vertex; // 顶点
typedef int WeightType; // 边的权值
typedef int DataType; // 数据
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // 有向边 <V1, V2>
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 邻接点
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
Vertex ADjV; // 邻接点下标
WeightType Weight; // 边权重
PtrToAdjVNode Next; // 指针
};
// 顶点表头结点
typedef struct VNode{
PtrToAdjVNode FirstEdge; // 边表头结点
DataType Data; // 数据
}AdjList[MaxVertexNum]; // 邻接表类型
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 邻接表-图类型
// 操作集
void Visit(Vertex V);
void DFS(LGraph Graph, Vertex V);
void Visit(Vertex V)
{
cout << "This Vertex is: " << V << endl;
}
void DFS(LGraph Graph, Vertex V, void (*Visit)(Vertex))
{
PtrToAdjVNode W;
Visit(V);
Visited[V] = true;
for(W=Graph->G[V].FirstEdge; W; W=W->Next)
if(!Visited[W->ADjV]) DFS(Graph, W->ADjV, Visit);
}
4. BFS - 广度优先搜索
using namespace std;
// BFS 广度优先搜索 算法
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
bool Visited[10] = {0};
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
// 操作集
bool IsEdge(MGraph Graph, Vertex V, Vertex W);
void BFS(MGraph Graph, Vertex S, void (*Visit)(Vertex));
void Visit(Vertex V);
void Visit(Vertex V)
{
cout << "This Vertex is: " << V << endl;
}
bool IsEdge(MGraph Graph, Vertex V, Vertex W)
{
return (Graph->G[V][W]>0?true:false);
}
void BFS(MGraph Graph, Vertex S, void (*Visit)(Vertex))
{
queue <Vertex> Q;
Vertex V, W;
Visit(S);
Visited[S] = true;
Q.push(S);
while(!Q.empty())
{
V = Q.front();
Q.pop();
for(W=0; W<Graph->Nv; W++)
if(!Visited[W] && IsEdge(Graph, V, W))
{
Visit(W);
Visited[W] = true;
Q.push(W);
}
}
}
5. 例题 - 六度空间 ( BFS算法邻接矩阵图 )
using namespace std;
// 例题:六度空间 ---> BFS算法 - 邻接矩阵图
int ENode[1001][1001] = {0};
int Nv, Ne;
int BFS(int v)
{
queue <int> Q;
bool visited[1001] = {false};
Q.push(v);
int cnt=0, level=0, last=v, tail=v;
while(!Q.empty())
{
v = Q.front();
Q.pop();
for(int w=1; w<=Nv; w++)
if(!visited[w] && ENode[v][w]) Q.push(w), cnt++, tail = w, visited[w] = true;
else continue;
// cout << "V: " << v << ' ' << "Level:" << level << ' ' << tail << endl;
if(v == last) level++, last = tail;
if(level == 6) break;
}
return cnt;
}
int main()
{
cin >> Nv >> Ne;
for(int i=1; i<=Ne; i++)
{
int v, w;
cin >> v >> w;
ENode[v][w] = 1;
ENode[w][v] = 1;
}
for(int v=1; v<=Nv; v++)
{
float tmp = BFS(v)/(Nv*1.0)*100;
cout << v << ": ";
printf("%.2f%\n", tmp);
}
return 0;
}
6. 无权图的最短路径问题
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
// 邻接矩阵 - 无权图的单源最短路算法
#define MaxVertexNum 100 // 最大顶点数
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
vector <int> dist(MaxVertexNum, -1); // 存储路径, 并初始化为 -1
vector <int> path(MaxVertexNum); // 存储路径长度
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
void Unweighted(MGraph Graph, Vertex V);
void Unweighted(MGraph Graph, Vertex V)
{
queue<Vertex> Q;
dist[V] = 0, path[V] = -1;
Q.push(V);
while(!Q.empty())
{
V = Q.front();
Q.pop();
for(Vertex W=0; W < Graph->Nv; W++)
if(Graph->G[V][W] && dist[W] == -1)
{
dist[W] = dist[V] + 1;
path[W] = V;
Q.push(W);
}
}
}
7. 邻接矩阵 - 有权图的单源最短路算法 - Dijkstra算法
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
// 邻接矩阵 - 有权图的单源最短路算法 - Dijkstra算法
#define MaxVertexNum 100 // 最大顶点数
#define Maxdist 100000000 // 最大顶点数
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
vector <int> dist(MaxVertexNum, -1); // 存储路径, 并初始化为 -1
vector <int> path(MaxVertexNum, Maxdist); // 存储路径长度, 并初始化为 Maxdist
vector <bool> collected(MaxVertexNum, false); // 判断该Vertex是否收集, 并初始化为 false
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
void Dijkstra(MGraph Graph, Vertex V);
void Dijkstra(MGraph Graph, Vertex V)
{
dist[V] = 0, path[V] = -1;
collected[V] = true;
for(Vertex W=0; W<Graph->Nv; W++)
if(Graph->G[V][W])
{
dist[W] = dist[V] + Graph->G[V][W];
path[W] = V;
}
while(1)
{
for(Vertex W=0; W<Graph->Nv; W++)
if(V != W && !collected[W]) V = min(dist[W], Maxdist);
else V = 0;
if(!V) break;
collected[V] = true;
for(Vertex W=0; W<Graph->Nv; W++)
if(Graph->G[V][W] && !collected[W])
if(dist[V] + Graph->G[V][W] < dist[W])
{
dist[W] = dist[V] + Graph->G[V][W];
path[W] = V;
}
}
}
8. 邻接矩阵 - 有权图的多源最短路算法 - Floyd算法
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
// 邻接矩阵 - 有权图的多源最短路算法 - Floyd算法
#define MaxVertexNum 100 // 最大顶点数
#define Maxdist 100000000 // 最大顶点数
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
vector<vector<int>> dist(MaxVertexNum, vector<int>(MaxVertexNum, 0)); // 存储路径长度, 并初始化为 0
vector<vector<int>> path(MaxVertexNum, vector<int>(MaxVertexNum, -1)); // 存储路径, 并初始化为 -1
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
void Floyd(MGraph Graph, Vertex V);
void Floyd(MGraph Graph, Vertex V)
{
Vertex i, j, k;
for(i=0; i<Graph->Nv; i++)
for(j=0; j<Graph->Nv; j++)
if(i!=j) // dist[i][j] 初始化为 0, 所以 i=j对角 均跳过(为默认值0)
if(Graph->G[i][j]) dist[i][j] = Graph->G[i][j]; // 若Graph->G[i][j] 为 0, 则判定为 无边,因此初始化为Maxdist;
else dist[i][j] = Maxdist;
for(k=0; k<Graph->Nv; k++)
for(i=0; i<Graph->Nv; i++)
for(j=0; j<Graph->Nv; j++)
if(dist[i][k] + dist[k][j] < dist[i][j]) dist[i][j] = dist[i][k] + dist[k][j], path[i][j] = k;
}
9. 例题 - 哈利·波特的考试 ( BFS + Floyd 算法 )
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
// 邻接矩阵 - BFS + Floyd 算法
struct animalTra{
int Ne;
int Nv;
int Weight[102][102] = {0};
};
typedef struct animalTra AniTran;
bool BFS_LT(AniTran Graph)
{
queue <int> Q;
Q.push(1);
int v;
bool res = true;
int checked[102] = {0};
checked[1] = 1;
while(!Q.empty())
{
v = Q.front();
Q.pop();
for(int w=2; w<=Graph.Nv; w++)
if(Graph.Weight[v][w] && !checked[w])
{
Q.push(w);
checked[w] = 1;
}
}
for(int w=1; w<=Graph.Nv; w++)
if(checked[w] == 0) res = false;
return res;
}
void Floyd(AniTran Graph)
{
vector <vector <int>> dist(102, vector<int>(102, 0));
int res[102] = {0}, resMin = 102;
for(int i=1; i<=Graph.Nv; i++)
for(int j=1; j<=Graph.Nv; j++)
if(i!=j)
if(Graph.Weight[i][j]) dist[i][j] = Graph.Weight[i][j];
else dist[i][j] = 102;
for(int k=1; k<=Graph.Nv; k++)
for(int i=1; i<=Graph.Nv; i++)
for(int j=1; j<=Graph.Nv; j++)
if(dist[i][k] + dist[k][j] < dist[i][j]) dist[i][j] = dist[i][k] + dist[k][j];
for(int i=1; i<=Graph.Nv; i++)
{
for(int j=1; j<=Graph.Nv; j++)
res[i] = max(res[i], dist[i][j]);
resMin = min(resMin, res[i]);
}
for(int i=1; i<=Graph.Nv; i++)
if(resMin == res[i])
{
cout << i << ' ' << res[i];
break;
}
}
int main()
{
AniTran AniGraph;
cin >> AniGraph.Nv >> AniGraph.Ne;
for(int i=1; i<=AniGraph.Ne; i++)
{
int v, w, weight;
cin >> v >> w >> weight;
AniGraph.Weight[v][w] = weight;
AniGraph.Weight[w][v] = weight;
}
if(BFS_LT(AniGraph)) Floyd(AniGraph);
else cout << BFS_LT(AniGraph);
return 0;
}
10. 邻接矩阵 - 最小生成树 - Prim算法
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 邻接矩阵 - 最小生成树 - Prim算法
#define Maxdist 10000000
#define MaxVertexNum 100 // 最大顶点数
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
vector <int> dist(MaxVertexNum, Maxdist); // 存储距离, 并初始化为 Maxdist
vector <Vertex> parent(MaxVertexNum, -1); // 储存父节点, 并初始化为 -1
vector <Vertex> MST; // 最小生成树
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
// 操作集
void initPrim(Vertex s); // 初始化 Prim
int FindMinVertex(MGraph Graph, Vertex v); // 找出dist最小值
void Prim(MGraph Graph, Vertex s); // Prim算法
void initPrim(MGraph Graph, Vertex s)
{
MST.push_back(s), dist[s] = 0;
for(Vertex w=0; w<Graph->Nv; w++)
if(Graph->G[s][w]) dist[w] = Graph->G[s][w], parent[w] = s;
}
int FindMinVertex(MGraph Graph, Vertex v)
{
Vertex vMin = -1;
int minV = Maxdist;
for(Vertex w=0; w<Graph->Nv; w++)
if(dist[w] && dist[w] < minV) minV = dist[w], vMin = w;
return vMin;
}
void Prim(MGraph Graph, Vertex s)
{
initPrim(Graph, s);
Vertex v;
int cnt=1;
while(1)
{
v = FindMinVertex(Graph, v);
if(v==-1) break;
MST.push_back(v), dist[v] = 0, cnt++;
for(Vertex w=0; w<Graph->Nv; w++)
if(dist[w] && Graph->G[v][w])
if(Graph->G[v][w] < dist[w]) dist[w] = Graph->G[v][w], parent[w] = v;
if(cnt < Graph->Nv) cout << "Bu Lian Tong !" << endl;
}
}
11. 邻接矩阵 - 最小生成树 - Kruskal算法
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
// 邻接矩阵 - 最小生成树 - Kruskal算法
#define Maxdist 10000000
#define MaxVertexNum 100 // 最大顶点数
typedef int WeightType; // 权值
typedef int Vertex; // 顶点
typedef int DataType; // 数据
vector <int> dist(MaxVertexNum, Maxdist); // 存储距离, 并初始化为 Maxdist
vector <int> parent(MaxVertexNum, -1); // 储存父节点, 并初始化为 -1
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // < V1, V2 > 有向边
WeightType Weight; // 权重
bool operator< (const ENode &b) const // 重载运算符
{
return this->Weight>b.Weight;
}
};
typedef PtrToENode Edge;
priority_queue <Edge> MinHeap; // 最小堆 <优先队列> 需存入边集合
vector <Edge> MST; // 最小生成树
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
WeightType G[MaxVertexNum][MaxVertexNum]; // 邻接矩阵
DataType Data[MaxVertexNum]; // 数据
};
typedef PtrToGNode MGraph;
// 操作集
int Kruskal(MGraph Graph);
void Union(Vertex v, Vertex w);
bool Union_HL(MGraph Graph, Edge E); // 判断回路
bool Union_HL(MGraph Graph, Edge E)
{
Vertex v = E->V1, w = E->V2;
for(; parent[v]>=0; v=parent[v]);
for(; parent[w]>=0; w=parent[w]);
if(v==w) return true;
else
{
Union(v, w);
return false;
}
}
void Union(Vertex v, Vertex w)
{
if(parent[v]<parent[w])
parent[v]+=parent[w], parent[w]=v;
else
parent[w]+=parent[v], parent[v]=w;
}
int Kruskal(MGraph Graph)
{
WeightType weight = 0;
while(MST.size()<(Graph->Nv-1) && !MinHeap.empty())
{
Edge E = MinHeap.top();
MinHeap.pop();
if(!Union_HL(Graph, E)) weight+=E->Weight, MST.push_back(E);
}
if(MST.size()<(Graph->Nv-1)) cout << "Bu Lian Tong !!!" << endl;
return weight;
}
12. 邻接表 - 拓扑排序
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
// 邻接表 - 拓扑排序
#define MaxVertexNum 100 // 最大顶点数
typedef int Vertex; // 顶点
typedef int WeightType; // 边的权值
typedef int DataType; // 数据
vector <Vertex> TopOrder(MaxVertexNum); // 拓扑排序后的下标顺序
// 边
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; // 有向边 <V1, V2>
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// 邻接点
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
Vertex ADjV; // 邻接点下标
WeightType Weight; // 边权重
PtrToAdjVNode Next; // 指针
};
// 顶点表头结点
typedef struct VNode{
PtrToAdjVNode FirstEdge; // 边表头结点
DataType Data; // 数据
}AdjList[MaxVertexNum]; // 邻接表类型
// 图
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; // 顶点数
int Ne; // 边数
AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 邻接表-图类型
// 操作集
bool TopSort(LGraph Graph, Vertex *TopOrder); // 拓扑排序
bool TopSort(LGraph Graph, Vertex *TopOrder)
{
queue <Vertex> zeroDegree; // 0 度 队列
int Indegree[MaxVertexNum], cnt = 0;
for(Vertex V=0; V<Graph->Nv; V++) Indegree[V] = 0;
for(Vertex V=0; V<Graph->Nv; V++)
for(PtrToAdjVNode W=Graph->G[V].FirstEdge; W; W=W->Next)
Indegree[W->ADjV]++;
for(Vertex V=0; V<Graph->Ne; V++)
if(!Indegree[V]) zeroDegree.push(V);
while(!zeroDegree.empty())
{
Vertex V = zeroDegree.front();
TopOrder[cnt++] = V;
zeroDegree.pop();
for(PtrToAdjVNode W=Graph->G[V].FirstEdge; W; W->Next)
if(--Indegree[W->ADjV] == 0) zeroDegree.push(W->ADjV);
}
if(cnt < Graph->Nv) return false; // 存在回路
else return true; // 排序成功
}