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

题目:

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

  

posted @ 2016-09-19 22:01  StrongYaYa  阅读(1172)  评论(0编辑  收藏  举报