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


    题目:

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

      

    幸运之神的降临,往往只是因为你多看了一眼,多想了一下,多走了一步。
  • 相关阅读:
    django QuerySet对象转换成字典对象
    HTTP请求中三种参数类型
    django开发中遇到的问题
    win7下mysql8.0.12解压缩版安装
    Django小部件
    程序员上班有什么提高效率的技巧?
    Android应用AsyncTask处理机制详解及源码分析
    Android常用工具类
    Android Volley解析
    Android 开发有哪些新技术出现?
  • 原文地址:https://www.cnblogs.com/strongYaYa/p/5886867.html
Copyright © 2020-2023  润新知