DAG是一种有向无环图,可以用来表示各种事务执行的先后顺序,而拓扑排序的作用就是找到恰当的工作顺序,使得对于所有有向边<u,v>,都保证顶点u出现在顶点v之前。具体的拓扑排序的形象解释我这里就不多废话了,下面直接附上两种搜索形式下的拓扑排序:
1.广度优先搜索实现的拓扑排序:
#include<iostream> #include<queue> #include<list> using namespace std; #define Max 10000 int N; bool visited[Max]; vector<int> G[Max]; int indeg[Max]; list<int> out; void bfs(int x) { queue<int> q; q.push(x); visited[x]=true; while(!q.empty()) { int u=q.front();q.pop(); out.push_back(u); for(int i=0;i<G[u].size();i++) { int v=G[u][i]; indeg[v]--; //删除当前访问节点的所有出边,并将其后继节点的入度减一 if(indeg[v]==0 && !visited[v]) //若后继节点中有入度为0并且未访问的,那么就将这个点放在 { //队列中,当做之后的拓扑排序的节点 visited[v]=true; q.push(v); } } } } void topologicalSort() { for(int i=0;i<N;i++) { visited[i]=false; } for(int u=0;u<N;u++) { if(indeg[u]==0 && !visited[u]) //找到入度为0并且未访问的点进行bfs bfs(u); } for(list<int>::iterator it=out.begin();it!=out.end();it++) { cout<<(*it)<<" "; } } int main() { int start,end,M; cin>>N>>M; for(int i=0;i<M;i++) { cin>>start>>end; G[start].push_back(end); indeg[end]++; } topologicalSort(); return 0; }
2.深度优先搜索实现的拓扑排序:
#include<iostream> #include<queue> #include<list> using namespace std; #define Max 10000 int N; bool visited[Max]; vector<int> G[Max]; list<int> out; void dfs(int u) { cout<<u<<endl; visited[u]=true; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(!visited[v]) dfs(v); } out.push_front(u); //和广度优先搜索中不一样,bfs是就是按照拓扑顺序,从前往后找,找到入度为0的顶点就进行输出 //而深度优先搜索dfs则是从后往前推,在不断深入图,找到最后没有后继结点,就放在输出队列一开始, //之后在不断递归返回时,再将其他没有后继节点的节点放在输出队列的开头,那么这样就会保证一开始 //进入输出队列的最深处的节点在最后输出,保证满足拓扑顺序 } void topologicalSort() { for(int i=0;i<N;i++) { visited[i]=false; } for(int u=0;u<N;u++) { if(!visited[u]) dfs(u); } for(list<int>::iterator it=out.begin();it!=out.end();it++) { cout<<(*it)<<" "; } } int main() { int start,end,M; cin>>N>>M; for(int i=0;i<M;i++) { cin>>start>>end; G[start].push_back(end); } topologicalSort(); return 0; }
对于拓扑排序,大家要知道的是,对于同一个DAG,其拓扑排序的结果可能不止一种,这里的广度和深度在确定了相同情况下先输出小编号的顶点或者大编号的顶点,所以只会输出一种结果,具体的对于求解所有的拓扑排序的结果,我之后会找个时间学习,并附上代码.
PS:这三月份以来,事情就特别多,首先本创结题,其次是准备江苏省计算机三级,准备了一个星期,才发现考试真的是水,心碎~之后我还是会坚持写博客~