图的应用——拓扑排序(判断有向图有无回路)
Posted Rainbowman 0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图的应用——拓扑排序(判断有向图有无回路)相关的知识,希望对你有一定的参考价值。
1. 拓扑排序的用处
对于有向图,我们有时候需要确保没有回路出现,如下面的例子:
学生学习的课程之间的优先关系构成了一个有向图,显然,该有向图不能出现回路,毕竟哪个学生也不想一直循环学习某几门课程不毕业。
P.s:这种用顶点表示活动,有向边表示活动之间的关系的有向图成为AOV网。
而拓扑排序的作用,就是帮我们判断一个有向图是否有回路出现。
2. 拓扑排序的思想
其实拓扑排序的思想很简单:
(1)在有向图中选择一个没有前驱(入度为0)的顶点输出;
(2)从图中删除该顶点和所有以它为尾的弧;
(3)重复(1)、(2)两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。
若所有顶点都被输出,则说明原有向图中没有回路;否则,说明有回路。
【举例】
3. 代码实现
代码实现也很简单,首先基于邻接表构造有向图,注意每个顶点结构体中需要加入一项int InDgree 表示该顶点的入度数(因为要把入度为0的顶点删除)。
我用的是栈来暂时存储删除的顶点,其实用队列或者别的容器都行,只是为了临时存储。
#include <iostream>
#include <stack>
#define MAX_VERTEX_NUM 20
#define OK 1
#define ERROR 0
using namespace std;
typedef char NumType;
typedef int Status;
//下面是邻接表构造有向图过程
struct ArcNode
{
int AdjVex;
ArcNode *NextArc;
};
struct VexNode
{
NumType data;
int InDegree;
ArcNode *FirstArc;
};
struct ALGraph
{
VexNode Vex[MAX_VERTEX_NUM];
int VexNum;
int ArcNum;
};
int Locate(ALGraph G,NumType v)
{
int i;
for(i=0;i<G.VexNum;i++)
if(v==G.Vex[i].data)return i;
return -1;
}
void CreatALGraph(ALGraph &G)
{
cout<<"请输入顶点数和弧数:"<<endl;
cin>>G.VexNum;cin>>G.ArcNum;
int i;
cout<<"请输入顶点数据:"<<endl;
for(i=0;i<G.VexNum;i++)
{
cin>>G.Vex[i].data;
G.Vex[i].FirstArc=0;
G.Vex[i].InDegree=0;
}
NumType v1,v2;
int j,k;
cout<<"请输入弧:"<<endl;
for(k=0;k<G.ArcNum;k++)
{
cin>>v1;cin>>v2;
i=Locate(G,v1);j=Locate(G,v2);
G.Vex[j].InDegree++;
ArcNode *p=new ArcNode();
*p={j,G.Vex[i].FirstArc};
G.Vex[i].FirstArc=p;
}
}
//上面是用邻接表构造有向图
//下面是拓扑排序代码
void TopoLogicalSort(ALGraph G)
{
ArcNode *p=0;
stack<int> s;
int i;
for(i=0;i<G.VexNum;i++)
if(G.Vex[i].InDegree==0)s.push(i);
int t;
int count0=0;
while(!s.empty())
{
count0++;
t=s.top();
s.pop();
cout<<G.Vex[t].data<<" ";
for(p=G.Vex[t].FirstArc;p!=0;p=p->NextArc)
{
G.Vex[p->AdjVex].InDegree--;
if(!G.Vex[p->AdjVex].InDegree)s.push(p->AdjVex);
}
}
if(count0==G.VexNum){cout<<"YES";return;}
cout<<"NO";
}
int main()
{
ALGraph G;
CreatALGraph(G);
TopoLogicalSort(G);
return 0;
}
以上是关于图的应用——拓扑排序(判断有向图有无回路)的主要内容,如果未能解决你的问题,请参考以下文章