zoukankan      html  css  js  c++  java
  • 拓扑排序

      指针对于有向图,可用顶点表示活动,用弧表示活动间的优先关系的有向无环图称为顶点表示活动的网,即AOV-网。

    特点:

    1. 先行关系具有传递性
    2. AOV-网的拓扑排序(图中顶点的线性顺序称为拓扑排序)不唯一

    拓扑排序的基本思想

    因为存储方式不同,拓扑排序算法也不同,但基本思想相同

    1. 从有向无环图中选一个无前驱的结点输出
    2. 将此节点和以它为起始结点的边删除
    3. 重复1,2直到不存在无前驱的结点
    4. 若此时输出的结点个数小于图中的结点个数,说明图中存在回路(环),否则输出的顶点顺序就是一个拓扑排序

    基于邻接矩阵的拓扑排序

    1. 选取1作为第一个新序号
    2. 找到一个未新编号的值为0的列j,若找到执行3否则,若所有的列都被编过号,排序结束,若有列未曾编号,图中有回路
    3. 输出列号对应的顶点j,把新序号赋值给新找到的列
    4. 将矩阵中的j对应的行全部置零
    5. 新序号加1转向2
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Graph
    {
        private:
            int num;
            int e;
            bool flag;
            vector<vector<int> > arr;
            vector<bool> visit;//标识该结点是否已经输出 
            vector<int> top_logical_sort;//保存拓扑排序的结果序列 
        public:
            Graph();
            void t_logical_sort();
    };
    Graph::Graph()
    {
        cout<<" num"<<endl;
        cin>>num;
        cout<<" e"<<endl;
        cin>>e;
        
        flag=false;
        visit.resize(num,false);
        
        arr.resize(num);
        for(int i=0;i<num;++i)
            arr.at(i).resize(num,0);
        
        cout<<" 输入边的两端点"<<endl; 
        pair<int,int> p;
        for(int i=0;i<e;++i)
        {
            cin>>p.first>>p.second;
            arr.at(p.first-1).at(p.second-1)=1;
        }
    }
    void Graph::t_logical_sort()
    {
        for(int i=0;i<num;++i)//依次检查每个点,因为在进行一次拓扑排序后会设置该行的状态,所以要进行num次检查 
        {
            for(int t=0;t<num;++t) 
            {
                for(int j=0;j<num;++j)//此for检查有没有不符合条件的值 
                {
                    if(t==j)//1.遇到自身 
                        continue;
                    else if(visit.at(t)||arr.at(j).at(t))//2.该结点被访问过或该结点有入度(即检查该列是不是全为0) 
                    {
                        flag=true;
                        break;
                    }
                }
                if(flag)
                {
                    flag=false;
                    continue;
                }
                else
                {
                    top_logical_sort.push_back(t);
                    visit.at(t)=true;    
                    for(int check=0;check<num;++check)//删除以t为起始点(出度)所有的边
                        arr.at(t).at(check)=0;
                    break;
                }
            }
            //flag=false;
        }
        for(auto i=top_logical_sort.begin();i<top_logical_sort.end();++i)
            cout<<*i+1<<"	";
        cout<<endl;
    }
    int main()
    {
        Graph g;
        g.t_logical_sort();
        return 0;
    }

     基于邻接表的拓扑排序

      设一个用于存放入度为0的顶点即没有前驱的结点的数组indegree[],查找入度为0的结点也就是找indegree[i]为0的i,删除以i为起点的所有的邻接顶点k,也就是对链在顶点i后面的顶点k将对应的indegree[k]减一操作。为避免重复检测入度为0的顶点,可以在设置一个辅助栈,若某一顶点的入度为0,则将它入栈,当某一顶点输出时,便将他从栈中删除。

    基本思想

    1. 首先求出各顶点的入度,并将入度为0的顶点入栈
    2. 只要栈不为空,重复一下处理
      • 将栈顶顶点打印并出栈
      • 将顶点i的每一个邻接点k的入度减一,如果顶点k的入度为0,便将他入栈
    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    #define max 100
    typedef struct Edgenode                                                //边表结构体 
    {
        int adjvex;                                                        //储存边表结点 
        int wight;                                                        //储存顶点间权值(可能用不上) 
        Edgenode *next;                                                    //连接边表结点的指针 
    }Edgenode;
     
    typedef struct                                                         //顶点表结构体 
    {
        Edgenode *firstedge;                                            //顶点表与边表的连接指针 
        bool x;                                                            //判断某一顶点是否已经输出,输出了为ture,判断时自动跳过 
        int data;                                                        //储存顶点值 
    }Vertexnode;
    typedef Vertexnode AdjList[max];                                    //顶点表数组,储存顶点
     
    typedef struct                                                        //图结构体 
    {
        int vertexnum;                                                    //储存顶点个数 
        int edgenum;                                                    //储存边的条数 
        AdjList adjlist;                                                //创建adjlist数组,用来保存顶点表的顶点 
    }Graph;
     
    void create_graph(Graph *G)
    {
        cout<<"input the vertexnum and edgenum"<<endl;                    //输入顶点数与边数 
        cin>>G->vertexnum>>G->edgenum;
        int i,j;
        Edgenode *e;                    
        for(i=0;i<G->vertexnum;i++)                                        //初始化 
        {
            G->adjlist[i].data=i;
            G->adjlist[i].firstedge=NULL;
            G->adjlist[i].x=false;
        }
        
        while(G->edgenum--)                                                //初始化输入顶点间关系 
        {
            cout<<"input the two points which be connected by a line"<<endl;
            cin>>i>>j;
            e=new Edgenode;
            e->adjvex=i;
            e->next=G->adjlist[j].firstedge;
            G->adjlist[j].firstedge=e;
        }
    }
     
    void order(Graph *G)                                                //拓扑排序函数 
    {
        
        int count,Count=0;                                                //count用于大循环,检查顶点表数组的每一个已保存顶点,Count用于每次输出一个顶点加一,最后检查count与Count是否相等 ,若相等,说明有环 
        for(count=0;count<G->vertexnum;count++)
        {
            int count1=0;
            if(!G->adjlist[count].x&&!G->adjlist[count].firstedge)        //如果被检测顶点还未输出(x为flase)并且入度为零(firstedge后无结点),则输出并删去其它顶点里拥有它的节点 
            {
                cout<<G->adjlist[count].data;
                G->adjlist[count].x=true;                                //将其设置为已输出 
                Count++;
                
                Edgenode *e;
                for(;count1<G->vertexnum;count1++)                        //检查其它顶点里是否有已输出顶点的相关节点 
                {
                    if(count1==count||G->adjlist[count1].x)                //如果是输出的顶点或已输出的顶点,则跳过(因为已经输出了) 
                        continue;
                    e=G->adjlist[count1].firstedge;
                    while(e)                                            //循环检查一个顶点的边表 
                    {    
                        if(e==G->adjlist[count1].firstedge&&e->adjvex==G->adjlist[count].data)//如果边表第一个便是已输出顶点的节点 
                        {
                            G->adjlist[count1].firstedge=e->next;
                            delete e;                                    //删去 
                            e=NULL;                                        //此边表已经不会再出现第二个已输出顶点的节点,while循环结束 
                            continue;
                        }
                        if(e->next&&e->next->adjvex==G->adjlist[count].data)//如果已输出节点在边表中第二个或后面的 
                        {
                            Edgenode *e1;
                            e1=e->next;
                            e->next=e1->next;                            //删去 
                            delete e1;
                        }
                        e=e->next;                                        //往下检查 
                    }
                    
                }
            }
            
        }
    }
     
    void show(Graph *G)                                                    //显示函数,显示每个顶点的邻接表(但此邻接表储存的是每个顶点的入度节点,不是出度节点) 
    {
        int count;
        Edgenode *e;
        for(count=0;count<G->vertexnum;count++)
        {
            e=G->adjlist[count].firstedge;
            cout<<G->adjlist[count].data<<'	'<<'	';
            while(e)
            {
                cout<<e->adjvex<<'	';
                e=e->next;
            }
            cout<<endl;
        }
    }
     
    int main()
    {
        Graph *G;
        G=new Graph;
        create_graph(G);
        show(G);
        cout<<endl<<"begin to order:"<<endl;
        order(G);
        cout<<endl<<"after ordering:<<endl";
        show(G);
        return 0;
    }
  • 相关阅读:
    仅允许修改输入框括号中内容
    Wget/httrack 爬取整站资源
    413 Request Entity Too Large 问题及方案详细分析
    python 安装 tensorflowjs
    WiFi TIM DTIM
    免费 CDN 玩法 —— 文件一键上传到 NPM
    函数式编程 —— 将 JS 方法函数化
    uniapp 复制操作
    splice() 方法用于添加或删除数组中的元素
    uni更改顶部标题
  • 原文地址:https://www.cnblogs.com/tianzeng/p/10458674.html
Copyright © 2011-2022 走看看