题目
实验目的:
- 掌握创建并使用图的两种存储方式:邻接矩阵、邻接表,掌握在这两种存储结构上图的基本操作(求点的入度、出度、找到某个点的邻接点等)。
- 掌握图的DFS与BFS代码实现。
- 掌握拓扑排序的代码实现。(课后)
- 掌握最短路径的代码实现。(课后)
参考代码(图的邻接矩阵存储结构):
#define MAXVEXNUM 100
//点,边
typedef int ArcCell;
typedef char VexType;
typedef struct {
VexType vexs[MAXVEXNUM];//点的集合
ArcCell arcs[MAXVEXNUM][MAXVEXNUM];//边的集合
int vexNum, arcNum;
}MyGraph;
实验内容:
(1)通过控制台创建如下图的邻接矩阵。(课上完成)
给出以下信息:a) 图的顶点数目vexNum,边的数目arcNum; (b) 各顶点的信息(节点类型为char或者string);c) 各条边的信息。
通过控制台键盘输入建立如下无向图和有向图,并使用下图进行测试:
无向图的创建函数:
void CreateUDGraphFromConsole(MyGraph &G, int vexNum, int arcNum)
有向图的创建函数:
void CreateDGraphFromConsole(MyGraph &G, int vexNum, int arcNum)
问题1:假如给每一条边加上一个权重w,满足w在(0,1)区间,如何修改该创建函数?
问题2:用控制台进行图结构信息的输入很麻烦,请尝试使用从文本文件中读取一个图结构(以上图为例),并进行图的初始化。
(2)图(邻接矩阵)的基本操作(课上完成)
a)void printMGraph(MyGraph &G)//打印图的邻接矩阵
b)int locateVex(MyGraph &G, VexType key)//若图中存在值为key的顶点,返回该顶点为位置,否则返回-1
c)int getInDegree(MyGraph &G, int vexPos) //打印顶点vex的入度,vexPos为vex点的位置
d)int getOutDegree(Mgraph& G, int vexPos) //打印顶点vex的出度,vexPos为vex点的位置
e)printAdjVex(MyGraph &G,int vexPos)//打印或返回vex的所有邻接点
f)destoryMGraph(MyGraph &G)//销毁图。可选:使用new或者malloc申请内存才需要销毁。直接使用数组则没必要手动销毁
(3)连通图的遍历(二选一,课上完成)
1. void DFSTravse(MyGraph &G) //深度优先搜索
问题1:你编写的算法适用于连通图还是非连通图?为什么?
问题2:如何改造适用于非连通图。
2. void BFSTravse(MyGraph &G, int i) //从位置为i的节点出发进行广度优先搜索。
说明:以上图为例进行测试。注意:只需考虑连通图即可。
问题:请说明其实现原理,给出伪代码或者给出实现思路
(4)判定图中两个顶点之间有无通路
1. bool printPathBetweenVex(MyGraph &G, int startV, int endV)-课上完成
基本要求:判断两个顶点之间有无路径,有路径返回true,无路径返回false
2. 选做-特别加分:在基本要求的基础上输出两个顶点之间的路径。思考:如何打印出路径长度?
3. 选做-特别加分-进阶:如何找到两个点之间所有的路径?路径应该存储到哪里?(要讲出实现原理,路径存储在哪里)
(5)对下图求出其最小生成树的权值(必做)。输出生成树上的所有边(必做)。-课后完成
(6)PTA编程题
-
- 图着色问题(主要是对无向图的邻接点进行操作)(必做)
- PTA编程题:六度空间(BFS应用)(必做)。
- 最短路径问题:PTA函数题:旅游规划(必做)
- 最小生成树问题
- PTA编程题:公路村村通。(必做)
- PTA编程题:通信网设计(非连通图)(选做)。
- PTA编程题:天梯地图(选做)
(7)附加:图的绘制,使用Graphviz进行图的绘制
提交要求:
- 对于要求课上完成的题目,请在实验课结束前提交代码至课堂派,并在课后完成实验报告,报告中要求给出伪代码或者实现思路(流程图或者自然语言描述),并且回答相关问题;
- 对于不要求课上完成的题目,请在实验课结束后提交代码至课堂派;
- PTA上的题目,还需要提交测试通过;
- 在实验报告中对每一道题都需要描述算法思路(可以用伪代码也可以用文字,还可以用ppt演示算法流程),实验报告为一个word、ppt或pdf文档,每个同学提交时将所有代码和实验报告统一放在文件夹中,文件夹命名为“学号后四位_姓名”,然后提交压缩文件,如有不同版本,请用“学号后四位_姓名_版本号”标识。
实验报告
实验步骤:
- 建图
- 图(邻接矩阵)的基本操作&&思考问题
- 连通图的遍历&&思考问题
- 判定途中两个顶点之间有无通路
1. 建图
1.1 建立无向图
流程:
对于vexNum个点:输入vexNum个点到G中的vexs中
对于arcNum条边:输入一对节点ab,每次令G中的arcs数组a行b列为1,b行a列为1
结果展示:
void CreateUDGraphFromConsole(MyGraph& G, int vexNum, int arcNum)
{
printf("\n*******************************创建无向图*******************************\n");
printf("请输入无向图的点:");
for (int i = 0; i < G.vexNum; i++)
cin >> G.vexs[i];
printf("请输入无向图的边:");
for (int i = 0; i < G.arcNum; i++)
{
int a, b;
cin >> a >> b;
G.arcs[a][b] = G.arcs[b][a] = 1;
}
printf("*******************************展示无向图*******************************\n");
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
cout << G.arcs[i][j] << " ";
cout << endl;
}
printf("**************************************************************************\n\n\n");
}
1.2 建立有向图
流程:
对于vexNum个点:输入vexNum个点到G中的vexs中
对于arcNum条边:输入一对节点ab,每次令G中的arcs数组a行b列为1
结果展示:
void CreateDGraphFromConsole(MyGraph& G, int vexNum, int arcNum)
{
printf("\n*******************************创建有向图*******************************\n");
printf("请输入有向图的点:");
for (int i = 0; i < G.vexNum; i++)
cin >> G.vexs[i];
printf("请输入有向图的边:");
for (int i = 0; i < G.arcNum; i++)
{
int a, b;
cin >> a >> b;
G.arcs[a][b] = 1;
}
printf("*******************************展示有向图*******************************\n");
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
cout << G.arcs[i][j] << " ";
}
cout << endl;
}
printf("*************************************************************************\n");
}
问题1:假如给每一条边加上一个权重w,满足w在(0,1)区间,如何修改该创建函数?
思路:在输入图的边时,将G.arcs[a][b] = 1;改成G.arcs[a][b] = w;
for (int i = 0; i < G.arcNum; i++)
{
int a, b;
cin >> a >> b;
//问:假如给每一条边加上一个权重w,满足w在(0,1)区间,如何修改该创建函数?
//答:将下面语句改成G.arcs[a][b] = w;
G.arcs[a][b] = 1;
}
问题2:用控制台进行图结构信息的输入很麻烦,请尝试使用从文本文件中读取一个图结构(以上图为例),并进行图的初始化。
思路:
通过路径读取文件。
若无法打开文件,则:
输出“can not open the file”,结束。
否则:
从文件中读取点的个数G.vexNum,随后读取G.vexNum个点到地图的vexs中。
读取G.vexNum * G.vexNum个点到地图的arcs中。
void GetGraph(MyGraph& G)
{
ifstream myfile("C:\\Users\\Administrator\\Desktop\\G.txt");
if (!myfile.is_open())
{
cout << "can not open the file" << endl;
return;
}
//读取点
myfile >> G.vexNum;
printf("\n图的节点:");
for (int i = 0; i < G.vexNum; i++)
{
myfile >> G.vexs[i];
cout << G.vexs[i];
}
cout << endl;
//读取边
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
myfile >> G.arcs[i][j];
}
}
//关闭
myfile.close();
}
读取文件:
读取结果:
2. 图(邻接矩阵)的基本操作
(1)void printMGraph(MyGraph &G)//打印图的邻接矩阵
(2)int locateVex(MyGraph &G, VexType key)//若图中存在值为key的顶点,返回该顶点为位置,否则返回-1
(3)int getInDegree(MyGraph &G, int vexPos) //打印顶点vex的入度,vexPos为vex点的位置
(4)int getOutDegree(Mgraph& G, int vexPos) //打印顶点vex的出度,vexPos为vex点的位置
(5)printAdjVex(MyGraph &G,int vexPos)//打印或返回vex的所有邻接点
(6)destoryMGraph(MyGraph &G)//销毁图。可选:使用new或者malloc申请内存才需要销毁。直接使用数组则没必要手动销毁
2.1 void printMGraph(MyGraph &G)
流程:
获取图的结点数G.vexNum
对于G.vexNum行,G.vexNum列,打印图的arcs二维数组
void printMGraph(MyGraph& G)
{
printf("*******************************展示图的邻接矩阵************************\n");
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
cout << G.arcs[i][j] << " ";
}
cout << endl;
}
printf("*************************************************************************\n");
}
2.2 int locateVex(MyGraph &G, VexType key)
流程:
遍历图中的节点(即G.vexs),若发现key,则返回该位置。
遍历完都没发现key,则返回-1.
int locateVex(MyGraph& G, VexType key)
{
//若图中存在值为key的顶点,返回该顶点为位置,否则返回-1
for (int i = 0; i < G.vexNum; i++)
{
if (G.vexs[i] == key)
return i;
}
return -1;
}
2.3 int getInDegree(MyGraph &G, int vexPos)
流程:
初始化入度=0。
遍历图的二维矩阵arcs的第vexPos列,数值为1,则入度加1。
返回入度。
int getInDegree(MyGraph& G, int vexPos)
{
//打印顶点vex的入度,vexPos为vex点的位置
int in = 0;
for (int i = 0; i < G.vexNum; i++)
{
in += G.arcs[i][vexPos];
}
return in;
}
2.4 int getOutDegree(Mgraph& G, int vexPos)
流程:
初始化出度=0。
遍历图的二维矩阵arcs的第vexPos行,数值为1,则出度加1。
返回出度。
int getOutDegree(MyGraph& G, int vexPos)
{
//打印顶点vex的出度,vexPos为vex点的位置
int out = 0;
for (int i = 0; i < G.vexNum; i++)
{
out += G.arcs[vexPos][i];
}
return out;
}
2.5 printAdjVex(MyGraph &G,int vexPos)
流程:
遍历图的二维矩阵arcs的第vexPos行和第vexPos列:
若数值为1,打印第该行/列的节点。
void printAdjVex(MyGraph& G, int vexPos)
{
//打印所有邻接点
printf("%d的邻接点:", G.vexs[vexPos]);
for (int i = 0; i < G.vexNum; i++)
{
if (G.arcs[i][vexPos] || G.arcs[vexPos][i])
cout << G.vexs[i] << " ";
}
}
3. 连通图的遍历
3.1 void DFSTravse(MyGraph &G,int i)
流程:
定义栈s,将k入栈(代表从k开始搜索)。
若s不空,取栈顶元素为e,则遍历图中的二维矩阵arcs的第e行,若数值为1,则放入栈中。重复该步骤。
若s空,则将结束搜索。
void DFSTravse(MyGraph& G)
{
//深度优先搜索
bool vis[MAXVEXNUM] = { 0 };
stack< VexType>s;
int node = 0;
//从下标0开始搜索
s.push(G.vexs[0]);
while (node < G.vexNum && s.size())
{
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[s.top()][i])
{
s.push(i);
vis[i] = true;
node++;
break;
}
}
}
}
问题1:你编写的算法适用于连通图还是非连通图?为什么?
适用于连通图。
因为当图非连通,遍历完一部分后,若剩下的点与该部分不连通,则也结束遍历。
问题2:如何改造适用于非连通图。
加入判断条件,当栈s为空时,挑选vis数组中值为0的最小下标放入栈s中。
直到所有的节点都已经遍历完。
while (node < G.vexNum)
{
if (s.empty())
{
int i;
for (i = 0; vis[i]; i++);
s.push(i);
}
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[s.top()][i])
{
s.push(i);
vis[i] = true;
node++;
break;
}
}
}
}
3.2 void BFSTravse(MyGraph &G, int i)
流程:
定义队列q和qq。
将0放入k内(代表从k开始广度优先遍历)。
只要q中有节点,重复下列步骤:
对于q中的每个节点,将他们的邻接结点放入qq中。
清空q,并调换q和qq。
void BFSTravse(MyGraph& G, int k)
{
//广度优先搜索
bool vis[MAXVEXNUM] = { 0 };
queue< VexType>q, qq;
int node = 0;
//从下标i开始搜索
q.push(k);
while (node < G.vexNum && q.size())
{
while (q.size())
{
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[q.front()][i])
{
qq.push(i);
vis[i] = true;
node++;
}
}
q.pop();
}
swap(q, qq);
}
}
4. 判定图中两个顶点之间有无通路
4.1【法一】判定图中两个顶点之间有无通路
流程:
定义vis数组用于记录每个节点的访问情况。
定义队列q用于储存当前节点。
将开始节点放入q,将开始节点的vis设置为1(已访问)。
q不为空时,执行如下操作:
遍历所有节点,如果该节点没有被访问过并且与q队列首结点联通,则加入队列。
如果该节点是结束节点,则返回true。
执行一个队首出队操作。
当q为空,返回false。
bool printPathBetweenVex1(MyGraph& G, int startV, int endV)
{
bool vis[MAXVEXNUM] = { 0 };
queue< VexType>q;
q.push(startV);
vis[startV] = 1;
while (q.size())
{
while (q.size())
{
for (int i = 0; i < G.arcNum; i++)
{
if (vis[i] == 0 && G.arcs[q.front()][i])
{
if (i == endV)
return true;
q.push(i);
vis[i] = 1;
}
}
q.pop();
}
}
return false;
}
4.2【法二】判定图中两个顶点之间有无通路
流程:
定义set容器用于储存还没被访问过的节点。
将所有节点加入set容器。
定义队列q用于储存当前节点。
将开始节点放入q,将开始节点从set中删除。
q不为空时,执行如下操作:
遍历set中所有节点,如果该节点与q队列首结点联通,则加入队列。
如果该节点是结束节点,则返回true。
执行一个队首出队操作。
当q为空,返回false。
bool printPathBetweenVex2(MyGraph& G, int startV, int endV)
{
set<int>s;
for (int i = 0; i < G.arcNum; i++)
s.insert(i);
queue< VexType>q;
q.push(startV);
s.erase(startV);
while (q.size())
{
while (q.size())
{
queue<int>delnum;
for (auto x : s)
{
if (G.arcs[q.front()][x])
{
if (x == endV)
return true;
q.push(x);
delnum.push(x);
}
}
while (delnum.size())
{
s.erase(delnum.front());
delnum.pop();
}
q.pop();
}
}
return false;
}
4.3【进阶】判定图中两个顶点之间有无通路并打印路径
流程:
在上一题的基础上,加入father数组,储存每个点的上一个联通点,以便回溯。
当从起始点开始寻找通路,找到结束点时,从结束点开始回溯father[endV]并存入栈,直到father的数值为起始点为止。
打印栈中所有结点。
结果展示:
bool printPathBetweenVex3(MyGraph& G, int startV, int endV)
{
cout << endl << endl << endl;
cout << "G中" << G.vexs[startV] << "与" << G.vexs[endV] << "之间是否存在通路?" << endl;
int father[MAXVEXNUM] = { 0 };
bool vis[MAXVEXNUM] = { 0 };
queue< VexType>q, qq;
q.push(startV);
vis[startV] = 1;
while (q.size())
{
while (q.size())
{
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[q.front()][i])
{
father[i] = q.front();
if (i == endV)
{
cout << "存在通路: ";
stack<int>ans;
ans.push(endV);
while (ans.top() != startV)
{
ans.push(father[ans.top()]);
}
while (ans.size())
{
cout << G.vexs[ans.top()] << " ";
ans.pop();
}
cout << endl;
return true;
}
qq.push(i);
vis[i] = true;
}
}
q.pop();
}
swap(q, qq);
}
cout << "无通路" << endl;
return false;
}
4.4【进进阶】判定图中两个顶点之间有无通路并打印所有路径
流程:
定义s储存每次走过的节点。
定义vis数组记录节点的访问情况。
定义函数FindNextNode:
对于本次的节点k,放入s中,并将vis改成1(已访问状态);
如果本次的节点是结束节点,则:
打印s中的节点(即走过的路径)。
将s栈顶节点的vis设为0(未访问),并出栈。
结束本次函数。
否则:
遍历所有节点,如果节点没有被访问过且与s栈顶节点联通,则:
进入函数FindNextNode。
如果没有符合条件的节点,结束本次函数。
将开始节点放进函数FindNextNode,每次找到通路的时候,FindNextNode函数会打印s中的所有节点,即当前路径,并寻找下一条路径。
如果没有符合条件的路径,则打印“无通路”。
结果展示:
stack< int >s;
bool vis[MAXVEXNUM] = { 0 };
int num = 0;
void FindNextNode(int k, MyGraph G, int endV)
{
s.push(k);
vis[k] = 1;
if (k == endV)
{
printf("通路%d:", ++num);
stack<int>ans, ans2 = s;
while (ans2.size())
{
ans.push(ans2.top());
ans2.pop();
}
while (ans.size())
{
cout << G.vexs[ans.top()] << " ";
ans.pop();
}
cout << endl;
vis[s.top()] = 0;
s.pop();
return;
}
int flag = 0;
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[k][i])
{
FindNextNode(i, G, endV);
}
}
if (flag == 0)
{
vis[s.top()] = 0;
s.pop();
}
}
bool printPathBetweenVex4(MyGraph& G, int startV, int endV)
{
cout << endl << endl << endl;
cout << "G中" << G.vexs[startV] << "与" << G.vexs[endV] << "之间是否存在通路?" << endl;
FindNextNode(startV, G, endV);
if (num == 0)
cout << "无通路" << endl;
return false;
}
代码
#include<bits/stdc++.h>
using namespace std;
#define MAXVEXNUM 100
typedef int ArcCell;
typedef char VexType;
typedef struct {
VexType vexs[MAXVEXNUM];//点的集合
ArcCell arcs[MAXVEXNUM][MAXVEXNUM];//边的集合
int vexNum, arcNum;
}MyGraph;
void CreateUDGraphFromConsole(MyGraph& G, int vexNum, int arcNum);//无向图
void CreateDGraphFromConsole(MyGraph& G, int vexNum, int arcNum);//有向图
MyGraph GetGraphNum();
void LoadGraph(MyGraph G);//保存到本都
void GetGraph(MyGraph& G);//从本地读取图
void printMGraph(MyGraph& G);//打印图的邻接矩阵
int locateVex(MyGraph& G, VexType key);//若图中存在值为key的顶点,返回该顶点为位置,否则返回-1
int getInDegree(MyGraph& G, int vexPos);//打印顶点vex的入度,vexPos为vex点的位置
int getOutDegree(MyGraph& G, int vexPos);//打印顶点vex的出度,vexPos为vex点的位置
void printAdjVex(MyGraph& G, int vexPos);//打印或返回vex的所有邻接点
void destoryMGraph(MyGraph& G);//销毁图。可选:使用new或者malloc申请内存才需要销毁。直接使用数组则没必要手动销毁
void DFSTravse(MyGraph& G); //深度优先搜索
void BFSTravse(MyGraph& G, int i); //广度优先搜索
bool printPathBetweenVex(MyGraph& G, int startV, int endV);//判定图中两个顶点之间有无通路
bool printPathBetweenVex2(MyGraph& G, int startV, int endV);//判定图中两个顶点之间有无通路
bool printPathBetweenVex3(MyGraph& G, int startV, int endV);//判定图中两个顶点之间有无通路并打印路径
bool printPathBetweenVex4(MyGraph& G, int startV, int endV);//判定图中两个顶点之间有无通路,打印所有路径
int main()
{
MyGraph G1 = GetGraphNum();
CreateUDGraphFromConsole(G1, G1.vexNum, G1.arcNum);
MyGraph G2 = GetGraphNum();
CreateDGraphFromConsole(G2, G2.vexNum, G2.arcNum);
LoadGraph(G1);
MyGraph G3;
GetGraph(G3);
printMGraph(G3);
printPathBetweenVex2(G1, 0, 5);
printPathBetweenVex3(G1, 0, 3);
printPathBetweenVex4(G1, 0, 3);
/********************************test data*******************************
6
7
ABCDEF
0 1 0 4 1 4 1 5 2 3 2 5 3 5
5
7
ABCDE
0 1 0 4 1 2 2 3 3 0 3 1 4 2
*/
}
MyGraph GetGraphNum()
{
MyGraph G;
printf("请输入G的节点数:");
cin >> G.vexNum;
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
G.arcs[i][j] = 0;
}
}
printf("请输入G的边数:");
cin >> G.arcNum;
return G;
}
void CreateUDGraphFromConsole(MyGraph& G, int vexNum, int arcNum)
{
printf("\n*******************************创建无向图*******************************\n");
printf("请输入无向图的点:");
for (int i = 0; i < G.vexNum; i++)
{
cin >> G.vexs[i];
}
printf("请输入无向图的边:");
for (int i = 0; i < G.arcNum; i++)
{
int a, b;
cin >> a >> b;
//问:假如给每一条边加上一个权重w,满足w在(0,1)区间,如何修改该创建函数?
//答:将下面语句改成G.arcs[a][b] = G.arcs[b][a] = w;
G.arcs[a][b] = G.arcs[b][a] = 1;
}
printf("*******************************展示无向图*******************************\n");
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
cout << G.arcs[i][j] << " ";
}
cout << endl;
}
printf("**************************************************************************\n\n\n");
}
void CreateDGraphFromConsole(MyGraph& G, int vexNum, int arcNum)
{
printf("\n*******************************创建有向图*******************************\n");
printf("请输入有向图的点:");
for (int i = 0; i < G.vexNum; i++)
{
cin >> G.vexs[i];
}
printf("请输入有向图的边:");
for (int i = 0; i < G.arcNum; i++)
{
int a, b;
cin >> a >> b;
//问:假如给每一条边加上一个权重w,满足w在(0,1)区间,如何修改该创建函数?
//答:将下面语句改成G.arcs[a][b] = w;
G.arcs[a][b] = 1;
}
printf("*******************************展示有向图*******************************\n");
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
cout << G.arcs[i][j] << " ";
}
cout << endl;
}
printf("*************************************************************************\n");
}
void LoadGraph(MyGraph G)
{
//将数据保存到至G.txt文件中
ofstream outfile("G.txt", ios::trunc);
//保存点
outfile << G.vexNum;
for (int i = 0; i < G.vexNum; i++)
{
outfile << G.vexs[i];
}
//保存边
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
outfile << G.arcs[i][j] << " ";
}
}
//关闭
outfile.close();
}
void GetGraph(MyGraph& G)
{
ifstream myfile("C:\\Users\\Administrator\\Desktop\\G.txt");
if (!myfile.is_open())
{
cout << "can not open the file" << endl;
return;
}
//读取点
myfile >> G.vexNum;
printf("\n图的节点:");
for (int i = 0; i < G.vexNum; i++)
{
myfile >> G.vexs[i];
cout << G.vexs[i];
}
cout << endl;
//读取边
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
myfile >> G.arcs[i][j];
}
}
//关闭
myfile.close();
}
void printMGraph(MyGraph& G)
{
printf("*******************************展示图的邻接矩阵************************\n");
for (int i = 0; i < G.vexNum; i++)
{
for (int j = 0; j < G.vexNum; j++)
{
cout << G.arcs[i][j] << " ";
}
cout << endl;
}
printf("*************************************************************************\n");
}
int locateVex(MyGraph& G, VexType key)
{
//若图中存在值为key的顶点,返回该顶点为位置,否则返回-1
for (int i = 0; i < G.vexNum; i++)
{
if (G.vexs[i] == key)
return i;
}
return -1;
}
int getInDegree(MyGraph& G, int vexPos)
{
//打印顶点vex的入度,vexPos为vex点的位置
int in = 0;
for (int i = 0; i < G.vexNum; i++)
{
in += G.arcs[i][vexPos];
}
return in;
}
int getOutDegree(MyGraph& G, int vexPos)
{
//打印顶点vex的出度,vexPos为vex点的位置
int out = 0;
for (int i = 0; i < G.vexNum; i++)
{
out += G.arcs[vexPos][i];
}
return out;
}
void printAdjVex(MyGraph& G, int vexPos)
{
//打印所有邻接点
printf("%d的邻接点:", G.vexs[vexPos]);
for (int i = 0; i < G.vexNum; i++)
{
if (G.arcs[i][vexPos] || G.arcs[vexPos][i])
cout << G.vexs[i] << " ";
}
}
void destoryMGraph(MyGraph& G)
{
//销毁图。可选:使用new或者malloc申请内存才需要销毁。直接使用数组则没必要手动销毁
}
void DFSTravse(MyGraph& G)
{
//深度优先搜索
bool vis[MAXVEXNUM] = { 0 };
stack< VexType>s;
int node = 0;
//从下标0开始搜索
s.push(G.vexs[0]);
while (node < G.vexNum)
{
if (s.empty())
{
int i;
for (i = 0; vis[i]; i++);
s.push(i);
}
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[s.top()][i])
{
s.push(i);
vis[i] = true;
node++;
break;
}
}
}
}
void BFSTravse(MyGraph& G, int k)
{
//广度优先搜索
bool vis[MAXVEXNUM] = { 0 };
queue< VexType>q, qq;
int node = 0;
//从下标i开始搜索
q.push(k);
while (node < G.vexNum && q.size())
{
while (q.size())
{
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[q.front()][i])
{
qq.push(i);
vis[i] = true;
node++;
}
}
q.pop();
}
swap(q, qq);
}
}
bool printPathBetweenVex1(MyGraph& G, int startV, int endV)
{
bool vis[MAXVEXNUM] = { 0 };
queue< VexType>q;
q.push(startV);
vis[startV] = 1;
while (q.size())
{
while (q.size())
{
for (int i = 0; i < G.arcNum; i++)
{
if (vis[i] == 0 && G.arcs[q.front()][i])
{
if (i == endV)
return true;
q.push(i);
vis[i] = 1;
}
}
q.pop();
}
}
return false;
}
bool printPathBetweenVex2(MyGraph& G, int startV, int endV)
{
cout << endl << endl << endl;
cout << "G中" << G.vexs[startV] << "与" << G.vexs[endV] << "之间是否存在通路?" << endl;
set<int>s;
for (int i = 0; i < G.arcNum; i++)
s.insert(i);
queue< VexType>q;
q.push(startV);
s.erase(startV);
while (q.size())
{
while (q.size())
{
queue<int>delnum;
for (auto x : s)
{
if (G.arcs[q.front()][x])
{
if (x == endV)
{
cout << "存在通路" << endl;
return true;
}
q.push(x);
delnum.push(x);
}
}
while (delnum.size())
{
s.erase(delnum.front());
delnum.pop();
}
q.pop();
}
}
cout << "无通路" << endl;
return false;
}
bool printPathBetweenVex3(MyGraph& G, int startV, int endV)
{
cout << endl << endl << endl;
cout << "G中" << G.vexs[startV] << "与" << G.vexs[endV] << "之间是否存在通路?" << endl;
int father[MAXVEXNUM] = { 0 };
bool vis[MAXVEXNUM] = { 0 };
queue< VexType>q, qq;
q.push(startV);
vis[startV] = 1;
while (q.size())
{
while (q.size())
{
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[q.front()][i])
{
father[i] = q.front();
if (i == endV)
{
cout << "存在通路: ";
stack<int>ans;
ans.push(endV);
while (ans.top() != startV)
{
ans.push(father[ans.top()]);
}
while (ans.size())
{
cout << G.vexs[ans.top()] << " ";
ans.pop();
}
cout << endl;
return true;
}
qq.push(i);
vis[i] = true;
}
}
q.pop();
}
swap(q, qq);
}
cout << "无通路" << endl;
return false;
}
stack< int >s;
bool vis[MAXVEXNUM] = { 0 };
int num = 0;
void FindNextNode(int k, MyGraph G, int endV)
{
s.push(k);
vis[k] = 1;
if (k == endV)
{
printf("通路%d:", ++num);
stack<int>ans, ans2 = s;
while (ans2.size())
{
ans.push(ans2.top());
ans2.pop();
}
while (ans.size())
{
cout << G.vexs[ans.top()] << " ";
ans.pop();
}
cout << endl;
vis[s.top()] = 0;
s.pop();
return;
}
int flag = 0;
for (int i = 0; i < G.vexNum; i++)
{
if (vis[i] == 0 && G.arcs[k][i])
{
FindNextNode(i, G, endV);
}
}
if (flag == 0)
{
vis[s.top()] = 0;
s.pop();
}
}
bool printPathBetweenVex4(MyGraph& G, int startV, int endV)
{
cout << endl << endl << endl;
cout << "G中" << G.vexs[startV] << "与" << G.vexs[endV] << "之间是否存在通路?" << endl;
FindNextNode(startV, G, endV);
if (num == 0)
cout << "无通路" << endl;
return false;
}