可以将图的拓扑排序看作是将图的所有结点在同一水平线上排开,图的所有有向边都从左指向右.
有向无环图的拓扑排序算法:
Toplogical-Sort(G) call DFS(G) to compute finish times v.f for each vertex v as each vertex is finished,insert onto the front of a linked list
//因为后被发现的结点的完成时间小于先被发现的结点 //实际上这里是按完成时间将结点从小到大排序 return the linked list of vertices
时间复杂度:O(|V|+|E|)
另一种算法:重复寻找入度为0的结点,输出该结点,将该结点及从其出发的边删除.
void find_indegree(Graph G,vector<int> &indegree){ for(int i=0;i<G.Adj.size();++i){ indegree.push_back(G.Adj[i].indegree); } } void toplogical_sort2(Graph G){ vector<int> indegree; find_indegree(G,indegree); stack<int> S; for(int i=0;i<G.Adj.size();++i){ if(!indegree[i]){ S.push(i);//入度为0的结点入栈 } } int count = 0; while(!S.empty()){ int i=S.top();//栈顶元素出栈 S.pop(); cout<<G.Adj[i].vertex<<","; ++count; for(auto p=G.Adj[i].firstNode;p != nullptr;p = p->next){ int k=p->index; //删除从结点i出发的边 if(!(--indegree[k])){ S.push(k); } } } assert(count == G.Adj.size());//若count<G.Adj.size(),则图中有回路 }
时间复杂度:O(|V|+|E|)
编码实现:
#include<iostream> #include<vector> #include<utility> #include<algorithm> #include<stack> #include<cassert> using namespace std; enum Color{white,gray,black}; vector<pair<int,int>> toplogical_list; class Node{ public: int index; Node* next=nullptr;// Node(int i):index(i){} }; class VNode{ public: char vertex; int dist; int final; int indegree; Color color=white; int prev=-1; Node* firstNode=nullptr; VNode(char c):vertex(c){} }; typedef struct Graph{ int EdgeNum; vector<VNode> Adj; }Graph; void DFS_VISIT(Graph &G,int u); int timex; void DFS(Graph &G){ for(int i=0;i<G.Adj.size();i++){ G.Adj[i].color = white; G.Adj[i].prev = -1; } timex =0; //begin from a certain vertex //DFS_VISIT(G,inndex); for(int i=0;i<G.Adj.size();i++){ if(G.Adj[i].color == white){ DFS_VISIT(G,i); } } } void DFS_VISIT(Graph &G,int u){ timex += 1; G.Adj[u].dist = timex; G.Adj[u].color = gray; //cout<<G.Adj[u].vertex<<","; Node* pv = G.Adj[u].firstNode; while(pv != nullptr){ int v= pv->index; if(G.Adj[v].color == white){ G.Adj[v].prev = u; DFS_VISIT(G,v); } pv = pv->next; } G.Adj[u].color = black; timex += 1; G.Adj[u].final = timex; toplogical_list.push_back(make_pair(u,timex)); } int comp(pair<int,int> a,pair<int,int> b){ if(a.second>b.second){ return -1; } else if(a.second==b.second){ return 0; } else{ return 1; } } void toplogical_sort(Graph G){ DFS(G); sort(toplogical_list.begin(),toplogical_list.end(),comp); for(const auto &c:toplogical_list ){ cout<<G.Adj[c.first].vertex<<","; } cout<<endl; } void find_indegree(Graph G,vector<int> &indegree){ for(int i=0;i<G.Adj.size();++i){ indegree.push_back(G.Adj[i].indegree); } } void toplogical_sort2(Graph G){ vector<int> indegree; find_indegree(G,indegree); stack<int> S; for(int i=0;i<G.Adj.size();++i){ if(!indegree[i]){ S.push(i); } } int count = 0; while(!S.empty()){ int i=S.top(); S.pop(); cout<<G.Adj[i].vertex<<","; ++count; for(auto p=G.Adj[i].firstNode;p != nullptr;p = p->next){ int k=p->index; if(!(--indegree[k])){ S.push(k); } } } assert(count == G.Adj.size()); } int main(){ Graph G; G.EdgeNum = 9; //vector<char> v{'v','r','s','w','x','y','t','u'}; vector<char> v{'v','r','s','w','x','y','t','u','p'}; for(int i=0;i<v.size();i++){ G.Adj.push_back(VNode(v[i])); } int i,j; for(int k=0;k<G.EdgeNum;k++){ cin>>i>>j; Node* p = new Node(j); p->next = G.Adj[i].firstNode; G.Adj[i].firstNode = p; ++G.Adj[j].indegree; /* p = new Node(i); p->next = G.Adj[j].firstNode; G.Adj[j].firstNode = p; */ } //DFS(G); toplogical_sort(G); toplogical_sort2(G); cout<<endl; return 0; }