题目:
在一个有向无回路图G=(V,E)上,执行拓扑排序的另一种方法是重复地寻找一个入度为0的顶点,将该点输出,并将该顶点及其所有的出边从图中删除。解释如何来实现这一想法,才能使得它的运行时间为O(V+E)。如果G中包含回路的话,这个算法在运行时会发生什么?
思考:
初始时,所有入度为0的顶点入队列
while队列不为空,作以下处理:
取队列头结点,并出队列
处理以头结点为起点的所有的边,将边的终点的入度-1
若入度减为0,则入队列
代码:
- #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;
- }