当前位置:   article > 正文

数据结构--拓扑排序

数据结构--拓扑排序

一、拓扑排序

        对于一个有向无环图G进行拓扑排序,是将G中所有节点排成一个线性序列,该序列满足以下两个条件:① 每个节点有且仅出现一次 ② 若存在一条从节点A到节点B的路径,则在序列中A一定出现在B前面。

        对于求一个有向无环图的拓扑排序步骤:

                1.在图中找到一个没有前驱(入度为0)的节点,然后输出

                2. 从图中删除该节点和所有以它为起点的有向边 ( 使边到达的节点 v 的入度-1) 

                3.重复操作1和操作2,直到图为空 或 当前图不存在无前驱的顶点为止(图存在环)

 第一步操作,删除节点 1

第二步操作,删除节点 2

 第三步操作,删除节点4

        

最后拓扑排序依次为 3 5,不再画图讲述。 

所以最后拓扑排序的顺序依次为 1 2 4 3 5 

二、代码实现拓扑排序

        1.Kahn算法

        算法思路:与上述实践过程相同

                ①记录各个点的入度,将入度为0的点加入队列

                ②依次将队列里的点取出,将以该点为起始点的边,删除边,并将另一侧的入度-1,若此时该点入度为0,则入队

                ③ 每个节点入队的顺序即为拓扑排序的顺序,若存在某点没有进入过队列,则无法进行拓扑排序

  1. void tuopo()
  2. {
  3. queue<int>q;
  4. for(int i=1;i<=n;i++)
  5. if(in[i]==0) q.push(i); //将入度为0的点入队列
  6. while(!q.empty())
  7. {
  8. int u=q.front(); q.pop(); // 选一个入度为0的点,出队列
  9. ans[++sum]=u;
  10. for(int i=head[u];i!=1;i=edge[i].next)
  11. {
  12. int v=egde[i].v;
  13. in[y]--;
  14. if(in[y]==0)
  15. q.push(y);
  16. }
  17. }
  18. }

       2. dfs 算法 (实现逆拓扑排序)

         根据节点的出度判断,即当节点 x 不能够继续深搜时,加入逆拓扑排序序列中。最后再根据逆拓扑排序序列倒序输出即可。

        需要对所有点都深搜一遍.

        以例题B3644 【模板】拓扑排序 / 家谱树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)                 代码如下:

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<queue>
  4. #include<iostream>
  5. using namespace std;
  6. int head[100001],vis[1001],cnt,ans[1001];
  7. struct node{
  8. int v,next;
  9. }edge[100001];
  10. queue<int>q;
  11. int in[100001];
  12. void addedge(int u,int v) // 链式前向星
  13. {
  14. edge[++cnt].v=v;
  15. edge[cnt].next=head[u];
  16. head[u]=cnt;
  17. }
  18. void dfs(int u)
  19. {
  20. if(vis[u]==1) return ;
  21. vis[u]=1;
  22. for(int i=head[u];i!=-1;i=edge[i].next)
  23. {
  24. int v=edge[i].v;
  25. if(!vis[v]) dfs(v); // 没有访问过,深搜
  26. }
  27. q.push(u);
  28. return ;
  29. }
  30. int main()
  31. {
  32. int n;
  33. memset(head,-1,sizeof(head)); // 初始化
  34. scanf("%d",&n);
  35. for(int i=1;i<=n;i++) //建边 题目要求
  36. {
  37. int x;
  38. scanf("%d",&x);
  39. if(x!=0) addedge(i,x);
  40. while(x!=0)
  41. {
  42. scanf("%d",&x);
  43. if(x!=0) addedge(i,x);
  44. }
  45. }
  46. int x;
  47. for(int i=1;i<=n;i++) // 每个点都搜一边,存在多个图的情况
  48. dfs(x);
  49. for(int i=1;i<=n;i++) {ans[i]=q.front();q.pop();}
  50. for(int i=n;i>=1;i--) printf("%d ",ans[i]);
  51. return 0;
  52. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/669831
推荐阅读
相关标签
  

闽ICP备14008679号