问题描述
我能够理解preorder穿越不使用递归,但我有一个很难与序遍历。我只是似乎没有得到它,也许,因为我还没有明白递归的内部工作。
这是我到目前为止已经试过:
高清traverseInorder(节点):
后进先出法=礼佛()
lifo.push(节点)
而真正的:
如果节点是没有:
打破
如果node.left不是无:
lifo.push(node.left)
节点= node.left
继续
preV =节点
而真正的:
如果节点是没有:
打破
打印node.value
preV =节点
节点= lifo.pop()
节点= preV
如果node.right不是无:
lifo.push(node.right)
节点= node.right
其他:
打破
内层while循环只是感觉不对。此外,一些元件的越来越打印两次;可能是我可以通过,如果该节点之前已经检查印刷解决这个问题,但是这需要另一个变量,这又感觉不对。我在哪里去了?
我没试过后序遍历,但是我想这是类似的,我也会面临同样的概念堵塞在那里。
感谢您的时间!
PS:定义的礼佛
和节点
:
类节点:
高清__init __(个体经营,价值,左=无吧=无):
self.value =价值
self.left =左
self.right =右
类礼佛:
高清__init __(个体经营):
self.lifo =()
高清推送(个体经营,数据):
self.lifo =(数据,self.lifo)
高清流行(个体经营):
如果len(self.lifo)== 0:
返回None
RET,self.lifo = self.lifo
返回RET
开始用递归算法(伪code):
移动(节点):
!如果节点=无做:
遍历(node.left)
打印node.value
遍历(node.right)
ENDIF
这是尾递归的一个明确的情况下,这样你就可以轻松地把它变成一个while循环。
移动(节点):
!而节点=无做:
遍历(node.left)
打印node.value
节点= node.right
ENDWHILE
你留下了一个递归调用。什么是递归调用确实是推栈新的上下文中运行从一开始code,然后检索的背景和继续做它在做什么。因此,您可以创建一个栈存放和循环决定,在每次迭代中,无论我们是在一个第一次运行的局面(非空节点)或回归的局面(空节点,非空栈),并运行相应的code:
移动(节点):
堆栈= []
而!空(栈)|| !节点=无做:
如果节点=无做://这是一个正常的呼叫,递归
推(栈,节点)
节点= node.left
否则//我们现在返回:弹出并打印当前节点
节点=流行(栈)
打印node.value
节点= node.right
ENDIF
ENDWHILE
硬的东西要把握的是回归的一部分:你要确定,你的循环,你正在运行的code是否在输入功能的情况或从返回呼叫的情况,你将有一个的if / else
链尽可能多的情况下,你有非终端递归在code。
在此特定情况下,我们使用节点,以保持有关情况的信息。另一种方式是,以存储在堆栈本身(就像一个计算机做为递归)。有了该技术,在code是不太理想的,但更容易执行
移动(节点):
// 条目:
如果节点== NULL做回报
遍历(node.left)
//后左跨越:
打印node.value
遍历(node.right)
遍历(结点):
堆栈= [节点,'入门']
!而空(栈)这样做:
[节点,状态] = POP(栈)
开关状态:
案入门:
如果节点==没有做的事:休息; // 返回
推(堆栈,[节点,后 - 左 - 穿越'])//存储返回地址
推(堆栈,[node.left,'入门'])//递归调用
打破;
案后,左穿越:
打印node.value;
//尾部调用:没有返回地址
推(堆栈,[node.right,'入门'])//递归调用
结束
ENDWHILE
I am able to understand preorder traversal without using recursion, but I'm having a hard time with inorder traversal. I just don't seem to get it, perhaps, because I haven't understood the inner working of recursion.
This is what I've tried so far:
def traverseInorder(node):
lifo = Lifo()
lifo.push(node)
while True:
if node is None:
break
if node.left is not None:
lifo.push(node.left)
node = node.left
continue
prev = node
while True:
if node is None:
break
print node.value
prev = node
node = lifo.pop()
node = prev
if node.right is not None:
lifo.push(node.right)
node = node.right
else:
break
The inner while-loop just doesn't feel right. Also, some of the elements are getting printed twice; may be I can solve this by checking if that node has been printed before, but that requires another variable, which, again, doesn't feel right. Where am I going wrong?
I haven't tried postorder traversal, but I guess it's similar and I will face the same conceptual blockage there, too.
Thanks for your time!
P.S.: Definitions of Lifo
and Node
:
class Node:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
class Lifo:
def __init__(self):
self.lifo = ()
def push(self, data):
self.lifo = (data, self.lifo)
def pop(self):
if len(self.lifo) == 0:
return None
ret, self.lifo = self.lifo
return ret
Start with the recursive algorithm (pseudocode) :
traverse(node):
if node != None do:
traverse(node.left)
print node.value
traverse(node.right)
endif
This is a clear case of tail recursion, so you can easily turn it into a while-loop.
traverse(node):
while node != None do:
traverse(node.left)
print node.value
node = node.right
endwhile
You're left with a recursive call. What the recursive call does is push a new context on the stack, run the code from the beginning, then retrieve the context and keep doing what it was doing. So, you create a stack for storage, and a loop that determines, on every iteration, whether we're in a "first run" situation (non-null node) or a "returning" situation (null node, non-empty stack) and runs the appropriate code:
traverse(node):
stack = []
while !empty(stack) || node != None do:
if node != None do: // this is a normal call, recurse
push(stack,node)
node = node.left
else // we are now returning: pop and print the current node
node = pop(stack)
print node.value
node = node.right
endif
endwhile
The hard thing to grasp is the "return" part: you have to determine, in your loop, whether the code you're running is in the "entering the function" situation or in the "returning from a call" situation, and you will have an if/else
chain with as many cases as you have non-terminal recursions in your code.
In this specific situation, we're using the node to keep information about the situation. Another way would be to store that in the stack itself (just like a computer does for recursion). With that technique, the code is less optimal, but easier to follow
traverse(node):
// entry:
if node == NULL do return
traverse(node.left)
// after-left-traversal:
print node.value
traverse(node.right)
traverse(node):
stack = [node,'entry']
while !empty(stack) do:
[node,state] = pop(stack)
switch state:
case 'entry':
if node == None do: break; // return
push(stack,[node,'after-left-traversal']) // store return address
push(stack,[node.left,'entry']) // recursive call
break;
case 'after-left-traversal':
print node.value;
// tail call : no return address
push(stack,[node.right,'entry']) // recursive call
end
endwhile
这篇关于帮助我了解序遍历,而无需使用递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!