一、拓扑排序定义:


二、卡恩算法(Kahn):

1、Kahn算法介绍:

有向无环图DAG至少具有一个度数为0的顶点和一个度数为0的顶点
证明:上述事实有一个简单的证明,即DAG不包含循环,这意味着所有路径的长度都是有限的。现在,使S为从u(源)到v(目标)的最长路径。由于S是最长的路径,因此不会有到u的传入边缘,也不会有从v的传出边缘,因此,如果发生这种情况,则S不会是最长的路径
=> indegree(u)= 0outdegree(v)= 0

2、查找DAG的拓扑顺序涉及的步骤:

步骤1:为DAG中存在的每个顶点计算入度(传入边数),并将访问节点的计数初始化为0
步骤2:选取度数为0的所有顶点并将其添加到队列中(入队操作)
步骤3:然后从队列中删除一个顶点(出队操作)。访问的节点数增加1。将其所有相邻节点的度数减少1。如果相邻节点的入度减小到零,则将其添加到队列中。
步骤4:重复步骤3,直到队列为空。
步骤5:如果访问的节点数小于图中的节点数,则对于给定的图,不可能进行拓扑排序。

2、Kahn算法的伪代码:

L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edge
while S is non-empty doremove a node n from Sadd n to tail of Lfor each node m with an edge e from n to m doremove edge e from the graphif m has no other incoming edges theninsert m into S
if graph has edges thenreturn error   (graph has at least one cycle)
else return L   (a topologically sorted order)

3、代码:

#include<iostream>
#include<list>
#include<vector>
#include<queue>using namespace std;class Graph
{int n;            //顶点数list<int> *adj;  //邻接表
public:Graph(int _n) { n = _n; adj = new list<int>[_n];}~Graph(){ delete [] adj; }void addEdge(int v, int w){ adj[v].push_back(w); }void topologicalSort();
};
void Graph::topologicalSort()
{vector<int> indegree(n,0);for(int i = 0; i < n; i++){list<int>::iterator it;for(it = adj[i].begin(); it != adj[i].end(); it++){indegree[*it]++;    //邻居的入度+1 }}queue<int> q;    for(int i = 0; i < n; i++)        //入度为0的顶点先进队列{if(indegree[i] == 0){q.push(i); }} vector<int> topologicalOrder;  //存排好序的拓扑排序while(!q.empty()){int u = q.front();q.pop();topologicalOrder.push_back(u);      list<int>::iterator it;for(it = adj[u].begin(); it != adj[u].end(); it++){indegree[*it]--;if(indegree[*it] == 0){//新的入度为0的顶点加入队列q.push(*it);}}}if(topologicalOrder.size() < n){cout<<"这个图有环"<<endl;return ; }for(int i = 0; i < topologicalOrder.size(); i++){cout<<topologicalOrder[i]<<" "; }cout<<endl;
}
int main()
{ Graph g(6); g.addEdge(5, 2); g.addEdge(5, 0); g.addEdge(4, 0); g.addEdge(4, 1); g.addEdge(2, 3); g.addEdge(3, 1); cout << "这个图的拓扑排序是:\n"; g.topologicalSort(); return 0;
}


4、理解:

Kahn算法,主要就是利用了“有向无环图DAG至少具有一个度数为0的顶点和一个度数为0的顶点”的原理(上面有证明),因为入度为0的顶点在拓扑排序里要排在有入度的前面,然后利用队列先进先出的特点,先把入度为0的顶点排前,一轮一轮地加入新的入度为0的顶点(它的所有的父顶点把到它的边删了),然后就排好序了。
为什么if(topologicalOrder.size() < n) { cout<<"这个图有环"<<endl; return ; } ?
因为当有环时,必然有顶点因为入度不为0而不能进队列,导致得到的拓扑排序里的顶点数小于图的顶点数。

5、字典序最小的拓扑排序:

把队列改成优先队列就能实现了。

#include<iostream>
#include<list>
#include<vector>
#include<queue>using namespace std;class Graph
{int n;            //顶点数list<int> *adj;  //邻接表
public:Graph(int _n) { n = _n; adj = new list<int>[_n];}~Graph(){ delete [] adj; }void addEdge(int v, int w){ adj[v].push_back(w); }void topologicalSort();
};
void Graph::topologicalSort()
{vector<int> indegree(n,0);for(int i = 0; i < n; i++){list<int>::iterator it;for(it = adj[i].begin(); it != adj[i].end(); it++){indegree[*it]++;    //邻居的入度+1 }}priority_queue<int, vector<int>,greater<int>> q;         //优先队列从小到大for(int i = 0; i < n; i++){if(indegree[i] == 0){q.push(i); }} vector<int> topologicalOrder; while(!q.empty()){int u = q.top();q.pop();topologicalOrder.push_back(u);list<int>::iterator it;for(it = adj[u].begin(); it != adj[u].end(); it++){indegree[*it]--;if(indegree[*it] == 0){q.push(*it);}}}if(topologicalOrder.size() != n){cout<<"这个图有环"<<endl;return ; }for(int i = 0; i < topologicalOrder.size(); i++){cout<<topologicalOrder[i]<<" "; }cout<<endl;
}
int main()
{ Graph g(6); g.addEdge(4, 2); g.addEdge(4, 0); g.addEdge(5, 0); g.addEdge(5, 1); g.addEdge(2, 3); g.addEdge(3, 1); cout << "这个图的拓扑排序是:\n"; g.topologicalSort(); return 0;
}

输入换个图:

不用优先队列:

用优先队列:

拓扑排序----Kahn算法和字典序最小的拓扑排序相关推荐

  1. 拓扑排序-Kahn算法

    题目描述 众所周知, TT 是一位重度爱猫人士,他有一只神奇的魔法猫. 有一天,TT 在 B 站上观看猫猫的比赛.一共有 N 只猫猫,编号依次为1,2,3,-,N进行比赛.比赛结束后,Up 主会为所有 ...

  2. 中石油训练赛 - Swapping Places(字典序最小的拓扑排序)

    题目链接:点击查看 题目大意:给出 s 个字符串表示种类,再给出 m 个朋友关系,表示两个种类的动物是朋友,现在给出一个长度为 n 的种类排列,规定相邻两个是朋友的种类的动物可以交换位置,问如何操作, ...

  3. (数据结构)有向图的拓扑排序 Kahn算法

    拓扑排序是对有向无圈图的顶点的一种排序,使得如果存在一条从vi到vj的路径,那么在排序中,vi必须出现在vj的前面. 首先,我们需要准备一个vector<int> link[maxn],l ...

  4. 拓扑排序【Kahn算法(bfs)和dfs求拓扑序列及判环】

    拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,该排序满足这样的条件--对于图中的任意两个结点u和v,若存在一条有 ...

  5. 拓扑排序(Kahn算法和基于DFS求解法)

    拓扑排序是对有向无环图(DAG)进行排序,从而找到一个序列.该序列满足对于任意一对不同的顶点u,v∈V,若G中存在一条从u->v的边,则在此序列中u在v前面. 拓扑排序也可以用来判断一个有向图是 ...

  6. 拓扑排序——Kahn算法

    Kahn算法 #include <iostream> #include<vector> #include<list> using namespace std;// ...

  7. shell sort 最后一列排序_算法实现系列(1)—— 排序算法

    1.冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法.它重复地遍历过要排序的数列,每次比较两个元素,如果它们的顺序不符合预期,就把它们的位置交换过来.遍历数列的工作是重复地进行直到没有 ...

  8. 推荐常用的排序学习算法——BPR(贝叶斯个性化排序)

    文章目录 1. 排序学习 1.1 优势 1.2 排序学习在推荐领域的作用 1.3 排序学习设计思路 1.3.1 单点法(Pointwise) 1.3.2 配对法(Pairwise) 1.3.3 列表法 ...

  9. 时间排序python_算法导论 第八章 线性时间排序(python)

    比较排序:各元素的次序依赖于它们之间的比较{插入排序O(n**2) 归并排序O(nlgn) 堆排序O(nlgn)快速排序O(n**2)平均O(nlgn)} 本章主要介绍几个线性时间排序:(运算排序非比 ...

最新文章

  1. CSS + DIV 让页脚始终底部
  2. RestSharp .net 轻量级rest客户端
  3. AJPFX关于StringBuffer类的总结
  4. UI组件之 ProgressBar及其子类(一)ProgressBar进度条的使用
  5. Flink DDL的java代碼中的DeserializationSchemaFactory與TableSourceFactory報錯解決方案記錄彙總
  6. (转)shiro权限框架详解05-shiro授权
  7. 腾讯宣布捐赠1亿元驰援河南;苹果回应iPhone 安全隐患;贝索斯完成10分钟太空之旅|极客头条...
  8. 一封写给2009年自己的信
  9. Java-集合练习题
  10. nagios 飞信通知
  11. 如何提高阿里云商标注册的成功率?(经验分享)
  12. 宋智孝那个机器人_陈柏霖机器人竟然冷落宋智孝
  13. 从生活角度学习c++
  14. 【Other】推荐点好听的钢琴曲
  15. 玻色量子CEO文凯受邀出席首经贸金融学院系列讲座
  16. oracle asm密码是什么,ORACLE 12C ASM 新特性:共享密码文件
  17. C++实现单链表的基本操作
  18. 云服务器云虚拟主机区别,带你了解云服务器和云虚拟主机有什么区别?
  19. 友坚Android210更新---支持7寸电阻屏和电容屏
  20. citespace 版本5.6.R5无法打开, 版本为5.6.R2可以打开

热门文章

  1. python兼职程序员工资-Python 程序员的工资能有多高?
  2. python 干什么工作具有明显优势-Python 的优势在哪里?
  3. php和python-php与python谁更适合web开发?为什么?
  4. python自学书-Python电子书免费分享
  5. python创意实用案例-精心整理!9个 Python 实用案例分享
  6. python自动化办公都能做什么-盘点使用Python进行自动化办公所需要的知识点
  7. python是什么 自学-怎么自学python,大概要多久?
  8. c语言写贪吃蛇什么水平_细致的C语言写贪吃蛇教程+详细思路-适合新手附源码...
  9. LeetCode 583 两个字符串的删除操作
  10. Windows平台下NS2网络仿真环境的搭建