数据结构 6-图

题目

实验目的:

  1. 掌握创建并使用图的两种存储方式:邻接矩阵、邻接表,掌握在这两种存储结构上图的基本操作(求点的入度、出度、找到某个点的邻接点等)。
  2. 掌握图的DFS与BFS代码实现。
  3. 掌握拓扑排序的代码实现。(课后)
  4. 掌握最短路径的代码实现。(课后)

参考代码(图的邻接矩阵存储结构):

#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编程题

    1. 图着色问题(主要是对无向图的邻接点进行操作)(必做)
    2. PTA编程题:六度空间(BFS应用)(必做)。
    3. 最短路径问题:PTA函数题:旅游规划(必做)
    4. 最小生成树问题
      1. PTA编程题:公路村村通。(必做)
      2. PTA编程题:通信网设计(非连通图)(选做)。
    5. PTA编程题:天梯地图(选做)

(7)附加:图的绘制,使用Graphviz进行图的绘制

 

提交要求:

  1. 对于要求课上完成的题目,请在实验课结束前提交代码至课堂派,并在课后完成实验报告,报告中要求给出伪代码或者实现思路(流程图或者自然语言描述),并且回答相关问题;
  2. 对于不要求课上完成的题目,请在实验课结束后提交代码至课堂派;
  3. PTA上的题目,还需要提交测试通过;
  4. 在实验报告中对每一道题都需要描述算法思路(可以用伪代码也可以用文字,还可以用ppt演示算法流程),实验报告为一个word、ppt或pdf文档,每个同学提交时将所有代码和实验报告统一放在文件夹中,文件夹命名为“学号后四位_姓名”,然后提交压缩文件,如有不同版本,请用“学号后四位_姓名_版本号”标识。

实验报告

实验步骤:

  1. 建图
  2. 图(邻接矩阵)的基本操作&&思考问题
  3. 连通图的遍历&&思考问题
  4. 判定途中两个顶点之间有无通路

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;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值