拓扑排序的两种算法
1. 拓扑排序主要有两种算法:方法1:《算法导论》上给出的DFS+时间戳;方法2:求顶点入度+贪心算法。
2. 两种算法的代码分别如下:
View Code
1 static int f[100]={0}; 2 static int ftime=0; 3 //递归深度优先搜索 4 template<typename vertexNametype, typename weight> 5 void ALGraph<vertexNametype, weight>::DFS() 6 { 7 int n=getVertexNumber(); 8 bool *visited=new bool[n]; 9 for (int i=0;i<n;i++) 10 { 11 visited[i]=false; 12 } 13 for (int i=0;i<n;i++) 14 { 15 if (!visited[i]) 16 { 17 DFS(i,visited); 18 cout<<endl; 19 } 20 } 21 delete[] visited; 22 } 23 24 25 26 template<typename vertexNametype, typename weight> 27 void ALGraph<vertexNametype, weight>::DFS(int vertexNumber,bool visited[]) 28 { 29 cout<<getData(vertexNumber)<<" "; 30 visited[vertexNumber]=true; 31 Edge<weight> *p=m_vertexArray.at(vertexNumber).pAdjEdges; 32 while(p!=NULL) 33 { 34 if (!visited[p->nDestVertex]) 35 { 36 DFS(p->nDestVertex,visited); 37 } 38 p=p->pNextEdge; 39 } 40 //每一个节点访问结束之后,都记录其访问时间。 41 f[vertexNumber]=ftime; 42 ftime++; 43 } 44 //拓扑排序算法一的思想是:用DFS遍历整个图,记录各个节点 45 //的完成时间,然后按各个节点的完成时间逆序排列,就得到了 46 //拓扑排序序列 47 template<typename vertexNametype, typename weight> 48 void ALGraph<vertexNametype,weight>::Topological_sort1() 49 { 50 DFS(); 51 int vectexNo=getVertexNumber(); 52 for (int i=0;i<vectexNo;i++) 53 { 54 cout<<i<<" : "<<f[i]<<" "; 55 } 56 cout<<endl; 57 int *tp=new int[vectexNo]; 58 //按访问时间逆序排列 59 for (int i=0;i<vectexNo;i++) 60 { 61 tp[vectexNo-f[i]-1]=i; 62 } 63 for (int i=0;i<vectexNo;i++) 64 { 65 cout<<getData(tp[i])<<" "; 66 } 67 cout<<endl; 68 delete[] tp; 69 } 70 71 //求一个图中所有节点的入度 72 template<typename vertexNametype, typename weight> 73 void ALGraph<vertexNametype,weight>::FindIndegree(INOUT int* &Ind) 74 { 75 assert(Ind); 76 int vertextNo=getVertexNumber(); 77 for (int i=0;i<vertextNo;i++) 78 { 79 Edge<weight> *pE=m_vertexArray.at(i).pAdjEdges; 80 while(pE) 81 { 82 Ind[pE->nDestVertex]++; 83 pE=pE->pNextEdge; 84 } 85 } 86 } 87 88 //拓扑排序2:方法一 89 //首先找到入度为0的节点,访问这个节点,并将这个节点 90 //的所有出边的邻接顶点的入读减1,访问这个顶点;下一步 91 //继续寻找入度为0的顶点,直到所有的节点均访问玩位置或者 92 //图中存在环 93 //时间复杂度为:O(v2) 94 //template<typename vertexNametype, typename weight> 95 //void ALGraph<vertexNametype,weight>::Topological_sort2() 96 //{ 97 // int vectexNo=getVertexNumber(); 98 // int *InDegree=new int[vectexNo]; 99 // for (int i=0;i<vectexNo;i++) 100 // { 101 // InDegree[i]=0; 102 // } 103 // FindIndegree(InDegree); 104 // for (int i=0;i<vectexNo;i++) 105 // { 106 // cout<<getData(i)<<":"<<InDegree[i]<<" "; 107 // } 108 // cout<<endl; 109 // bool *visited=new bool[vectexNo]; 110 // vector<vertexNametype> top; 111 // for (int i=0;i<vectexNo;i++) 112 // { 113 // visited[i]=false; 114 // } 115 // int count=0; 116 // while(count++<vectexNo) 117 // { 118 // int IndexZero=0; 119 // for (;IndexZero<vectexNo;IndexZero++) 120 // { 121 // if (InDegree[IndexZero]==0 && !visited[IndexZero]) 122 // { 123 // break; 124 // } 125 // } 126 // if (IndexZero>=vectexNo) 127 // { 128 // break; 129 // } 130 // visited[IndexZero]=true; 131 // top.push_back(getData(IndexZero)); 132 // Edge<weight>* pE=m_vertexArray.at(IndexZero).pAdjEdges; 133 // while(pE) 134 // { 135 // InDegree[pE->nDestVertex]--; 136 // pE=pE->pNextEdge; 137 // } 138 // } 139 // if (count<vectexNo) 140 // { 141 // cout<<"Graph Has a cycle!!!"<<endl; 142 // return ; 143 // } 144 // for (int i=0;i<vectexNo;i++) 145 // { 146 // cout<<top[i]<<" "; 147 // } 148 // cout<<endl; 149 //} 150 151 152 //在方案一中,每次寻找节点入度为0的节点,一个for 153 //循环时间复杂度为O(v),改用queue每次将入读为0的节点 154 //存入队列,省去了下一步寻找入读为0的顶点的过程 155 template<typename vertexNametype, typename weight> 156 void ALGraph<vertexNametype,weight>::Topological_sort2() 157 { 158 int vectexNo=getVertexNumber(); 159 int *InDegree=new int[vectexNo]; 160 for (int i=0;i<vectexNo;i++) 161 { 162 InDegree[i]=0; 163 } 164 FindIndegree(InDegree); 165 166 queue<int> qu; 167 int IndexZero=0; 168 //首先将途中所有入读为0的顶点存入队列 169 for (;IndexZero<vectexNo;IndexZero++) 170 { 171 if (InDegree[IndexZero]==0) 172 { 173 qu.push(IndexZero); 174 } 175 } 176 vector<vertexNametype> top; 177 while(!qu.empty()) 178 { 179 IndexZero=qu.front(); 180 qu.pop(); 181 top.push_back(getData(IndexZero)); 182 Edge<weight>* pE=m_vertexArray.at(IndexZero).pAdjEdges; 183 while(pE) 184 { 185 InDegree[pE->nDestVertex]--; 186 if (InDegree[pE->nDestVertex]==0) 187 { 188 qu.push(pE->nDestVertex); 189 } 190 pE=pE->pNextEdge; 191 } 192 } 193 if (top.size()<vectexNo) 194 { 195 cout<<"Graph Has a cycle!!!"<<endl; 196 return ; 197 } 198 for (int i=0;i<vectexNo;i++) 199 { 200 cout<<top[i]<<" "; 201 } 202 cout<<endl; 203 }
3. 有人说利用DFS做拓扑排序算法有错,但是本人目前没发现这个算法有什么错误。
4. 拓扑排序可以做很多事情:如判断图中有没有环(利用方法2);排课程表(比如学C++之前一定要先学习C语言)。
5. 方法2的两种实现只有细微的差别,实现2更好一点,时间复杂度低,代码简洁。
6. 算法有不当之处,欢迎指正。
7. 算法测试使用图如下:
8. 程序运行结果(图的创建等基本程序参照随笔:图的相关算法):
A B C D E F G分别对应V1 V2 ... V7