判断有向图是否有环有三种方法:拓扑排序、深度遍历+回溯、深度遍历 + 判断后退边
这里使用 拓扑排序 和 深度遍历 + 回溯判断是不是环。使用 深度遍历 + 判断后退边找出环个数 以及环中元素
1、拓扑排序
思想:找入度为0的顶点,输出顶点,删除出边。循环到无顶点输出。
若:输出所有顶点,则课拓扑排序,无环;反之,则不能拓扑排序,有环
使用:可以使用拓扑排序为有向无环图每一个结点进行编号,拓扑排序输出的顺序可以为编号顺序
源代码:
- #include <iostream>
- using namespace std;
- const int MAX_Vertex_Num = 20;
- template<class VexType,class ArcType>
- class MGraph
- {
- public:
- void CreateGraph();
- int LocateVex(VexType 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<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::CreateGraph()
- {
- VexType first;
- VexType Secend;
- cout<<"请输入顶点数:";
- cin>>vexnum;
- cout<<"请输入边数:";
- cin>>arcnum;
- cout<<"请输入各个顶点值:";
- for (int i=0;i<vexnum;i++)
- {
- cin>>vexs[i];
- }
-
- for (int i=0;i<arcnum;i++)
- {
- for (int j=0;j<arcnum;j++)
- {
- arcs[i][j]=0;
- }
- }
- cout<<"请输入边的信息:"<<endl;
- for (int i=0;i<arcnum;i++)
- {
- cin>>first>>Secend;
-
- int x = LocateVex(first);
- int y = LocateVex(Secend);
- arcs[x][y]=1;
- }
- }
-
-
-
-
- template<class VexType,class ArcType>
- int MGraph<VexType,ArcType>::LocateVex(VexType v)
- {
- for (int i=0;i<vexnum;i++)
- {
- if (vexs[i]==v)
- {
- return i;
- }
- }
- return -1;
- }
-
-
-
-
-
-
-
- template<class VexType,class ArcType>
- bool MGraph<VexType,ArcType>::TopSort()
- {
- int count = 0;
- int top = -1;
- int stack[MAX_Vertex_Num];
- int indegree[MAX_Vertex_Num]={0};
-
-
- for (int i=0;i<vexnum;i++)
- {
- int num=0;
- for (int j=0;j<vexnum;j++)
- {
- if (arcs[j][i]!=0)
- {
- num++;
- }
- }
- indegree[i]=num;
- }
-
- for (int i=0;i<vexnum;i++)
- {
- if (!indegree[i])
- {
- stack[++top]=i;
- }
- }
-
- while (top>-1)
- {
- int x = stack[top--];
- cout<<vexs[x];
- count++;
-
- for (int i=0;i<vexnum;i++)
- {
- if (arcs[x][i]!=0)
- {
- arcs[x][i]=0;
- indegree[i]--;
- if (!indegree[i])
- {
- stack[++top]=i;
- }
- }
- }
- }
- cout<<endl;
- if (count == vexnum)
- {
- return true;
- }
- return false;
- }
-
-
-
-
-
- template<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::CheckCircle()
- {
- if (TopSort())
- {
- cout<<"无环!"<<endl;
- }
- else
- {
- cout<<"有环!"<<endl;
- }
- }
-
- int main()
- {
- MGraph<char,int> G;
- G.CreateGraph();
- G.CheckCircle();
- system("pause");
- return 1;
- }
测试:
有向图:
结果:
2、深度遍历 + 回溯
思想:用回溯法,遍历时,如果遇到了之前访问过的结点,则图中存在环。
代码:
- #include <iostream>
- using namespace std;
- const int MAX_Vertex_Num = 20;
- template<class VexType,class ArcType>
- class MGraph
- {
- public:
- void CreateGraph();
- int LocateVex(VexType 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<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::CreateGraph()
- {
- VexType first;
- VexType Secend;
- cout<<"请输入顶点数:";
- cin>>vexnum;
- cout<<"请输入边数:";
- cin>>arcnum;
- cout<<"请输入各个顶点值:";
- for (int i=0;i<vexnum;i++)
- {
- cin>>vexs[i];
- }
-
- for (int i=0;i<arcnum;i++)
- {
- for (int j=0;j<arcnum;j++)
- {
- arcs[i][j]=0;
- }
- }
- cout<<"请输入边的信息:"<<endl;
- for (int i=0;i<arcnum;i++)
- {
- cin>>first>>Secend;
-
- int x = LocateVex(first);
- int y = LocateVex(Secend);
- arcs[x][y]=1;
- }
- }
-
-
-
-
- template<class VexType,class ArcType>
- int MGraph<VexType,ArcType>::LocateVex(VexType v)
- {
- for (int i=0;i<vexnum;i++)
- {
- if (vexs[i]==v)
- {
- return i;
- }
- }
- return -1;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- template<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::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<vexnum;j++)
- {
- if (arcs[u][j]==1)
- {
- if (visited[j]==false)
- {
- CheckCircle(j,isExist,visited,Isvisited);
- }
- else
- {
- isExist = true;
- }
- }
- }
- visited[u]=false;
- }
-
- template<class VexType,class ArcType>
- bool MGraph<VexType,ArcType>::CheckCircle()
- {
- bool isExist = false;
- bool Isvisited[MAX_Vertex_Num]={false};
- bool visited[MAX_Vertex_Num]={false};
- for (int i=0;i<vexnum;i++)
- {
- if (Isvisited[i]==false)
- {
- CheckCircle(i,isExist,visited,Isvisited);
- if (isExist)
- {
- return true;
- }
- }
- }
- return isExist;
- }
-
- int main()
- {
- MGraph<char,int> G;
- G.CreateGraph();
- if (G.CheckCircle())
- {
- cout<<"图存在环!"<<endl;
- }
- else
- {
- cout<<"图不存在环!"<<endl;
- }
- system("pause");
- return 1;
- }
结果测试:
图:
结果:
3、深度遍历 + 判断后退边
思想:用DFS(深度优先遍历),判断是否有后退边,若有,则存在环
具体来说,在遍历顶点的每一条边时,判断一下这个边的顶点是不是在栈中,如果在栈中,说明之前已经访问过了,这里再次访问,说明有环存在
判断后退边时,借助一个栈和一个数组
栈:即可以用来输出环
数组:inStack判断是否在栈中
源代码:
- #include <iostream>
- using namespace std;
- const int MAX_Vertex_Num = 20;
- template<class VexType,class ArcType>
- class MGraph
- {
- public:
- void CreateGraph();
- int LocateVex(VexType 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<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::CreateGraph()
- {
- VexType first;
- VexType Secend;
- cout<<"请输入顶点数:";
- cin>>vexnum;
- cout<<"请输入边数:";
- cin>>arcnum;
- cout<<"请输入各个顶点值:";
- for (int i=0;i<vexnum;i++)
- {
- cin>>vexs[i];
- }
-
- for (int i=0;i<arcnum;i++)
- {
- for (int j=0;j<arcnum;j++)
- {
- arcs[i][j]=0;
- }
- }
- cout<<"请输入边的信息:"<<endl;
- for (int i=0;i<arcnum;i++)
- {
- cin>>first>>Secend;
-
- int x = LocateVex(first);
- int y = LocateVex(Secend);
- arcs[x][y]=1;
- }
- }
-
-
-
-
- template<class VexType,class ArcType>
- int MGraph<VexType,ArcType>::LocateVex(VexType v)
- {
- for (int i=0;i<vexnum;i++)
- {
- if (vexs[i]==v)
- {
- return i;
- }
- }
- return -1;
- }
-
-
-
-
-
-
- template<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::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<vexnum;i++)
- {
- if (!visited[i])
- {
- DFS(i,visited,stack,top,inStack,count);
- }
- }
- }
-
- template<class VexType,class ArcType>
- void MGraph<VexType,ArcType>::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<vexnum;i++)
- {
- if (arcs[x][i]!=0)
- {
- if (!inStack[i])
- {
- DFS(i,visited,stack,top,inStack,count);
- }
- else
- {
- count++;
- cout<<"第"<<count<<"环为:";
-
-
- int t=0;
- for (t=top;stack[t]!=i;t--);
-
- for (int j=t;j<=top;j++)
- {
- cout<<vexs[stack[j]];
- }
- cout<<endl;
- }
- }
- }
-
- top--;
- inStack[x]=false;
- }
- int main()
- {
- MGraph<char,int> G;
- G.CreateGraph();
- G.CheckCircle();
- system("pause");
- return 1;
- }
结果测试:
有向图:
结果: