用队列实现拓扑排序(致敬京东面试)
题目:
在一个有向无回路图G=(V,E)上,执行拓扑排序的另一种方法是重复地寻找一个入度为0的顶点,将该点输出,并将该顶点及其所有的出边从图中删除。解释如何来实现这一想法,才能使得它的运行时间为O(V+E)。如果G中包含回路的话,这个算法在运行时会发生什么?
思考:
初始时,所有入度为0的顶点入队列
while队列不为空,作以下处理:
取队列头结点,并出队列
处理以头结点为起点的所有的边,将边的终点的入度-1
若入度减为0,则入队列
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #include <iostream> #include <queue> using namespace std; #define N 10 //边结点结构 struct Edge { int start; //有向图的起点 int end; //有向图的终点 Edge *next; //指向同一个起点的下一条边 int type; //边的类型 Edge( int s, int e):start(s),end(e),next(NULL){} }; //顶点结点结构 struct Vertex { int id; Edge *head; //指向以该顶点为起点的下一条边 int degree; Vertex( int i):head(NULL),degree(0),id(i){} }; //图结构 struct Graph { Vertex *V[N+1]; //N个顶点 Graph() { int i; for (i = 1; i <= N; i++) V[i] = new Vertex(i); } ~Graph() { int i; for (i = 1; i <= N; i++) delete V[i]; } }; queue< int > Q; int time = 0; //插入边 void InsertEdge(Graph *G, Edge *E) { //如果没有相同起点的边 if (G->V[E->start]->head == NULL) G->V[E->start]->head =E; //如果有,加入到链表中,递增顺序排列,便于查重 else { //链表的插入,不解释 Edge *e1 = G->V[E->start]->head, *e2 = e1; while (e1 && e1->end < E->end) { e2 = e1; e1 = e1->next; } if (e1 && e1->end == E->end) return ; if (e1 == e2) { E->next = e1; G->V[E->start]->head =E; } else { e2->next = E; E->next = e1; } //插入边的同时,计下每个顶点的入度 G->V[E->end]->degree++; } } //拓扑排序 void Topological(Graph *G) { //队列初始化 while (!Q.empty()) Q.pop(); int i; //将所有入度为0的点入队列 for (i = 1; i <= N; i++) { if (G->V[i]->degree == 0) Q.push(i); } //队列不为空 while (!Q.empty()) { //队列首元素 int t = Q.front(); Q.pop(); //输出 cout<< char (t+ 'l' )<< ' ' ; //处理以头结点为起点的所有的边 Edge *e = G->V[t]->head; while (e) { //将边的终点的入度-1 G->V[e->end]->degree--; //若入度减为0,则入队列 if (G->V[e->end]->degree == 0) Q.push(e->end); e = e->next; } } cout<<endl; } int main() { //构造一个空的图 Graph *G = new Graph; Edge *E; //输入边 int i; char start, end; for (i = 1; i <= 14; i++) { cin>>start>>end; E = new Edge(start- 'p' , end- 'p' ); InsertEdge(G, E); //无向图,要加两条边 // E = new Edge(end, start); // InsertEdge(G, E); } //拓扑排序并输出 Topological(G); return 0; } |
幸运之神的降临,往往只是因为你多看了一眼,多想了一下,多走了一步。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步