Python 拓扑排序
本篇文章将介绍拓扑排序算法在 Python 中的实现。
Python 中的拓扑排序算法
拓扑排序算法对有向无环图 (DAG) 进行排序。 有向无环图 (DAG) 是一种具有从一个节点到另一个节点的有向边但没有环的图。
拓扑排序是一种接受 DAG 作为输入并返回数组的算法,其中每个节点都出现在它指向的节点之前。
它不能应用于 DAG 以外的任何图,因为在拓扑排序中,排序完全取决于节点之间边的方向,并且如果图内有循环,则可以有多种排列。
因此,我们可以说有向无环图节点的拓扑排序是按顺序排列节点的操作,如果边 (i,j) 存在,则 i 在列表中排在 j 之前。
拓扑排序本质上提供了执行任务的顺序,并帮助我们确定图是否有环。
每个图可能支持不止一种拓扑排序。 图中节点的入度决定了它。
此外,网络的拓扑排序从入度为 0 的节点开始,即没有传入边的节点。
让我们看一个例子,以更好地理解拓扑排序中发生的事情。
Input DAG:
First Iteration: []
Second Iteration: [B]
Third Iteration: [B, E]
Fourth Iteration: [B, E, A]
Fifth Iteration: [B, E, A, F]
Final Output: [B, E, A, F, C, D]
在上面的例子中,我们迭代地从我们的图中删除没有输入边的节点并将其放入我们的数组中。 我们重复这一过程,直到图中只剩下一个节点。
最后,我们将这个最终节点附加到数组的末尾。
在 Python 中实现拓扑排序算法
我们可以实现上面讨论的相同逻辑,以在 Python 中创建拓扑排序程序。 下面给出了在我们的代码中实现该算法的步骤。
- 识别没有传入边的节点。
- 从图中删除此节点及其对应的边。
- 更新相邻节点的入度。
- 重复步骤 1 到 3,直到图形为空。
从这 4 个步骤可以清楚地看出,我们必须为拓扑排序创建一个图。 这可以通过多种方式完成,但最方便的方法是创建一个图类,其中包含用于将节点和边插入到我们的图中的方法。
以下代码片段显示了一个带有构造函数和向我们的图形添加更多边的方法的图形类。
from collections import defaultdict
class Graph:
def __init__(self, directed=False):
self.graph = defaultdict(list)
self.directed = directed
def addEdge(self, frm, to):
self.graph[frm].append(to)
if self.directed is False:
self.graph[to].append(frm)
else:
self.graph[to] = self.graph[to]
现在,我们有一个名为 graph 的类可以初始化有向或无向图,还有一个方法 addEdge() 可以用来向我们的图添加更多的边。
我们现在需要的只是一种实现拓扑排序算法的机制。 我们需要创建一个访问节点的函数,检查是否没有传入边,如果没有任何传入边,则删除该节点。
此类函数显示在以下代码片段中。
def visitNode(self, s, visited, sortlist):
visited[s] = True
for i in self.graph[s]:
if not visited[i]:
self.visitNode(i, visited, sortlist)
sortlist.insert(0, s)
上面的函数取当前节点s的索引; 一个布尔列表 visited 包含有关节点是否已被访问的信息,以及我们将用于存储从图中删除的节点的排序列表。
我们需要创建另一个辅助函数,它会为图中的所有节点增量调用此 visitNode()
并在最后打印排序列表的值。 以下代码片段显示了用 Python 实现的类似功能。
def topologicalSort(self):
visited = {i: False for i in self.graph}
sortlist = []
for v in self.graph:
if not visited[v]:
self.visitNode(v, visited, sortlist)
print(sortlist)
现在,我们对图形类的实现已经完成。 我们现在需要创建一个图形并调用 topologicalSort() 函数来对我们的列表进行排序。
此过程已在以下代码中实现。
if __name__ == '__main__':
graph = Graph(directed=True)
graph.addEdge(1, 6)
graph.addEdge(1, 3)
graph.addEdge(2, 1)
graph.addEdge(2, 5)
graph.addEdge(3, 4)
graph.addEdge(5, 1)
graph.addEdge(5, 6)
graph.addEdge(5, 6)
graph.addEdge(6, 3)
graph.addEdge(6, 4)
print("Topological Sort Algorithm:")
graph.topologicalSort()
输出:
Topological Sort Algorithm:
[2, 5, 1, 6, 3, 4] #[B, E, A, F, C, D] in terms of previous example
我们在此代码中创建的图表对应于上面给出的图表中的图表。 这里,索引 1 到 6 指的是节点 A 到 F。
正如我们所见,最终排序的列表是 [B, E, A, F, C, D],这与我们在代码中的输出相同。
现在,让我们看看上面的代码组合在一个代码块中。
from collections import defaultdict
class Graph:
def __init__(self, directed=False):
self.graph = defaultdict(list)
self.directed = directed
def addEdge(self, frm, to):
self.graph[frm].append(to)
if self.directed is False:
self.graph[to].append(frm)
else:
self.graph[to] = self.graph[to]
def visitNode(self, s, visited, sortlist):
visited[s] = True
for i in self.graph[s]:
if not visited[i]:
self.visitNode(i, visited, sortlist)
sortlist.insert(0, s)
def topologicalSort(self):
visited = {i: False for i in self.graph}
sortlist = []
for v in self.graph:
if not visited[v]:
self.visitNode(v, visited, sortlist)
print(sortlist)
if __name__ == '__main__':
graph = Graph(directed=True)
graph.addEdge(1, 6)
graph.addEdge(1, 3)
graph.addEdge(2, 1)
graph.addEdge(2, 5)
graph.addEdge(3, 4)
graph.addEdge(5, 1)
graph.addEdge(5, 6)
graph.addEdge(5, 6)
graph.addEdge(6, 3)
graph.addEdge(6, 4)
print("Topological Sort Algorithm:")
graph.topologicalSort()
输出:
Topological Sort Algorithm:
[2, 5, 1, 6, 3, 4] #[B, E, A, F, C, D] in terms of previous example
我们的教程到此结束。 现在,您可以在完全了解其工作原理的情况下实现拓扑排序。
相关文章
在 Python 中对日期和时间进行排序
发布时间:2023/06/17 浏览次数:82 分类:Python
-
在本文中,我们讨论了如何在 Python 中使用 sorted() 方法对日期和时间进行排序。 为了理解这个概念,我们举了一些例子以及 Python 中的 datetime 模块。
Python 双样本 T 检验
发布时间:2023/06/17 浏览次数:94 分类:Python
-
Python 为我们提供的一个功能是我们可以执行双样本 t 检验。 通过本文,我们将讨论什么是双样本 t 检验以及如何使用 Python 执行它。
在 Python 中生成随机 4 位数字
发布时间:2023/06/17 浏览次数:174 分类:Python
-
本文讨论如何使用 randint() 和 randrange() 方法生成四位数。 此外,我们还讨论了另一种获得随机四位数的方法。
Python中ReLU函数的导数
发布时间:2023/06/16 浏览次数:152 分类:Python
-
就深度学习而言,ReLU 函数在机器学习中使用最频繁。 本文讨论如何在Python中实现ReLU推导以及实现ReLU功能。
计算 Python 中一个句子的平均字长
发布时间:2023/06/16 浏览次数:62 分类:Python
-
本篇文章将介绍用 Python 计算句子中的平均字长。在 Python 中使用 split()、sum() 和 len() 计算句子中的平均字长
Python 中的可选链
发布时间:2023/06/16 浏览次数:80 分类:Python
-
本文描述了我们在适应 Python 中的可选链接时可以遵循的方法。 适应以下方法之一将使在 Python 而不是 JavaScript 中使用可选链接变得容易。
Python中另一个函数调用的模拟补丁一个函数
发布时间:2023/06/16 浏览次数:122 分类:Python
-
本篇文章介绍模拟对象及其重要性,并使用 patch() 作为装饰器、上下文管理器和手动启动/停止来演示如何模拟补丁由另一个函数调用的一个函数。
Python 四舍五入到最接近的十位
发布时间:2023/06/16 浏览次数:124 分类:Python
-
本篇文章将讨论使用 Python 的 ceil() 函数将数字四舍五入到最接近的十。Python 整数到最接近的十 Python 具有三个内置函数 round()、floor() 和 ceil(),可用于对数字进行舍入。
Python 中的模拟函数
发布时间:2023/06/16 浏览次数:127 分类:Python
-
Mock 是为与 unittest 一起使用而创建的,它基于操作到断言模式而不是大多数模拟框架中使用的记录到重播。 对于以前版本的 Python,有一个 unittest.mock 的反向移植。