如何使用不可变数据类型实现 DFS
我正在尝试找出一种 Scala 风格的图形遍历方式,最好使用 val 和不可变数据类型。
给出下图,
val graph = Map(0 -> Set(1),
1 -> Set(2),
2 -> Set(0, 3, 4),
3 -> Set(),
4 -> Set(3))
我希望输出是从给定节点开始的深度优先遍历。例如从 1 开始,应该产生例如 1 2 3 0 4
。
如果没有可变集合或变量,我似乎无法找到一种很好的方法来做到这一点。任何帮助将不胜感激。
I'm trying to figure out a neat way of traversing a graph Scala-style, preferably with vals and immutable data types.
Given the following graph,
val graph = Map(0 -> Set(1),
1 -> Set(2),
2 -> Set(0, 3, 4),
3 -> Set(),
4 -> Set(3))
I'd like the output to be the depth first traversal starting in a given node. Starting in 1 for instance, should yield for instance 1 2 3 0 4
.
I can't seem to figure out a nice way of doing this without mutable collections or vars. Any help would be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
尾递归解决方案:
Tail Recursive solution:
这是递归解决方案(希望我正确理解您的要求):
另请注意,此函数不是尾递归。
Here is recursive solution (hope I understood your requirements correctly):
Also please note, that this function is NOT tail recursive.
我猜这是一个变体:
更新:这是一个扩展版本。在这里,我将左侧的地图元素折叠起来,从一个空列表和数字 1 的元组开始。对于每个元素,我检查图表的大小并相应地创建一个新元组。结果列表以相反的顺序出现。
This is one variant I guess:
Updated: This is an expanded version. Here I fold left over the elements of the map starting out with a tuple of an empty list and number 1. For each element I check the size of the graph and create a new tuple accordingly. The resulting list come out in reverse order.
不知道 6 年后您是否仍在寻找答案,但它就是:)
它还返回图的拓扑排序和周期性:-
Don't know if you are still looking for an answer after 6 years, but here it is :)
It also returns a topological ordering and cyclicality of the graph:-
看来这个问题比我原来想象的更复杂。我写了另一个递归解决方案。它仍然不是尾递归。我也努力让它成为单行,但在这种情况下可读性会受到很大影响,所以我决定这次声明几个
val
:在我之前的回答中,我试图找到来自有向图中的给定节点。但按照要求却是错误的。这个答案尝试遵循有向边,但如果不能,那么它只需要一些未访问的节点并从那里继续。
Seems that this question is more involving than I originally thought. I wrote another recursive solution. It's still not tail recursive. I also tried hard to make it one-liner, but in this case readability will suffer a lot, so I decided to declare several
val
s this time:In my previous answer I tried to find all paths from the given node in directed graph. But it was wrong according to the requirements. This answer tries to follow directed edges, but if it can't, then it just takes some unvisited node and continues from there.
Tenshi,
我还没有完全理解你的解决方案,但如果我没有记错的话,它的时间复杂度至少是 O(|V|^2),因为下面的行复杂度是 O(|V|):
即,将一个元素附加到列表的右侧。
此外,代码不是尾递归的,如果递归深度受到您所使用的环境的限制,这可能会成为问题。
以下代码解决了有向图上的一些与 DFS 相关的图问题。这不是最优雅的代码,但如果我没有记错的话,它是:
代码:
Tenshi,
I haven't fully understood your solution , but if I am not mistaken it's time complexity is at least O(|V|^2) since the following line complexity is O(|V|):
Namely, appending an element to the right of a list.
Further more, the code is not tail recursive, which might be a problem if for example the recursion depth is limited by the environment you are using.
The following code solves a few DFS related graph problems on directed graphs. It is not the most elegant code, but if I am not mistaken it is:
The code:
Marimuthu Madasamy 的答案确实有效。
这是它的通用版本:
注意:您必须确保
T
的实例正确实现 equals 和 hashcode。 使用具有原始值的 case 类是一种简单的方法到达那里。Marimuthu Madasamy's answer is indeed working.
Here is the generic version of it:
Note: You have to make sure the instances of
T
are correctly implementing equals and hashcode. Using case classes with primitive values is an easy way to get there.我想修改 Marimuthu Madasamy 的答案,因为代码使用
Set
表示堆栈,这是无序数据结构,使用List
表示访问,这需要线性时间来调用contains
方法,整个时间复杂度为 O(E * V),效率不高(E 是边数,V 是顶点数)。我宁愿使用List
作为堆栈,使用Set
来访问(将其命名为discovered
),另外使用List
对于按顺序访问的节点的结果值。I want to revise Marimuthu Madasamy's answer because the code uses
Set
for stack which is unordered data structure andList
for visited which takes linear time for callingcontains
method so that the entire time complexity is O(E * V) which is not efficient(E is # of edges and V is # of vertices). I would rather useList
for stack,Set
for visited(named it asdiscovered
), and additionally useList
for result value which is ordered visited nodes.