判断有向图是否有环 、环的个数以及环中元素

判断有向图是否有环有三种方法:拓扑排序、深度遍历+回溯、深度遍历 + 判断后退边

这里使用 拓扑排序深度遍历 + 回溯判断是不是环。使用 深度遍历 + 判断后退边找出环个数 以及环中元素

1、拓扑排序

思想:找入度为0的顶点,输出顶点,删除出边。循环到无顶点输出。

若:输出所有顶点,则课拓扑排序,无环;反之,则不能拓扑排序,有环

使用:可以使用拓扑排序为有向无环图每一个结点进行编号,拓扑排序输出的顺序可以为编号顺序

源代码:

#include 
using namespace std;
const int MAX_Vertex_Num = 20;
template
class MGraph
{
public:
	void CreateGraph();//创建图
	int LocateVex(VexType v);//返回顶点v所在顶点向量中的位置(下标)
	void CheckCircle();
private:
	VexType vexs[MAX_Vertex_Num];//顶点向量
	ArcType arcs[MAX_Vertex_Num][MAX_Vertex_Num]; //这里把邻接矩阵类型用模板表示,主要是为了处理有权值的情况,比如:权值可以为小数(代价),也可以为整数
	int vexnum;//顶点数
	int arcnum;//边数
private:
	bool TopSort();
};

template
void MGraph::CreateGraph()
{
	VexType first;
	VexType Secend;
	cout<<"请输入顶点数:";
	cin>>vexnum;
	cout<<"请输入边数:";
	cin>>arcnum;
	cout<<"请输入各个顶点值:";
	for (int i=0;i>vexs[i];
	}
	//初始化邻接矩阵
	for (int i=0;i>first>>Secend;
		//如果边有权值的话,则还应该输入权值
		int x = LocateVex(first);
		int y = LocateVex(Secend);
		arcs[x][y]=1;//如果是有权的话,这里应该是arc[x][y]=权值
	}
} 
/*
参数:v:表示顶点向量中一个值
函数返回值:函数返回v在顶点向量中的下标
*/
template
int MGraph::LocateVex(VexType v)
{
	for (int i=0;i
bool MGraph::TopSort()
{
	int count = 0;//拓扑排序输出顶点的个数
	int top = -1;
	int stack[MAX_Vertex_Num];
	int indegree[MAX_Vertex_Num]={0};
	//求各个顶点的入度--邻接矩阵要查询该元素的列(记录入度情况)--
	//如果是邻接表,就是麻烦在这里,查询结点入度很不方便
	for (int i=0;i-1)
	{
		int x = stack[top--];
		cout<
void MGraph::CheckCircle()
{
	if (TopSort())
	{
		cout<<"无环!"< G;
	G.CreateGraph();
	G.CheckCircle();
	system("pause");
	return 1;
}

测试:

有向图:

 

结果:

2、深度遍历 + 回溯

思想:用回溯法,遍历时,如果遇到了之前访问过的结点,则图中存在环。

代码:

#include 
using namespace std;
const int MAX_Vertex_Num = 20;
template
class MGraph
{
public:
	void CreateGraph();//创建图
	int LocateVex(VexType v);//返回顶点v所在顶点向量中的位置(下标)
	bool CheckCircle();//检查图中有无环
private:
	VexType vexs[MAX_Vertex_Num];//顶点向量
	ArcType arcs[MAX_Vertex_Num][MAX_Vertex_Num]; //这里把邻接矩阵类型用模板表示,主要是为了处理有权值的情况,比如:权值可以为小数(代价),也可以为整数
	int vexnum;//顶点数
	int arcnum;//边数
private:
	void CheckCircle(int u,bool& isExist,bool visited[MAX_Vertex_Num],bool Isvisited[MAX_Vertex_Num]);
};

template
void MGraph::CreateGraph()
{
	VexType first;
	VexType Secend;
	cout<<"请输入顶点数:";
	cin>>vexnum;
	cout<<"请输入边数:";
	cin>>arcnum;
	cout<<"请输入各个顶点值:";
	for (int i=0;i>vexs[i];
	}
	//初始化邻接矩阵
	for (int i=0;i>first>>Secend;
		//如果边有权值的话,则还应该输入权值
		int x = LocateVex(first);
		int y = LocateVex(Secend);
		arcs[x][y]=1;//如果是有权的话,这里应该是arc[x][y]=权值
	}
} 
/*
参数:v:表示顶点向量中一个值
函数返回值:函数返回v在顶点向量中的下标
*/
template
int MGraph::LocateVex(VexType v)
{
	for (int i=0;i
void MGraph::CheckCircle(int u,bool& isExist,bool visited[MAX_Vertex_Num],bool Isvisited[MAX_Vertex_Num])
{
	visited[u]=true;
	Isvisited[u]=true;
	for (int j=0;j
bool MGraph::CheckCircle()
{
	bool isExist = false;
	bool Isvisited[MAX_Vertex_Num]={false};
	bool visited[MAX_Vertex_Num]={false};
	for (int i=0;i G;
	G.CreateGraph();
	if (G.CheckCircle())
	{
		cout<<"图存在环!"<

结果测试:

图:

 

结果:

3、深度遍历 + 判断后退边

思想:用DFS(深度优先遍历),判断是否有后退边,若有,则存在环

具体来说,在遍历顶点的每一条边时,判断一下这个边的顶点是不是在栈中,如果在栈中,说明之前已经访问过了,这里再次访问,说明有环存在

判断后退边时,借助一个栈和一个数组

栈:即可以用来输出环

数组:inStack判断是否在栈中

源代码:

#include 
using namespace std;
const int MAX_Vertex_Num = 20;
template
class MGraph
{
public:
	void CreateGraph();//创建图
	int LocateVex(VexType v);//返回顶点v所在顶点向量中的位置(下标)
	void CheckCircle();
private:
	VexType vexs[MAX_Vertex_Num];//顶点向量
	ArcType arcs[MAX_Vertex_Num][MAX_Vertex_Num]; //这里把邻接矩阵类型用模板表示,主要是为了处理有权值的情况,比如:权值可以为小数(代价),也可以为整数
	int vexnum;//顶点数
	int arcnum;//边数
private:
	void DFS(int x,bool visited[MAX_Vertex_Num],int stack[MAX_Vertex_Num],int& top,bool inStack[MAX_Vertex_Num],int& count);

};

template
void MGraph::CreateGraph()
{
	VexType first;
	VexType Secend;
	cout<<"请输入顶点数:";
	cin>>vexnum;
	cout<<"请输入边数:";
	cin>>arcnum;
	cout<<"请输入各个顶点值:";
	for (int i=0;i>vexs[i];
	}
	//初始化邻接矩阵
	for (int i=0;i>first>>Secend;
		//如果边有权值的话,则还应该输入权值
		int x = LocateVex(first);
		int y = LocateVex(Secend);
		arcs[x][y]=1;//如果是有权的话,这里应该是arc[x][y]=权值
	}
} 
/*
参数:v:表示顶点向量中一个值
函数返回值:函数返回v在顶点向量中的下标
*/
template
int MGraph::LocateVex(VexType v)
{
	for (int i=0;i
void MGraph::CheckCircle()
{
	int count=0;//环的个数
	int top=-1;
	int stack[MAX_Vertex_Num];
	bool inStack[MAX_Vertex_Num]={false};
	bool visited[MAX_Vertex_Num]={false};
	for (int i=0;i
void MGraph::DFS(int x,bool visited[MAX_Vertex_Num],int stack[MAX_Vertex_Num],int& top,bool inStack[MAX_Vertex_Num],int& count)
{
	visited[x]=true;
	stack[++top]=x;
	inStack[x]=true;
	for (int i=0;i G;
	G.CreateGraph();
	G.CheckCircle();
	system("pause");
	return 1;
}

结果测试:

有向图:

 

结果:
 

你可能感兴趣的:(数据结构)