• 使用C++语言BFS实现拓扑排序,BFS和DFS实现逆拓扑排序


    目录

    1.有向无环图

    2.拓扑排序

    (1)拓扑排序实现步骤

    (2)逆拓扑排序的实现步骤


    1.有向无环图

    有向无环图:一个无环的有向图。简称DAG图。

    有向无环图的应用:描述一项工程或系统的进行过程。由于几乎所有的工程都可分为若干个称为活动的子工程,而这些子工程之间也是存在约束的,比如某些子工程的开始必须在另外一些子工程完成之后才能进行。对于要完成的工程来说就是该工程能否顺利的进行和工程完成的最短时间。而有向无环图即可应用于此。

    2.拓扑排序

    由一个有向无环图的顶点组成的序列,当且仅当满足以下条件:

         a.每个顶点只能出现一次;

         b.若顶点A在序列中排在顶点B之前,那么B不能出现在A之前,也就是不能出现环;

    (1)拓扑排序实现步骤

    第一步:从AOV网中选择一个没有前驱(也就是入度为0的顶点)的顶点并输出;

    第二步:从网络中删除顶点和所有以它为起点的有向边;

    第三步:重复以上的操作,直到当前网络中不存在无前驱的顶点为止。

    注:AOV网:使用顶点表示活动,用弧表示活动之间的优先关系的有向图称为顶点表示活动的网络(Activity On Vertex Network)——AOV网。在网络中。若从顶点i到顶点j有一条有向路径,则i是j的前驱;j是i的后继。若是网络中一条弧,则i是j的直接前驱;j是i的直接后继。也就是AOV网络不能存在环,因为活动之间是有某种先后顺序关系的。

     如上图所示:当前网络中入度为0的只有顶点a,所以首先输出的顶点为a.

    1. #include<stdio.h>
    2. #include<queue>
    3. #include<stdlib.h>
    4. #define maxn 10
    5. #define inf 0x3f3f3f3f
    6. using namespace std;
    7. int n,m;
    8. //保存入度
    9. int indegree[maxn];
    10. //保存边
    11. int edge[maxn][maxn];
    12. //保存输出的拓扑排序
    13. int output[maxn];
    14. void init(){
    15. for(int i=0;i<maxn;i++){
    16. indegree[i]=0;
    17. output[i]=0;
    18. for(int j=0;j<maxn;j++){
    19. edge[i][j]=0;
    20. }
    21. }
    22. }
    23. void TopoSort(){
    24. queue<int>q;
    25. int count=0;
    26. for(int i=1;i<=n;i++){
    27. if(indegree[i]==0){
    28. q.push(i);
    29. }
    30. }
    31. int k=1;
    32. while(!q.empty()){
    33. int v=q.front();
    34. count++;
    35. q.pop();
    36. output[k++]=v;
    37. for(int i=1;i<=n;i++){
    38. if(i!=v&&edge[v][i]){
    39. indegree[i]--;
    40. if(indegree[i]==0){
    41. q.push(i);
    42. }
    43. }
    44. }
    45. }
    46. if(count==n){
    47. for(int i=1;i<n;i++){
    48. printf("%d->",output[i]);
    49. }
    50. printf("%d\n",output[n]);
    51. }else{
    52. printf("存在环!\n");
    53. }
    54. }
    55. int main(){
    56. init();
    57. printf("请输入顶点数: ");
    58. scanf("%d",&n);
    59. printf("请输入边数: ");
    60. scanf("%d",&m);
    61. printf("请输入边: \n");
    62. for(int i=1;i<=m;i++){
    63. int u,v;
    64. scanf("%d %d",&u,&v);
    65. indegree[v]++;
    66. edge[u][v]=1;
    67. }
    68. TopoSort();
    69. return 0;
    70. }
    71. /*
    72. 6 6
    73. 1 2
    74. 1 3
    75. 2 4
    76. 2 5
    77. 3 6
    78. 6 4
    79. */

    (2)逆拓扑排序的实现步骤

    第一步:从AOV网络中选择一个没有后继(出度为0)的顶点并输出;

    第二步:从网络中删除该顶点和所有以它为终点的有向边;

    第三步:重复上述操作,直至AOV网络为空。

    注:具体的画图和上面是类似的,只是从出度为0的顶点开始而已(相反的操作)。

     方式一:使用BFS输出逆拓扑排序

    1. #include<stdio.h>
    2. #include<queue>
    3. #include<stdlib.h>
    4. #define maxn 10
    5. #define inf 0x3f3f3f3f
    6. using namespace std;
    7. int n,m;
    8. //保存入度
    9. int outdegree[maxn];
    10. //保存边
    11. int edge[maxn][maxn];
    12. //保存输出的拓扑排序
    13. int output[maxn];
    14. void init(){
    15. for(int i=0;i<maxn;i++){
    16. outdegree[i]=0;
    17. output[i]=0;
    18. for(int j=0;j<maxn;j++){
    19. edge[i][j]=0;
    20. }
    21. }
    22. }
    23. void TopoSort(){
    24. queue<int>q;
    25. int count=0;
    26. for(int i=1;i<=n;i++){
    27. if(outdegree[i]==0){
    28. q.push(i);
    29. }
    30. }
    31. int k=1;
    32. while(!q.empty()){
    33. int v=q.front();
    34. count++;
    35. q.pop();
    36. output[k++]=v;
    37. for(int i=1;i<=n;i++){
    38. if(i!=v&&edge[i][v]){
    39. outdegree[i]--;
    40. if(outdegree[i]==0){
    41. q.push(i);
    42. }
    43. }
    44. }
    45. }
    46. // printf("%d\n",count);
    47. if(count==n){
    48. for(int i=1;i<n;i++){
    49. printf("%d->",output[i]);
    50. }
    51. printf("%d\n",output[n]);
    52. }else{
    53. printf("存在环!\n");
    54. }
    55. }
    56. int main(){
    57. init();
    58. printf("请输入顶点数: ");
    59. scanf("%d",&n);
    60. printf("请输入边数: ");
    61. scanf("%d",&m);
    62. printf("请输入边: \n");
    63. for(int i=1;i<=m;i++){
    64. int u,v;
    65. scanf("%d %d",&u,&v);
    66. outdegree[u]++;
    67. edge[u][v]=1;
    68. }
    69. TopoSort();
    70. return 0;
    71. }
    72. /*
    73. 6 6
    74. 1 2
    75. 1 3
    76. 2 4
    77. 2 5
    78. 3 6
    79. 6 4
    80. */

     方式二:使用DFS输出拓扑排序

    1. #include<stdio.h>
    2. #include<queue>
    3. #include<stdlib.h>
    4. #define maxn 10
    5. #define inf 0x3f3f3f3f
    6. using namespace std;
    7. int n,m;
    8. //保存出度
    9. int outdegree[maxn];
    10. bool vis[maxn];
    11. //保存边
    12. int edge[maxn][maxn];
    13. //保存输出的拓扑排序
    14. int output[maxn];
    15. int k=1;
    16. void init(){
    17. for(int i=0;i<maxn;i++){
    18. vis[i]=false;
    19. outdegree[i]=0;
    20. output[i]=0;
    21. for(int j=0;j<maxn;j++){
    22. edge[i][j]=0;
    23. }
    24. }
    25. }
    26. void DFS(int u){
    27. for(int i=1;i<=n;i++){
    28. //访问到当前的顶点时,如果存在出度,那么首先减一
    29. if(outdegree[u]>0){
    30. outdegree[u]--;
    31. }
    32. if(vis[i]==false){
    33. if(i!=u&&edge[u][i]){
    34. DFS(i);
    35. }
    36. }
    37. }
    38. //这一段主要是为了判断出度是否为0
    39. if(outdegree[u]==0){
    40. output[k++]=u;
    41. vis[u]=true;
    42. }else{
    43. //出栈的时候,前面是已经入栈的,并且也已经是首先减一的
    44. //所以前面已经出栈的表示已经访问了,因此和出栈的顶点之间的边需要断开
    45. //所以需要进行outdegree[u]--
    46. outdegree[u]--;
    47. if(outdegree[u]==0){
    48. output[k++]=u;
    49. vis[u]=true;
    50. }
    51. }
    52. }
    53. void DFSTopoSort(){
    54. for(int i=1;i<=n;i++){
    55. if(vis[i]==false){
    56. DFS(i);
    57. }
    58. }
    59. for(int i=1;i<n;i++){
    60. printf("%d->",output[i]);
    61. }
    62. printf("%d\n",output[n]);
    63. }
    64. int main(){
    65. init();
    66. printf("请输入顶点数: ");
    67. scanf("%d",&n);
    68. printf("请输入边数: ");
    69. scanf("%d",&m);
    70. printf("请输入边: \n");
    71. for(int i=1;i<=m;i++){
    72. int u,v;
    73. scanf("%d %d",&u,&v);
    74. edge[u][v]=1;
    75. outdegree[u]++;
    76. }
    77. DFSTopoSort();
    78. return 0;
    79. }
    80. /*
    81. 6 6
    82. 1 2
    83. 1 3
    84. 2 4
    85. 2 5
    86. 3 6
    87. 6 4
    88. 6 5
    89. 1 2
    90. 1 3
    91. 1 4
    92. 1 5
    93. 1 6
    94. */

     

  • 相关阅读:
    Cartopy绘图入门指南
    idea正常run,但是debug报错
    Hystrix的监控平台
    R语言的向量数据循环规则以及自动补齐机制(Recycling Rule)、在函数中也可以使用自动循环补齐机制(以cbind函数为例)
    分布式通过tcp控制开关
    Android 调试桥 (adb) 使用教程/示例
    0基础跟我学python---Django(2)
    树大总结(王道+红皮书)
    王学岗音视频开发(二)—————OpenGLES开发实践
    metaRTC5.0实现webrtc的TURN支持
  • 原文地址:https://blog.csdn.net/Keep_Trying_Go/article/details/126453912