- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
摘自 here我们得到了一个最小的迭代 dfs 例程,我称它为最小是因为你很难进一步简化代码:
def iterative_dfs(graph, start, path=[]):
q = [start]
while q:
v = q.pop(0)
if v not in path:
path = path + [v]
q = graph[v] + q
return path
graph = {
'a': ['b', 'c'],
'b': ['d'],
'c': ['d'],
'd': ['e'],
'e': []
}
print(iterative_dfs(graph, 'a'))
这是我的问题,您如何将这个例程转换为拓扑排序方法,其中例程也变得“最小”?我看过 video而且这个想法非常聪明,所以我想知道是否可以将相同的技巧应用到上面的代码中,这样 topological_sort 的最终结果也变得“最小”。
不要求拓扑排序的版本不是对上述例程的微小修改,我已经看过其中的一些。问题不是“我如何在 python 中实现拓扑排序”,而是找到上述代码的最小可能调整集以成为 topological_sort
。
补充意见
作者在原文中说:
A while ago, I read a graph implementation by Guido van Rossen that was deceptively simple. Now, I insist on a pure python minimal system with the least complexity. The idea is to be able to explore the algorithm. Later, you can refine and optimize the code but you will probably want to do this in a compiled language.
这个问题的目标不是优化 iterative_dfs
而是想出一个从它派生的最小版本的拓扑排序(只是为了了解更多关于图论算法的信息)。事实上,我想一个更普遍的问题可能是给定一组最小算法,{iterative_dfs
, recursive_dfs
, iterative_bfs
, recursive_dfs
},它们的拓扑排序推导是什么?虽然这会使问题变得更冗长/复杂,但从 iterative_dfs 中找出 topological_sort 就足够了。
最佳答案
将 DFS 的迭代实现转变为拓扑排序并不容易,因为需要进行的更改使用递归实现更自然。但是你仍然可以这样做,它只需要你实现自己的堆栈。
首先,这是您的代码稍微改进的版本(它更高效,也不是更复杂):
def iterative_dfs_improved(graph, start):
seen = set() # efficient set to look up nodes in
path = [] # there was no good reason for this to be an argument in your code
q = [start]
while q:
v = q.pop() # no reason not to pop from the end, where it's fast
if v not in seen:
seen.add(v)
path.append(v)
q.extend(graph[v]) # this will add the nodes in a slightly different order
# if you want the same order, use reversed(graph[v])
return path
以下是我将如何修改该代码以进行拓扑排序:
def iterative_topological_sort(graph, start):
seen = set()
stack = [] # path variable is gone, stack and order are new
order = [] # order will be in reverse order at first
q = [start]
while q:
v = q.pop()
if v not in seen:
seen.add(v) # no need to append to path any more
q.extend(graph[v])
while stack and v not in graph[stack[-1]]: # new stuff here!
order.append(stack.pop())
stack.append(v)
return stack + order[::-1] # new return value!
我用“这里的新东西”评论的部分是在您向上移动时计算顺序的部分。它检查找到的新节点是否是前一个节点(位于堆栈顶部)的子节点。如果不是,它会弹出堆栈顶部并将值添加到 order
.在我们进行 DFS 时,order
从最后一个值开始,将采用反向拓扑顺序。我们在函数的末尾反转它,并将它与堆栈上的剩余值连接起来(方便地,它们已经按正确的顺序排列了)。
因为这段代码需要检查v not in graph[stack[-1]]
很多时候,如果 graph
中的值会更有效字典是集合,而不是列表。图通常不关心其边的保存顺序,因此进行此类更改不会导致大多数其他算法出现问题,尽管生成或更新图的代码可能需要修复。如果您打算扩展您的图形代码以支持加权图形,您可能最终将列表更改为字典,从节点映射到权重,这对于此代码同样有效(字典查找是 O(1)
只是像集合查找)。或者,我们可以自己构建我们需要的集合,如果 graph
不能直接修改。
作为引用,这里是 DFS 的递归版本,并对其进行了修改以进行拓扑排序。所需的修改确实非常小:
def recursive_dfs(graph, node):
result = []
seen = set()
def recursive_helper(node):
for neighbor in graph[node]:
if neighbor not in seen:
result.append(neighbor) # this line will be replaced below
seen.add(neighbor)
recursive_helper(neighbor)
recursive_helper(node)
return result
def recursive_topological_sort(graph, node):
result = []
seen = set()
def recursive_helper(node):
for neighbor in graph[node]:
if neighbor not in seen:
seen.add(neighbor)
recursive_helper(neighbor)
result.insert(0, node) # this line replaces the result.append line
recursive_helper(node)
return result
就是这样!一条线被删除,类似的一条被添加到不同的位置。如果您关心性能,您可能应该这样做 result.append
在第二个辅助函数中,执行 return result[::-1]
在顶层 recursive_topological_sort
功能。但是使用 insert(0, ...)
是一个更小的变化。
另外值得注意的是,如果您想要整个图的拓扑顺序,则不需要指定起始节点。实际上,可能没有一个节点可以让您遍历整个图形,因此您可能需要进行多次遍历才能到达所有内容。在迭代拓扑排序中实现这一点的一个简单方法是初始化 q
至list(graph)
(所有图键的列表)而不是只有一个起始节点的列表。对于递归版本,将调用替换为 recursive_helper(node)
如果它还没有在 seen
中,则使用循环调用图中每个节点上的辅助函数.
关于python - python中拓扑排序的看似简单的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47192626/
是否可以可视化kubernetes拓扑并看到它在添加/删除/链接对象时实时更新? 我在https://www.youtube.com/watch?v=38SNQPhsGBk上观看了一个视频,其中服务/
我在搜索 Rack 拓扑时发现了这个问题...可能是hadoop认证问题: 您的群集在三个不同的 Rack 中都有从属节点,并且您编写了一个 Rack 拓扑脚本,以将每台计算机分别识别为位于 Rack
我拿了sticky force layout示例并尝试添加额外链接并使用 enter() 更新布局,但随后所有链接都消失了,FireBug 也没有显示任何错误。 这些行不应该添加链接吗? graph.
我需要编写一个订单管理器,将客户(股票、外汇等)订单发送到适当的交易所。客户想要发送订单,但对 FIX 或其他专有协议(protocol)一无所知,只知道发送订单的内部(规范化)格式。我有应用程序(服
我正在尝试使用 Eclipse 在远程主机上提交 Storm 拓扑。 这是我的代码: Config conf = new Config(); conf.setDebug(false); conf.se
这是一个名为 mininet 的流行网络模拟器的拓扑文件 我创建了一个 MultiSwitch() 类,我想将其传递给我的 Topology 类以用作默认开关 有没有办法做到这一点?我对Python不
我从 cat/proc/cpuinfo 中了解到,我正在使用 Intel(R) Core(TM) i5 CPU M 560 @ 2.67GHz。但是我想知道确切的层次结构,比如有多少个套接字,每个套接
我正在学习storm。我对我们可以在 Apache Storm 上一次运行的拓扑数量有疑问。我已经在 Storm 集群上提交了两个拓扑,但一次只运行了一个拓扑。我需要杀死或停用已经存在的拓扑拓扑以运行
我正在尝试理解 topology of queues并交换 MT 在 RabbitMQ 中创建的。 我不能得到这两个陈述: we generate an exchange for each queue
我正在寻找一种方法来测试 Kafka Streams 应用程序。这样我就可以定义输入事件,测试套件会向我显示输出。 如果没有真正的 Kafka 设置,这可能吗? 最佳答案 更新 Kafka 1.1.0
我正在使用 Java 类将拓扑提交到 Storm 集群,我还计划使用 Java 类来终止拓扑。但根据 Storm documentation ,以下命令用于终止拓扑并且没有 Java 方法(这是有正当
Storm jar storm-starter-topologies-0.10.0-beta1.jar storm-starter-master.jar生产拓扑本地 我遇到了错误: Running:
我正在编写一个 dockerized Java Spring 应用程序,该应用程序使用 Apache Storm v1.1.2、Kafka v0.11.0.1、Zookeeper 3.4.6、Eure
我在 jts 拓扑库中有一些多边形。如果我想在 javafx Pane 上绘图,我会这样做: Polygon poly=new Polygon();//javafx //g is geometry
我需要在 Java GUI 应用程序中动态绘制(星形)拓扑。通过星形拓扑,我的意思是这样的: (来源:thebryantadvantage.com) 不需要太花哨,但我不想做得太丑陋和粗糙。我所说的动
我想自动化设置 Mininet 的过程虚拟机,通过 SSH 连接到 VM,在 VM 中启动 Mininet,并初始化拓扑。我需要 session 保持打开状态,以便我可以使用创建的网络向 Minine
我正在尝试重新平衡使用 KafkaSpout 的 Storm 拓扑。我的代码是: TopologyBuilder builder = new TopologyBuilder(); Pr
标题几乎说明了一切,我有一些 Storm 拓扑,我想测量它们的延迟,即来自 Kafka 的消息与最终相关执行的最后一点之间的时间量 bolt 。如果我可以深入研究结果以查看每个 bolt 之间的延迟,
假设我想让一些转换“A”可配置。此转换使用状态存储管理某些状态,并且还需要重新分区,这意味着仅在配置后才会进行重新分区。现在,如果我按照以下方式(或任何其他组合)运行应用程序 3 次(也可能是滚动升级
我目前正在尝试实现与 R 语言集成的 Storm 拓扑。 作为起点,我采用了以下项目 ( https://github.com/allenday/R-Storm ),它通过扩展 ShellBolt 类
我是一名优秀的程序员,十分优秀!