图综合练习--拓扑排序_拓扑排序
一个场景
在大学里,每当到了期末的时候,你一定会头疼于选课给你带来的困扰。其中一项就是先修课的问题,每次你高高兴兴地选了自己心仪的选修课时,却发现自己不满足先修课的要求,只好默默地退掉。到底怎样安排我们的课才能保证不会有这种麻烦呢?这一次,我们就来讨论一下这个问题。
假设大学里开设了这些课程:高等数学,线性代数,概率论,数据结构,机器学习和计算机视觉。它们存在这样的先修关系:线性代数的先修课为高等数学;概率论的先修课是线性代数;机器学习的先修课为线性代数,概率论和数据结构;最后计算机视觉的先修课是机器学习。
下面我们需要把这些课程和关系做一个抽象化的处理,说白了就是能够让计算机读懂这些关系。这里我们用图来表示这些关系,把每门课程当做图的节点,两门课的先修关系抽象为图的边,并且是带有方向的边,从一个节点
指向另一个节点
表示
是
的先修课。要是我们把这些关系用图表示出来就是下面这样:
这里,我们对上图进行类似“排序”的操作,也就是怎样安排这些课程使得一些课程不会因为先修课的原因而没有被选上,我们把这种操作叫做拓扑排序(topological sorting)。
卡恩算法
下面我们来分析一下这个问题,它跟我们前面提到的减治有什么关系呢?假如我们要在某一个学期修计算机视觉这门课,我们首先要保证修了机器学习这门课,而要达到修机器学习这门课的条件,我们又要修三门前置课,这样问题的规模在逐渐减小,直到这门课没有任何先修条件,我们就可以直接修这门课。
卡恩算法为我们提供了具体的步骤。
- 步骤 1:在图中找到没有被其它节点所指向的节点,即入度(在图论中,入度指的是所有进入该节点的节点个数)为 0 的节点。
- 步骤 2:删除该节点以及对应的边。
- 步骤 3:重复步骤 1 和步骤 2,直到图中没有入度为 0 的节点为止。
最后我们用代码来实现一下:
首先构建节点 Vertex 类:
class Vertex(object):def __init__(self, subject):self.subject = subject # 科目
然后写出寻找入度为 0 的节点的函数:
def find_source(G):source = None # 初始化为 NoneV = G.keys(); E = G.values() # 分别获取节点和边的集合for v in V:for neighbour in E:for vertex in neighbour:if vertex is v:break # 如果 v 指向了其他节点就退出循环else:continue # 否则查看下一条边break # 如果 v 指向了其他节点就退出循环 else: # 正常退出循环source = v break # 找到了入度为 0 的节点后退出最外层循环return source
最后写出我们的主函数,我们用pop
方法从图G
中每次 pop 出入度为 0 的节点,但如果发现没有入度为 0 的节点,就说明这样的拓扑排序不存在,因此我们就提前终止程序。
def topo_main(G):order = [] # 存放排序后的节点while len(G) != 0:s = find_source(G) # 寻找入度为 0 的节点if s is None:return "不存在拓扑排序." # 退出函数order.append(s.subject)G.pop(s) # 删除每次循环中入度为 0 的节点return order
在主程序中,我们先构建一个图G
,然后执行topo_main
函数,最后得到排序后的结果:
>>> print(topo_main(G))
>>> 排序结果为 ["高等数学", "线性代数", "概率论", "数据结构", "机器学习", "计算机视觉"]
其实,除了卡恩算法之外,我们还可以用 DFS 的方法。由于它跟减治的关系不是很大,这里我们就不做讨论了,感兴趣的同学可以去网上搜一搜这方面的内容。
→ 本节全部代码 ←
← 插入排序 | 算法与复杂度zhuanlan.zhihu.com
→ 二分查找与二叉树 | 算法与复杂度zhuanlan.zhihu.com
图综合练习--拓扑排序_拓扑排序相关推荐
- python链表排序_链表排序+末尾各种排序
#工具人排序 def nums_sort(data): if not data: return [] min_data = min(data) max_data = max(data) nums = ...
- java shell排序_八大排序算法——希尔(shell)排序
一.动图演示 二.思路分析希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止. 简单插入 ...
- js数组按中文拼音排序_学习排序算法,结合这个方法太容易理解了
排序是一个经典的问题,它以一定的顺序对一个数组或列表中的元素进行重新排序.而排序算法也是各有千秋,每个都有自身的优点和局限性.虽然这些算法平常根本就不用自己去编写,但作为一个有追求的程序员,还是要了解 ...
- golang 排序_常用排序算法之冒泡排序
周末无事,带娃之余看到娃娃在算数,想到了排序-尝试着把几种常用的排序算法跟大家聊一聊,在分析的后面我会用GoLang.PHP和JS三种语言来实现下. 常见的基于选择的排序算法有冒泡排序.插入排序.选择 ...
- java二分法排序_二分法排序讲解『附视频』
二分法排序讲解『附视频』 时间:2017-06-22 来源:华清远见JAVA学院 算法一直是Java编程学习中的重点和难点,今天华清Java学院小编就和大家分享一下Java中的二分法排序. ① ...
- python经典排序_经典排序 python实现
稳定的排序算法:冒泡排序.插入排序.归并排序和基数排序.不是稳定的排序算法:选择排序.快速排序.希尔排序.堆排序. 冒泡 defbobble(arr): length=len(arr)for i in ...
- python 拓扑排序_拓扑排序(topsort)算法详解
在图论中,由某个集合上的偏序得到全序的策略就是拓补排序算法.拓扑排序常出现在涉及偏序关系的问题中,例如时序的先后.事物的依赖等.针对这些问题拓扑排序通常能有效地给出可行解. 为了便于理解,我们先来看一 ...
- 排序_简单排序_选择排序
选择排序是有三个记录值,其中一个记录值标记着需要比较的数组的第一个值,也是变换后的最小值.其中两个记录值记录需要比较的两个对象,而且记录临时最小值的位置和记录另一个还未比较的数据. public cl ...
- c语言对n个数选择排序_选择排序法 -- C语言
算法原理 直接选择排序的基本思想:n个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果. 初始状态:无序区为 A[1...n],有序区为空. 第 1 趟排序:在无序区 A[1...n] 中 ...
最新文章
- N4 接口是 5G 产业价值的金线
- 单点登录SSO流程图
- Python爬虫学习笔记(三)——正则表达式
- zigbee 端点描述符
- linux gunzip r .tar,Linux命令之文件归档、压缩、解压缩tar,gzip,gunzip,bzip2,bunz -电脑资料...
- Spring4.x集成xfire1.26 问题汇总
- 四种依恋类型_“我值得被爱吗?”| 如何在亲密关系中培养安全型依恋
- linux空间满了有什么问题,Linux 空间满问题分析 [ Keep Coding ]
- strcpy sprintf memcpy 它们之间的区别
- 高通平台开发系列讲解(外设篇)BMI160基本配置
- 考研高等数学张宇30讲笔记——第十二讲 二重积分
- centos/linux 服务器的内存不够了怎么办?centos用虚拟内存扩展内存
- 技嘉主板设置服务器启动不了系统,技嘉主板开启ahci模式不认硬盘 - 卡饭网
- 电脑删除的文件去哪了?删除的数据恢复,居然有3个方法…
- oracle 按每分钟分组,oracle按每个10分钟进行分组展示数据
- java 机机接口定义_【JAVA】接口
- MATLAB下配置C和C++编译器(MinGW)
- 艾宾浩斯记忆曲线——定期、及时复习的重要性
- 【计算机视觉与深度学习】全连接神经网络(一)
- file not found
热门文章
- 如何处理SAP Fiori Launchpad KPI tile点击后出现的错误消息
- SAP web service开发工具SOAMANAGER里ping按钮的实现细节
- 如何使用SAT trace一个正在运行的程序
- 一些SAP UI5的控件无法按照预期渲染的错误分析方法和解决方案
- 一次完整的性能测试过程
- android4.0 菜单,三大主流安卓4.0界面解析 MIUI最实用
- python调用random失败_python怎么调用random
- PyCharm的光标插入与覆盖模式
- nedc和epa续航里程什么意思_NEDC、WLTP和EPA续航里程标准谁最真实?看比亚迪工程师怎么说...
- python 概率分布_python实现beta分布概率密度函数的方法