用队列实现拓扑排序(致敬京东面试)

题目:

在一个有向无回路图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; 

  

posted @   StrongYaYa  阅读(1173)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示