对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。如下图
拓扑排序序列还可以为:C1,C3,C2,C4,C6,C5,C7当然还有别的可能。对于这些基础概念在此就不在强调,相信学过学过数据结构的同学,都知道它的概念,在此我们只要来看看拓扑排序的算法实现,以及各种算法的分析。
实现1:
bool TopologicalSortingVer1(int G[][Max],int Result[])
{
// 时间复杂度o(n~3)
int i,j,k;
bool Visit[Max];
for(i=0;i<Max;i++)Visit[i]=false;
for(k=0;k<Max;k++){
for(i=0;i<Max;i++){
if(Visit[i])continue;
for(j=0;j<Max;j++){
if(G[j][i]==1)break;
}
if(j<Max)continue;
Visit[i]=true;
for(j=0;j<Max;j++)G[i][j]=2;
Result[k]=i;
break;
}
if(i>=Max) return false;
}
return true;
}
这是一种很直接的想法,最外层的K循环,表示已经排序的个数,第二层的循环i表示从n个顶点中寻找一个还没有被排序的顶点(每次只找一个,当然可以改进,找多个),一旦找到,再判断这个顶点的入度是否为零,这就是第三层循环j。一旦不能找到这样入度为零的顶点了,排序结束,即存在有向圈。 这种算法的时间复杂度o(n~2)<T<o(n~3).
实现2:
void GetdInDegree(int G[][Max],int Degree[])
{
for(int i=0;i<Max;i++){
Degree[i]=0;
for(int j=0;j<Max;j++)
Degree[i]+=G[j][i];
}
}
bool TopologicalSortingVer2(int G[][Max],int Result[])
{
using std::stack;
// 时间复杂度
int i,j;
int Degree[Max];
stack<int> Mystack;
GetdInDegree(G,Degree);//o(n~2)或o(e);
for(i=0;i<Max;i++)//o(n);
if(Degree[i]==0)Mystack.push(i);
int Count=0;
while(!Mystack.empty()){
Result[Count]=Mystack.top();
Mystack.pop();
for(j=0;j<Max;j++)
if(G[Result[Count]][j]==1){
Degree[j]–;
if(Degree[j]==0)Mystack.push(j);
}
Count++;
}
//while循环的时间复杂度分析类型与深度优先搜索,每个元素仅仅进出栈一次,在每一次出栈后寻找他的邻接点(邻接表储存矩阵时o(n)邻接表储存时o(e_1),)
//所以while循环时间复杂度为o(n~2)或o(e)
if(Count<Max)return false;
return true;
//所以总的时间度为o(n~2)或o(n+e);
}
这种版本i就是数据结构(严蔚敏版本)书中介绍的,在此就不多说了。
实现3:
int Index=Max-1;
void DFS_TopologicalSorting(int G[][Max],int BeginVer,int Result[])
{
Visited[BeginVer]=true;
for(int i=0;i<Max;i++)
if(IsEdgeFuncion(G,BeginVer,i)&&!Visited[i]){
DFS_TopologicalSorting(G,i,Result);
}
Result[Index–]=BeginVer;
}
bool TopologicalSortingVer3(int G[][Max],int Result[],bool(*IsEdgeFun)(int G[][Max],int, int))
{
int i,BeginVer=0;
for(i=0;i<Max;i++)Visited[i]=false;
IsEdgeFuncion=IsEdgeFun;
DFS_TopologicalSorting(G,BeginVer,Result);
if(Index>=0)return false;
else return true;
//时间复杂度类似于深度优先遍历为:o(n~2)或o(n+e)
}
数据结构书中提到过,可以利用深度优先来实现拓扑排序,但没有给出实现,在此我们利用深度优先的递归版本来实现这个算法。