自从我在大学学习数据结构和算法以来已经有一段时间了,所以我最近感到惊讶的是,递归可能不是的方式(tm)做树遍历。出于某种原因,迭代,基于队列的遍历并不是我曾经使用过的技术。
迭代与递归遍历的优点是什么?在什么情况下我可以使用一个而不是另一个?
答案 0 :(得分:19)
如果您正在进行广度优先搜索,则自然实现是将节点推入队列,而不是使用递归。
如果您正在进行深度优先搜索,则递归是编码遍历的最自然方式。但是,除非您的编译器将尾递归优化为迭代,否则递归实现将比迭代算法慢,并且会在足够深的树上发生堆栈溢出而死亡。
一些快速Python来说明差异:
#A tree is a tuple of an int and a tree.
t = (1, (2,(4, (6), (7, (9)) )), (3, (5, (8)) ))
def bfs(t):
to_visit = [t]
while len(to_visit) > 0:
c = to_visit[0]
if type(c) is int:
print c
else:
print c[0]
to_visit.append(c[1])
if len(c) > 2: to_visit.append(c[2])
to_visit = to_visit[1:]
def dfs(t):
if type(t) is int:
print t
return
print t[0]
dfs(t[1])
if len(t) > 2: dfs(t[2])
bfs(t)
dfs(t)
答案 1 :(得分:8)
如果你有一个固定数量的内存专用于堆栈,就像你经常做的那样(这在许多Java JVM配置中尤其是一个问题),如果你有一个深树(或者如果递归深度是在任何其他场景中都很高);它会导致堆栈溢出。推动节点访问队列(用于类似BFS的遍历)或堆栈(用于类似DFS的遍历)的迭代方法在几个方面具有更好的内存属性,因此如果这很重要,请使用迭代方法。
递归的优点是表达的简单/优雅,而不是表现。记住,这是为给定算法,问题规模和机器架构选择适当方法的关键。
答案 2 :(得分:1)
这取决于您是要进行深度优先还是广度优先遍历。 Depth-first是最容易通过递归实现的。使用广度优先,您需要保留一个节点队列以便将来扩展。
答案 3 :(得分:1)
实际上你应该使用队列进行广度优先搜索和堆栈以进行深度优先搜索, 并从while循环运行您的算法。 如果做得很简单,进行递归函数调用可以显着拖动程序 遍历时的操作,可能会导致堆栈溢出,但是现在你会这样做 需要努力去看一个。
只是在旁边有一个哈希来跟踪已经访问过的节点,如果不是的话 一棵树,但连接得很好。
答案 4 :(得分:-2)
使用递归,因为你实际上可能会出现堆栈溢出错误,毕竟这是stackoverflow.com。