拓扑排序---时间戳方法和顶点入度的方法。

(转自  http://www.cnblogs.com/ZJUKasuosuo/archive/2012/07/12/2587889.html

1. 拓扑排序主要有两种算法:方法1:《算法导论》上给出的DFS+时间戳;方法2:求顶点入度+贪心算法。

2. 两种算法的代码分别如下:

View Code 
 static int f[100]={0};
 static int ftime=0;
 //递归深度优先搜索
 template<typename vertexNametype, typename weight>
 void ALGraph<vertexNametype, weight>::DFS()
 {
     int n=getVertexNumber();
     bool *visited=new bool[n];
     for (int i=0;i<n;i++)
     {
         visited[i]=false;
     }
     for (int i=0;i<n;i++)
     {
         if (!visited[i])
         {
             DFS(i,visited);
             cout<<endl;
         }
     }
     delete[] visited;
 }
 
 
 
 template<typename vertexNametype, typename weight>
 void ALGraph<vertexNametype, weight>::DFS(int vertexNumber,bool visited[])
 {
     cout<<getData(vertexNumber)<<"  ";
     visited[vertexNumber]=true;
     Edge<weight> *p=m_vertexArray.at(vertexNumber).pAdjEdges;
     while(p!=NULL)
     {
         if (!visited[p->nDestVertex])
         {
             DFS(p->nDestVertex,visited);
         }
         p=p->pNextEdge;
     }
     //每一个节点访问结束之后,都记录其访问时间。
  //在每一个dfs的后面加上这个。
f[vertexNumber]=ftime; ftime++; } //拓扑排序算法一的思想是:用DFS遍历整个图,记录各个节点 //的完成时间,然后按各个节点的完成时间逆序排列,就得到了 //拓扑排序序列 template<typename vertexNametype, typename weight> void ALGraph<vertexNametype,weight>::Topological_sort1() { DFS(); int vectexNo=getVertexNumber(); for (int i=0;i<vectexNo;i++) { cout<<i<<" : "<<f[i]<<" "; } cout<<endl; int *tp=new int[vectexNo]; //按访问时间逆序排列
for (int i=0;i<vectexNo;i++) { tp[vectexNo-f[i]-1]=i; //位置为0的是值最大的那个,1的是次大的那个。然后逐渐递推。tp等于的i的值是结点的位置。用总数减去时间再-1就是他的位置了。(之所以-1,因为从0开始的。)                     //实际上就是将值对调,例如,4,3,2,1,0, 那么对应的位置就是0,1,2,3,4的位置。
} for (int i=0;i<vectexNo;i++) { cout<<getData(tp[i])<<" "; //得到那个结点的值。
} cout<<endl; delete[] tp; } ####################################################
//求一个图中所有节点的入度 template<typename vertexNametype, typename weight> void ALGraph<vertexNametype,weight>::FindIndegree(INOUT int* &Ind) { assert(Ind); int vertextNo=getVertexNumber(); for (int i=0;i<vertextNo;i++) { Edge<weight> *pE=m_vertexArray.at(i).pAdjEdges;// 找到这个结点的第一个弧
while(pE) { Ind[pE->nDestVertex]++; //给那个连接的顶点+1,因为跟他连接的那个顶点有了一个入度。
pE=pE->pNextEdge; } } } //拓扑排序2:方法一 //首先找到入度为0的节点,访问这个节点,并将这个节点 //的所有出边的邻接顶点的入读减1,访问这个顶点;下一步 //继续寻找入度为0的顶点,直到所有的节点均访问玩位置或者 //图中存在环 //时间复杂度为:O(v2) //template<typename vertexNametype, typename weight> //void ALGraph<vertexNametype,weight>::Topological_sort2() //{ // int vectexNo=getVertexNumber(); // int *InDegree=new int[vectexNo]; // for (int i=0;i<vectexNo;i++) // { // InDegree[i]=0; // } // FindIndegree(InDegree); // for (int i=0;i<vectexNo;i++) // { // cout<<getData(i)<<":"<<InDegree[i]<<" "; // } // cout<<endl; // bool *visited=new bool[vectexNo]; // vector<vertexNametype> top; // for (int i=0;i<vectexNo;i++) // { // visited[i]=false; // } // int count=0; // while(count++<vectexNo) // { // int IndexZero=0; // for (;IndexZero<vectexNo;IndexZero++) // { // if (InDegree[IndexZero]==0 && !visited[IndexZero]) // {             // 当没有环的时候,总会有这么一个满足条件的:总会有一个顶点的入度为0。当找到这个的时候,就跳出,没有的话就一直循环直到 indexzero 达到了最大值。
// break; } // } // if (IndexZero>=vectexNo) // { // break;         //这个用来判断终结上面那个循环的,究竟是找到了满足入度为0的顶点,还是没有找到,循环结束了。如果是循环结束了,那么说明有环,后面的没有必要
//继续了,直接跳出就行了。
// } // visited[IndexZero]=true; // top.push_back(getData(IndexZero)); // Edge<weight>* pE=m_vertexArray.at(IndexZero).pAdjEdges; // while(pE) // { // InDegree[pE->nDestVertex]--; // pE=pE->pNextEdge; // } // } // if (count<vectexNo) // {        //如果没有环,count会一直++,直到=总数的时候才终止循环的,但是有的话就<
// cout<<"Graph Has a cycle!!!"<<endl; // return ; // } // for (int i=0;i<vectexNo;i++) // { // cout<<top[i]<<" "; // } // cout<<endl; //} //在方案一中,每次寻找节点入度为0的节点,一个for //循环时间复杂度为O(v),改用queue每次将入读为0的节点 //存入队列,省去了下一步寻找入读为0的顶点的过程 template<typename vertexNametype, typename weight> void ALGraph<vertexNametype,weight>::Topological_sort2() { int vectexNo=getVertexNumber(); int *InDegree=new int[vectexNo]; for (int i=0;i<vectexNo;i++) { InDegree[i]=0; } FindIndegree(InDegree); queue<int> qu; int IndexZero=0; //首先将途中所有入读为0的顶点存入队列 for (;IndexZero<vectexNo;IndexZero++) { if (InDegree[IndexZero]==0) { qu.push(IndexZero); } } vector<vertexNametype> top; while(!qu.empty()) { IndexZero=qu.front(); qu.pop(); top.push_back(getData(IndexZero)); Edge<weight>* pE=m_vertexArray.at(IndexZero).pAdjEdges; while(pE) { InDegree[pE->nDestVertex]--; if (InDegree[pE->nDestVertex]==0) { qu.push(pE->nDestVertex); } pE=pE->pNextEdge; } } if (top.size()<vectexNo) { cout<<"Graph Has a cycle!!!"<<endl; return ; } for (int i=0;i<vectexNo;i++) { cout<<top[i]<<" "; } cout<<endl; }

  

3. 有人说利用DFS做拓扑排序算法有错,但是本人目前没发现这个算法有什么错误。 4. 拓扑排序可以做很多事情:如判断图中有没有环(利用方法2);排课程表(比如学C++之前一定要先学习C语言)。

5. 方法2的两种实现只有细微的差别,实现2更好一点,时间复杂度低,代码简洁。

6. 算法有不当之处,欢迎指正。

7. 算法测试使用图如下:

8. 程序运行结果(图的创建等基本程序参照随笔:图的相关算法):

A B C D E F G分别对应V1 V2 ... V7

转载于:https://www.cnblogs.com/kamendula/archive/2013/03/30/2990477.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值