title: 拓扑排序及实现
date: 2019-09-03 19:45:00
tags: python,数据结构
categories: 计算机理论
拓扑排序
算法原理
拓扑排序是有向图(网)中的内容,只在有向网(图)的范畴中讨论。
先看一个实际生活中可能遇到的问题:选课问题,例如上大一的时候你肯定要先学C语言,然后才能学数据结构。这个时候C语言和数据结构就构成了一个排列问题,谁在前谁在后。用图中的顶点表示一个活动,边表示活动之间的顺序关系。这样的图就称为AOV网(顶点活动网)
下图就是一个典型的AOV网实例。
任何无回路的AOV网N都可以求解出拓扑序列,方法很简单:
- 从N中选出一个入度为0的顶点作为序列的下一个顶点
- 从N网中删除所选顶点的出边
- 重复执行上面两步,直到已经选出了图N的所有顶点
拓扑排序算法有两个难点:
- 如何寻找入度为0的顶点
- 真的需要拷贝整张图,然后进行删除
一个显然的办法是不断遍历图,寻找入度为0的顶点。但时间代价会很高。顶点间的制约关系决定了顶点的入度。入度是一个整数,用一个整数表就能记录所以顶点的入度了。因此,我的方法是用一张入度表记录了每个顶点的入度,初始时,表中的各顶点的入度对应为图中顶点的入度,在随后的计算中,一旦选中一个顶点,就将该顶点的出边入度减一。
在实际的算法实现中还用了一个0度栈来记录已经入度为0但还未处理的顶点。
算法比较简单。
可以慢慢调试
算法实现
def topological_sort(self):
indegree = {} # 入度表
zerov = [] # 利用0度栈记录已知的入度为0的但还未处理的顶点
m = 0 # 输出顶点计数
topo = [] # 拓扑排序结果
# 生成入度表和0度栈
for vetx in self._graph:
indegree[vetx] = self.get_inEdge(vetx).__len__()
if indegree[vetx] == 0:
zerov.append(vetx)
pass
while zerov.__len__() != 0:
Vi = zerov.pop()
topo.append(Vi)
m += 1
for Vj in self.get_outEdge(Vi).keys(): # 对顶点Vi的每个邻接点入度减1,如果Vj的入度变为0,则将Vj入栈,表示Vj就是下一个需要处理的顶点
indegree[Vj] -= 1
if indegree[Vj] == 0:
zerov.append(Vj)
if m < self.get_vertexNum(): # 该有向图有回路
return False
return topo