数据结构之图

1.图的邻接矩阵表示

#include <iostream>
#include<queue>
using namespace std;

/*
图的邻接矩阵表示法
*/

const int MaxVertexNum = 100; //顶点数最大为100
const int INFINITY = 65535; //两点之间的权重值设为65535时,两点之间无边
typedef int Vertex; //用顶点的下表表示顶点,为整型
typedef int WeightType; //边的权值设为整型
typedef char DataType; //顶点存储的数据类型设为字符型

//边的定义
typedef struct ENode* PtrToENode;
struct ENode
{
Vertex 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 Visited[MaxVertexNum] = { false }; //顶点是否遍历过的标志,遍历过为true,没有遍历过为false

//初始化图,只有顶点没有边
MGraph CreatGraph(int VertexNum)
{
Vertex V, M;
MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;

for (V = 0; V < VertexNum; V++)
{
for (M = 0; M < VertexNum; M++)
{
Graph->G[V][M] = INFINITY;
}
}
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;
int Nv, i;

cin >> Nv;
Graph = CreatGraph(Nv);
cin >> Graph->Ne;
if (Graph->Ne)
{
E = (Edge)malloc(sizeof(struct ENode));
for (i = 0; i < Graph->Ne; i++)
{
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(Graph, E);
}
free(E);
}
return Graph;
}

//判断两个顶点之间是否有边
bool IsEdge(MGraph Graph, Vertex V1, Vertex V2)
{
return Graph->G[V1][V2] != INFINITY;
}

//将所有顶点初始化为都没有遍历过
void IniVisited()
{
for (int i = 0; i < MaxVertexNum; i++)
{
Visited[i] = false;
}
}

//输出顶点
void Visit(Vertex V)
{
cout << V << ” “;
}

//图连通时的DFS和BFS
//BFS(Breadth First Search)广度优先 初始顶点S
void BFS(MGraph Graph, Vertex S, void(*Visit)(Vertex))
{
queue<Vertex> Q;
Vertex V, W;
Q.push(S);
Visited[S] = true;

while (!Q.empty())
{
V = Q.front();
Visit(V);
Q.pop();
for (W = 0; W < Graph->Nv; W++)
{
if (!Visited[W] && IsEdge(Graph, V, W))
{
Q.push(W);
Visited[W] = true;
}
}
}
}

//DFS(Depth First Search) 深度优先
void DFS(MGraph Graph, Vertex S, void(*Visit)(Vertex))
{
Visit(S);
Visited[S] = true;
for (Vertex W = 0; W < Graph->Nv; W++)
{
if (!Visited[W] && IsEdge(Graph, S, W))
{
DFS(Graph, W, Visit);
}
}
return;
}

//图不连通时的DFS和BFS
void BFSListComponents(MGraph Graph, void(*Visit)(Vertex))
{
for (Vertex V = 0; V < Graph->Nv; V++)
{
if (!Visited[V])
{
BFS(Graph, V, Visit);
cout << endl;
}
}
}
void DFSListComponents(MGraph Graph, void(*Visit)(Vertex))
{
for (Vertex V = 0; V < Graph->Nv; V++)
{
if (!Visited[V])
{
DFS(Graph, V, Visit);
cout << endl;
}
}
}
int main()
{
MGraph Graph = BuildGraph();
IniVisited();
BFSListComponents(Graph, Visit);
IniVisited();
DFSListComponents(Graph, Visit);
free(Graph); //释放动态数组开辟的内存
system(“pause”);
return 0;
}

2.图的邻接表表示

#include <iostream>
#include <queue>
using namespace std;

typedef int Vertex;
typedef int WeightType;
typedef char DataType;
const int INFINITY = 65535;
const int MaxVertexNum = 100;
bool Visited[MaxVertexNum] = {false};

//定义边
typedef struct ENode* PtrToENode;
struct ENode
{
Vertex V1, V2;
WeightType Weight;
};
typedef PtrToENode Edge;

//定义邻接顶点结点
typedef struct AdjVNode* PtrToAdjVNode;
struct AdjVNode
{
Vertex AdjV; //邻接点下标
WeightType Weight;
PtrToAdjVNode Next;
};

//定义邻接表表头的结点
typedef struct VNode
{
PtrToAdjVNode FisrtEdge;
DataType data;
}AdjList[MaxVertexNum];

//图的定义
typedef struct GNode* PtrToGNode;
struct GNode
{
int Nv; //顶点数量
int Ne; //边的数量
AdjList G; //邻接表
};
typedef PtrToGNode LGraph;

//初始化图,只有顶点没有边
LGraph CreateLGraph(int VertexNum)
{
LGraph Graph = (LGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
for (Vertex V = 0; V < Graph->Nv; V++)
{
Graph->G[V].FisrtEdge = NULL;
}
return Graph;
}

//在图中插入一条边,无向图
void InsertEdge(LGraph Graph, Edge E)
{
PtrToAdjVNode NewNode;

//<V1, V2>
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V2;
NewNode->Weight = E->Weight;
NewNode->Next = Graph->G[E->V1].FisrtEdge;
Graph->G[E->V1].FisrtEdge = NewNode;

//<V2, V1>
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V1;
NewNode->Weight = E->Weight;
NewNode->Next = Graph->G[E->V2].FisrtEdge;
Graph->G[E->V2].FisrtEdge = NewNode;
}

//输入数据并建立图
LGraph BuildLGraph()
{
int Nv;
LGraph Graph;
Edge E = (Edge)malloc(sizeof(struct ENode));

cin >> Nv;
Graph = CreateLGraph(Nv);
cin >> Graph->Ne;
for (int i = 0; i < Graph->Ne; i++)
{
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(Graph, E);
}
return Graph;
}

//图的遍历,广度优先和深度优先
void IniVisited()
{
for (int i = 0; i < MaxVertexNum; i++)
{
Visited[i] = false;
}
}
void Visit(Vertex V)
{
cout << V << ” “;
}
//图整个连通时的BFS和DFS
void BFS(LGraph Graph, Vertex S, void(*Visit)(Vertex))
{
queue<Vertex> Q;
Vertex V;

Q.push(S);
Visited[S] = true;
while (!Q.empty())
{
V = Q.front();
Visit(V);
Q.pop();
PtrToAdjVNode P = Graph->G[V].FisrtEdge;
while(P)
{
if (!Visited[P->AdjV])
{
Q.push(P->AdjV);
Visited[P->AdjV] = true;
}
P = P->Next;
}
}
}
//递归
void DFS(LGraph Graph, Vertex S, void(*Visit)(Vertex))
{
Visit(S);
Visited[S] = true;
PtrToAdjVNode P = Graph->G[S].FisrtEdge;
while (P)
{
if (!Visited[P->AdjV])
{
DFS(Graph, P->AdjV, Visit);
}
P = P->Next;
}
}

//图不连通时的遍历
void BFSListComponent(LGraph Graph, void(*Visit)(Vertex))
{
for (Vertex V = 0; V < Graph->Nv; V++)
{
if (!Visited[V])
{
BFS(Graph, V, Visit);
cout << endl;
}
}
}
void DFSListComponent(LGraph Graph, void(*Visit)(Vertex))
{
for (Vertex V = 0; V < Graph->Nv; V++)
{
if (!Visited[V])
{
DFS(Graph, V, Visit);
cout << endl;
}
}
}
//释放动态分配的内存空间
void DestoryGraph(LGraph Graph)
{
PtrToAdjVNode P;
PtrToAdjVNode Temp;
for (Vertex V = 0; V < Graph->Nv; V++)
{
P = Graph->G[V].FisrtEdge;
while (P)
{
Temp = P->Next;
free(P);
P = Temp;
}
}
}

int main()
{
LGraph Graph = BuildLGraph();
IniVisited();
BFSListComponent(Graph, Visit);
IniVisited();
DFSListComponent(Graph, Visit);
DestoryGraph(Graph);
free(Graph);
system(“pause”);
return 0;
}

3. 无权图的单元最短路径算法

#include <iostream>
#include <queue>
#include <stack>
using namespace std;
/*
无权图的单元最短路径算法, 图是采用邻接表存储的,算法的时间复杂度为O(V + E)(结点+边)
*/
typedef int Vertex;
const int MaxVertexNum = 100;
int dist[MaxVertexNum + 1];
Vertex path[MaxVertexNum + 1];

typedef struct AdjVNode* ptrToAdjVNode;
struct AdjVNode
{
Vertex V;
ptrToAdjVNode Next;
};

typedef struct VNode
{
ptrToAdjVNode FistAdjVNode;
}AdjList[MaxVertexNum + 1];

typedef struct GNode* ptrToGNode;
struct GNode
{
int Nv;
int Ne;
AdjList G;
};
typedef ptrToGNode LGraph;

//初始化图,只有结点,没有边
LGraph CreatLGraph(int Nv)
{
LGraph Graph = (LGraph)malloc(sizeof(struct GNode));
Graph->Nv = Nv;
Graph->Ne = 0;
for (int i = 0; i < MaxVertexNum; i++)
{
Graph->G[i].FistAdjVNode = NULL;
}
return Graph;
}
void InsertNode(LGraph Graph, Vertex L, Vertex R)
{
ptrToAdjVNode Temp = (ptrToAdjVNode)malloc(sizeof(struct AdjVNode));
Temp->V = R;
Temp->Next = Graph->G[L].FistAdjVNode;
Graph->G[L].FistAdjVNode = Temp;
}
LGraph BuildGraph()
{
int N; //图的结点的数量
Vertex L, R;
cin >> N;
LGraph Graph = CreatLGraph(N);
cin >> Graph->Ne;
for (int i = 0; i < Graph->Ne; i++)
{
cin >> L >> R; //L和R是图中边的两端的顶点
InsertNode(Graph, L, R);
}
return Graph;
}
void FreeGraph(LGraph &Graph)
{
for (int i = 1; i <= Graph->Nv; i++)
{
ptrToAdjVNode Temp = Graph->G[i].FistAdjVNode;
ptrToAdjVNode pNext;
while (Temp)
{
pNext = Temp->Next;
free(Temp);
Temp = pNext;
}
}
free(Graph);
Graph = NULL;
}
void InitDistAndPath()
{
for (int i = 0; i <= MaxVertexNum; i++)
{
dist[i] = -1;
path[i] = -1;
}
}
void Unweight(LGraph Graph, int dist[], int path[], Vertex S)
{
queue<Vertex> Q;
Vertex V;
Vertex W;
ptrToAdjVNode Temp;
dist[S] = 0;
Q.push(S);
while (!Q.empty())
{
V = Q.front();
Q.pop();
Temp = Graph->G[V].FistAdjVNode;
while (Temp)
{
W = Temp->V;
if(dist[W] == -1)
{
dist[W] = dist[V] + 1;
path[W] = V;
Q.push(W);
}
Temp = Temp->Next;
}
}
}
void MinPath(Vertex V)
{
cout << “3到” << V << “的最短路径长度为:” << dist[V] << endl;
stack<Vertex> s;
Vertex W;
s.push(V);
W = path[V];
while (W != 3)
{
s.push(W);
W = path[W];
}
cout << “最短路径为: ” << 3 << “->”;
while (!s.empty())
{
W = s.top();
s.pop();
if (W == V)
{
cout << W;
}
else
{
cout << W << “->”;
}
}
cout << endl;
}
int main()
{
LGraph Graph = BuildGraph();
InitDistAndPath();
Unweight(Graph, dist, path, 3);
MinPath(7);
free(Graph);
system(“pause”);
return 0;
}

4.有权图的单元最短路径算法

#include <iostream>
#include <stack>
using namespace std;
/*
有权图的最短路径算法
时间复杂度:若直接扫描所有未收录顶点 T= O(V^2 + E) 若将dist存在最小堆中 T = O(ElogV)
用矩阵存储图
DijKstra算法计算有权图的最短路径
*/
typedef int Vertex;
typedef int WeightType;
const int MaxVertexNum = 100;
const int INFINITY = 65535;

//定义边
typedef struct ENode* ptrToENode;
struct ENode
{
Vertex V1, V2;
WeightType weight;
};
typedef ptrToENode Edge;

//定义图结点
typedef struct GNode* ptrToGNode;
struct GNode
{
int Nv;
int Ne;
WeightType G[MaxVertexNum][MaxVertexNum];
};
typedef ptrToGNode MGraph;

/* 邻接矩阵存储 –有权图的单源最短路径算法*/
Vertex FindMinDist(MGraph Graph, int dist[], int collected[])
{
/*将所有顶点遍历,返回未被收录顶点中dist最小者*/
Vertex MinV;
int Mindist = INFINITY;
for (Vertex V = 0; V < Graph->Nv; V++)
{
if (!collected[V] && dist[V] < Mindist)
{
Mindist = dist[V];
MinV = V;
}
}
if (Mindist == INFINITY)
{
return -1;
}
else
{
return MinV;
}
}

bool DijKstra(MGraph Graph, int dist[], int path[], Vertex S)
{
Vertex V;
int collected[MaxVertexNum];
for (Vertex W = 0; W < Graph->Nv; W++)
{
dist[W] = Graph->G[S][W]; //初始化所有的dist
if (dist[W] < INFINITY) //初始化所有的path
{
path[W] = S;
}
else
{
path[W] = -1;
}
collected[W] = false; //初始化collected
}
while (1)
{
V = FindMinDist(Graph, dist, collected); //未收录的顶点中的dist的最小的
if (V == -1)
{
break;
}
collected[V] = true;
for (Vertex W = 0; W < Graph->Nv; W ++)
{
if (Graph->G[V][W] < INFINITY && collected[W] == false)
{
if (Graph->G[V][W] < 0)
{
return false;
}
if (dist[V] + Graph->G[V][W] < dist[W])
{
dist[W] = dist[V] + Graph->G[V][W];
path[W] = V;
}
}
}
}
return true;
}
void ShowPath(MGraph Graph, int path[], Vertex S, Vertex V) //从S到V的最短路径
{
if (S == V)
{
return;
}
stack<Vertex> s;
Vertex tempV = V;
s.push(tempV);
while (path[tempV] != S)
{
tempV = path[tempV];
s.push(tempV);
}
s.push(S);
while (!s.empty())
{
tempV = s.top();
s.pop();
cout << tempV << ” “;
}
}
int main()
{
//输入图
int Nv;
int dist[MaxVertexNum];
Vertex path[MaxVertexNum];
Vertex V1, V2;
WeightType Weight;
MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
cin >> Nv;
Graph->Nv = Nv;
cin >> Graph->Ne;
for (Vertex V = 0; V < Graph->Nv; V++)
{
for (Vertex W = 0; W < Graph->Nv; W++)
{
Graph->G[V][W] = INFINITY;
}
}
for (int i = 0; i < Graph->Ne; i++)
{
cin >> V1 >> V2 >> Weight;
Graph->G[V1][V2] = Weight;
}
if (DijKstra(Graph, dist, path, 0))
{
for (Vertex V = 0; V < Graph->Nv; V++)
{
ShowPath(Graph, path, 0, V);
if (V == 0)
{
continue;
}
cout << dist[V] << endl;
}

}
else
{
cout << “最短路径寻找失败!!!” << endl;
}

system(“pause”);
return 0;
}

5. 多源最短路径算法

#include <iostream>
#include <stack>
using namespace std;
/*
无向有权图的最短路径算法
时间复杂度:若直接扫描所有未收录顶点 T= O(V^2 + E) 若将dist存在最小堆中 T = O(ElogV)
用矩阵存储图
DijKstra算法计算有权图的最短路径
*/
typedef int Vertex;
typedef int WeightType;
const int MaxVertexNum = 100;
const int INFINITY = 65535;

//定义边
typedef struct ENode* ptrToENode;
struct ENode
{
Vertex V1, V2;
WeightType weight;
};
typedef ptrToENode Edge;

//定义图结点
typedef struct GNode* ptrToGNode;
struct GNode
{
int Nv;
int Ne;
WeightType G[MaxVertexNum][MaxVertexNum];
};
typedef ptrToGNode MGraph;

bool Floyd( MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum] )
{
/*
D[MaxVertexNum][MaxVertexNum]存储的是从i到j的距离
path[MaxVertexNum][MaxVertexNum]存储的是i到j之间经过的顶点k
*/

Vertex i, j, k;
/* 初始化 */
for ( i=0; i<Graph->Nv; i++ )
for( j=0; j<Graph->Nv; j++ )
{
D[i][j] = Graph->G[i][j];
path[i][j] = -1;
}

for( k=0; k<Graph->Nv; k++ )
for( i=0; i<Graph->Nv; i++ )
for( j=0; j<Graph->Nv; j++ )
if( D[i][k] + D[k][j] < D[i][j] )
{
D[i][j] = D[i][k] + D[k][j];
if ( i == j && D[i][j] < 0 ) /* 若发现负值圈 */
return false; /* 不能正确解决,返回错误标记 */
path[i][j] = k;
}

return true; /* 算法执行完毕,返回正确标记 */
}

int main()
{
//输入图
int Nv;
int D[MaxVertexNum][MaxVertexNum];
Vertex path[MaxVertexNum][MaxVertexNum];
Vertex V1, V2;
WeightType Weight;
MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
cin >> Nv;
Graph->Nv = Nv;
cin >> Graph->Ne;
for (Vertex V = 0; V < Graph->Nv; V++)
{
for (Vertex W = 0; W < Graph->Nv; W++)
{
if (V == W)
{
Graph->G[V][W] = 0;
}
else
{
Graph->G[V][W] = INFINITY;
}
}
}
for (int i = 0; i < Graph->Ne; i++)
{
cin >> V1 >> V2 >> Weight;
Graph->G[V1][V2] = Weight;
Graph->G[V2][V1] = Weight;
}
Floyd(Graph, D, path);
system(“pause”);
return 0;
}

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/mengjuanjuan/p/9979743.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞