算法导论-22.4-5-用队列实现拓扑排序

本文介绍了一种在有向无环图上实现拓扑排序的方法,通过不断寻找入度为0的顶点进行输出,并从图中移除,确保算法的时间复杂度为O(V+E)。同时探讨了此方法在含有回路的图中的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

在一个有向无回路图G=(V,E)上,执行拓扑排序的另一种方法是重复地寻找一个入度为0的顶点,将该点输出,并将该顶点及其所有的出边从图中删除。解释如何来实现这一想法,才能使得它的运行时间为O(V+E)。如果G中包含回路的话,这个算法在运行时会发生什么?

 

思考:

初始时,所有入度为0的顶点入队列

while队列不为空,作以下处理:

         取队列头结点,并出队列

         处理以头结点为起点的所有的边,将边的终点的入度-1

         若入度减为0,则入队列

 

代码:

  1. #include <iostream>  
  2. #include <queue>  
  3. using namespace std;  
  4.   
  5. #define N 10  
  6.   
  7. //边结点结构  
  8. struct Edge  
  9. {  
  10.     int start;//有向图的起点  
  11.     int end;//有向图的终点  
  12.     Edge *next;//指向同一个起点的下一条边  
  13.     int type;//边的类型  
  14.     Edge(int s, int e):start(s),end(e),next(NULL){}  
  15. };  
  16. //顶点结点结构  
  17. struct Vertex  
  18. {  
  19.     int id;  
  20.     Edge *head;//指向以该顶点为起点的下一条边  
  21.     int degree;  
  22.     Vertex(int i):head(NULL),degree(0),id(i){}  
  23. };  
  24. //图结构  
  25. struct Graph  
  26. {  
  27.     Vertex *V[N+1];//N个顶点  
  28.     Graph()  
  29.     {  
  30.         int i;  
  31.         for(i = 1; i <= N; i++)  
  32.             V[i] = new Vertex(i);  
  33.     }  
  34.     ~Graph()  
  35.     {  
  36.         int i;  
  37.         for(i = 1; i <= N; i++)  
  38.             delete V[i];  
  39.     }  
  40. };  
  41.   
  42. queue<int> Q;  
  43. int time = 0;  
  44.   
  45. //插入边  
  46. void InsertEdge(Graph *G, Edge *E)  
  47. {  
  48.     //如果没有相同起点的边  
  49.     if(G->V[E->start]->head == NULL)  
  50.         G->V[E->start]->head =E;  
  51.     //如果有,加入到链表中,递增顺序排列,便于查重  
  52.     else  
  53.     {  
  54.         //链表的插入,不解释  
  55.         Edge *e1 = G->V[E->start]->head, *e2 = e1;  
  56.         while(e1 && e1->end < E->end)  
  57.         {  
  58.             e2 = e1;  
  59.             e1 = e1->next;  
  60.         }  
  61.         if(e1 && e1->end == E->end)  
  62.             return;  
  63.         if(e1 == e2)  
  64.         {  
  65.             E->next = e1;  
  66.             G->V[E->start]->head =E;  
  67.         }  
  68.         else  
  69.         {  
  70.             e2->next = E;  
  71.             E->next = e1;  
  72.         }  
  73.         //插入边的同时,计下每个顶点的入度  
  74.         G->V[E->end]->degree++;  
  75.     }  
  76. }  
  77. //拓扑排序  
  78. void Topological(Graph *G)  
  79. {  
  80.     //队列初始化  
  81.     while(!Q.empty())  
  82.         Q.pop();  
  83.     int i;  
  84.     //将所有入度为0的点入队列  
  85.     for(i = 1; i <= N; i++)  
  86.     {  
  87.         if(G->V[i]->degree == 0)  
  88.             Q.push(i);  
  89.     }  
  90.     //队列不为空  
  91.     while(!Q.empty())  
  92.     {  
  93.         //队列首元素  
  94.         int t = Q.front();  
  95.         Q.pop();  
  96.         //输出  
  97.         cout<<char(t+'l')<<' ';  
  98.         //处理以头结点为起点的所有的边  
  99.         Edge *e = G->V[t]->head;  
  100.         while(e)  
  101.         {  
  102.             //将边的终点的入度-1  
  103.             G->V[e->end]->degree--;  
  104.             //若入度减为0,则入队列  
  105.             if(G->V[e->end]->degree == 0)  
  106.                 Q.push(e->end);  
  107.             e = e->next;  
  108.         }  
  109.     }  
  110.     cout<<endl;  
  111. }  
  112.   
  113. int main()  
  114. {  
  115.     //构造一个空的图  
  116.     Graph *G = new Graph;  
  117.     Edge *E;  
  118.     //输入边  
  119.     int i;  
  120.     char start, end;  
  121.     for(i = 1; i <= 14; i++)  
  122.     {  
  123.         cin>>start>>end;  
  124.         E = new Edge(start-'p', end-'p');  
  125.         InsertEdge(G, E);  
  126.         //无向图,要加两条边  
  127. //      E = new Edge(end, start);  
  128. //      InsertEdge(G, E);  
  129.     }  
  130.     //拓扑排序并输出  
  131.     Topological(G);  
  132.     return 0;  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值