Kahn算法-拓扑排序

来源:互联网 发布:js清空数组中所有元素 编辑:程序博客网 时间:2024/03/29 23:26
/*时间:2015/11/22内容:拓扑排序的实现(可用于判断图中是否有环路)概述:基于Kahn算法(DFS算法的实现),采用邻接表的方式来存储有向无权图,并实现对图的拓扑排序,在给出拓扑序列的同时,也能判断图中是否存在环路(即没有拓扑序列)操作:邻接表的创建 邻接表的打印 拓扑排序及其辅助函数*/#include<iostream>#include<vector>#include<deque>#include<memory>#include<algorithm>#include<utility>class edgesList//边表{public:    int index;//表示与之相连的顶点在顶点表中的编号    edgesList *next;//表示与之相连的其它顶点    edgesList(int index, edgesList* next) :index(index), next(next){}};class vertexList//顶点表{public:    char vertex;//当前顶点用字符表示    edgesList *edges;//表示与之相连的顶点,用智能指针管理    vertexList(char vertex, edgesList* next) :vertex(vertex), edges(next){}};class Graphe{public:    std::vector<vertexList> g;//图(邻接表存储方式)    std::vector<char> topologicallysort;//拓扑排序结果     std::vector<std::pair<int,bool>> incoming; //记录顶点的入度和是否已经从图中删除public:     //创建并初始化邻接表    Graphe()    {        int vertexNum=0, edgesNum=0;        std::cout << "输入图中的顶点数和边数 ";        std::cin >> vertexNum >> edgesNum;        std::cout << "输入图中的所有顶点编号 ";        for (int i = 0; i < vertexNum; ++i)        {            char vertexName;            std::cin >> vertexName;            g.push_back({ vertexName, NULL });        }        for (auto &v : g)        {            int n = 0;            std::cout << "输入从" << v.vertex<<"出发的顶点的数量和它们在数组中的下标";            std::cin >> n;            incoming.push_back({ 0, false });//记录每个定点的入度            for (int i = 0; i < n; ++i)//创建时采用头插法            {                               int index=0;                std::cin >> index;                                      edgesList* temp =new edgesList( index, NULL );                if (v.edges == NULL)                                    v.edges = temp;//此时直接插在头部                else                {                    temp->next = v.edges;                    v.edges = temp;                }                           }        }    }    //依次释放表中内存    ~Graphe()    {        for (auto &v : g)        {            edgesList* ptr = v.edges;            while (ptr)            {                edgesList* temp = ptr;                ptr = ptr->next;                free(temp);            }        }    }    //打印邻接表    void type()    {        for (auto &v : g)        {                       auto temp = v.edges;            std::cout << v.vertex;            while (temp)            {                   std::cout << "->" << temp->index;                temp = temp->next;                          }            std::cout << "-> End\n";        }    }    //初始化incoming和S    void initialize(std::deque<char>& S)    {               for (int i = 0; i < g.size();++i)        {                       edgesList* temp = g[i].edges;            while (temp)            {                ++incoming[temp->index].first;//没发现一次入的边,则对应的入度加一                temp = temp->next;            }        }        for (int i = 0; i < g.size(); ++i)        {            if (!incoming[i].first)//如果入度为0,则加入S中            {                S.push_back(g[i].vertex);                incoming[i].second = true;            }        }    }    //每次删除一个顶点后更新所有顶点的入度    void updateIncoming(std::vector<vertexList>::iterator v)    {         edgesList* temp=v->edges;        while (temp)//依次更新顶点的入度        {            if(incoming[temp->index].first)            --incoming[temp->index].first;            temp = temp->next;        }    }    //将表中入度为0且没有加入过S中的顶点纳入S    void updateS(std::deque<char>& S)    {        for (int i = 0; i < g.size(); ++i)//遍历整个入度表        if (!incoming[i].first && !incoming[i].second)//如果入度为0且没有加入S,则将之加入S后将标志域设置为true;        {            S.push_back(g[i].vertex);            incoming[i].second = true;        }    }    //拓扑排序    bool Kahn()    {        /*            std::vector<vertexList> g;            //图(邻接表存储方式)            std::vector<char> topologicallysort;  //拓扑排序结果             std::vector<int> incoming;            //记录顶点的入度            std::deque<char> S;                   //没有入度的顶点的集合        */        std::deque<char> S;        initialize(S);        while (!S.empty())        {            char curNode = S[0];            topologicallysort.push_back(curNode);//插入一个点进入拓扑序列            S.erase(S.begin());//从没有入度的顶点集合中删除该顶点            updateIncoming(std::find_if(g.begin(), g.end(), //更新入度                [curNode](vertexList c)->bool{ return c.vertex == curNode; }));            updateS(S);//更新集合S        }        if (topologicallysort.size()!=g.size())//如果拓扑排序的节点数和图中节点数不一致,则说明有环存在            return false;        else            return true;    }};int main(){    Graphe g;    g.type();    if (g.Kahn())    for (auto c : g.topologicallysort)        std::cout << c << ' ';    else        std::cout << "circle";    return 0;}
0 0
原创粉丝点击