• 数据结构-拓扑排序


    情景引入 

    一个无环的有向图称作有向无环图(Directed Acycline Graph),简称DAG图。

    DAG图是描述含有公共子式的表达式的有效工具。

    在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,称这种有向图为顶

    点表示活动的网,简称AOV网。

    AOV网中不能出现回路,而判断一个AOV网是否有回路,可以通过“拓扑排序”来判断。

    算法思想

    1.从一个AOV网中选择一个没有前驱的顶点输出它。

    2.从AOV网中删除该顶点,并且删去所有以该顶点为尾的弧。

    3.重复上述两步,直到顶点全部被输出,或AOV网中不存在没有前驱的顶点位置。

    显然,若最后顶点全部被输出,代表AOV网中没有回路。

    若顶点没有被全部输出,即AOV网中还存在有前驱的顶点。

    那么,在程序层次我们该怎么实现呢?

    因为在拓扑排序中需要查找所有以某个顶点为尾的弧,需要找到该顶点的所有出边,为此,图应该

    采用邻接表存储。

    同时,因为还要判断某个顶点有没有入度,即找到没有前驱的顶点,我们还需要一个辅助数组

    degree数组用来确定某个顶点的入度。

    另外,为了防止重复检测入度为0的顶点,可以设置一个栈来暂存所有入度为0的顶点。

    代码部分

    1. #include
    2. #include
    3. #define MAX 100
    4. typedef struct ArcNode{
    5. int adjvex;
    6. int weight;
    7. struct ArcNode *nextarc;
    8. }ArcNode;
    9. typedef struct VNode{
    10. char vertex;
    11. ArcNode *firstarc;
    12. }VNode;
    13. typedef VNode AdjList[MAX];
    14. typedef struct ALGraph{
    15. AdjList adjlist;
    16. int vexnum,arcnum;
    17. }ALGraph;
    18. int LocateVertex(ALGraph *G,char v)
    19. {
    20. int k;
    21. for(k=0;kvexnum;k++)
    22. if(G->adjlist[k].vertex == v)
    23. return k;
    24. return -1;
    25. }
    26. void CreateALGraph(ALGraph *G)
    27. {
    28. int i,l1,l2,weight;
    29. char v1,v2;
    30. printf("请输入顶点数和边数:\n");
    31. scanf("%d%d",&G->vexnum,&G->arcnum);
    32. getchar();
    33. printf("请输入{%d}个顶点:\n",G->vexnum);
    34. for(i=0;ivexnum;i++){
    35. scanf("%c",&G->adjlist[i].vertex);
    36. G->adjlist[i].firstarc = NULL;
    37. }
    38. getchar();
    39. printf("请输入{%d}条边,格式如(v1 v2 权值)\n",G->arcnum);
    40. for(i=0;iarcnum;i++){
    41. scanf("%c %c %d",&v1,&v2,&weight);
    42. getchar();
    43. l1 = LocateVertex(G,v1);
    44. l2 = LocateVertex(G,v2);
    45. if(l1 == -1 || l2 == -1){
    46. printf("失败.\n");
    47. i = i - 1;
    48. continue;
    49. }
    50. else{
    51. ArcNode *tmp = (ArcNode*)malloc(sizeof(ArcNode));
    52. tmp->adjvex = l2;
    53. tmp->weight = weight;
    54. tmp->nextarc = G->adjlist[l1].firstarc;
    55. G->adjlist[l1].firstarc = tmp;
    56. printf("成功.\n");
    57. }
    58. }
    59. }
    60. void FindInDegree(ALGraph *G,int *indegree) //求入度函数
    61. {
    62. int i;
    63. ArcNode *p;
    64. for(i=0;ivexnum;i++)
    65. indegree[i] = 0; //初始化 indegree数组全部置为0
    66. for(i=0;ivexnum;i++){
    67. p = G->adjlist[i].firstarc;
    68. while(p){ //对p节点进行遍历
    69. indegree[p->adjvex]++; //对应索引入度加一
    70. p = p->nextarc;
    71. }
    72. }
    73. }
    74. void TopologicalSort(ALGraph *G,int n)
    75. {
    76. int indegree[n];
    77. int i,j,count;
    78. int top;
    79. ArcNode *p;
    80. FindInDegree(G,indegree); //求该图的所有顶点入度
    81. top = 0;
    82. for(i=0;ivexnum;i++){ //遍历图中顶点入度为0的顶点
    83. if(indegree[i] == 0){ //如果顶点入度为0,那么入栈
    84. indegree[i] = top; //令该顶点值为top指针的值
    85. top = i + 1; //top指针加一
    86. }
    87. }
    88. count = 0;
    89. while(top!=0){
    90. i = top - 1; //top指针减一
    91. top = indegree[i];
    92. printf("移除顶点:{%c}\n",G->adjlist[i].vertex);
    93. count++;
    94. for(p=G->adjlist[i].firstarc;p;p=p->nextarc){ //模拟移除以该顶点为弧尾的边
    95. j = p->adjvex; //这里的移除边,并不是真的删除这条边,而是数量减一
    96. if(--indegree[j] == 0){ //--表示该顶点入度减一后是否为0
    97. indegree[j] = top; //如果入度为0了,需要入栈
    98. top = j + 1; //top指针加一
    99. }
    100. }
    101. }
    102. if(count < n){
    103. printf("该图有回路.\n");
    104. }
    105. else{
    106. printf("该图没有回路.\n");
    107. }
    108. }
    109. int main()
    110. {
    111. ALGraph G;
    112. CreateALGraph(&G);
    113. TopologicalSort(&G,G.vexnum);
    114. return 0;
    115. }

    验证部分

    现在我们考虑下面这个例子:

    很显然该图是无环的。

    运行结果:

    我们再看这个例子:

    很显然这个图是有环的。

    运行结果:

    符合我们的要求。

  • 相关阅读:
    SpringBoot接收参数的几种常用方式
    C代码写的比Codex还溜的AI神器开源
    leetcode 1047. Remove All Adjacent Duplicates In String(删除相邻的重复字母)
    切换npm的版本
    SpringMVC的请求与响应和参数传递
    web内容如何保护:如何有效地保护 HTML5 格式的视频内容?
    Python3中.whl文件介绍
    蓝桥杯备赛(三)
    springcloud springboot nacos版本对应
    Footprint_Expert_2022-04_Pro 可以产生 cadence SPB16.6的封装
  • 原文地址:https://blog.csdn.net/zheshiyangyang/article/details/133997639