前序遍历(根、左、右)
-
递归方式实现
算法:
1.如果结点为空,返回空
2.否则:打印当前结点的值->递归遍历结点的左子树->递归遍历结点的右子树
def PreOrder(node):
if node == None:
return None
else:
print(node.value)
PreOrder(node.left)
PreOrder(node.right)
-
非递归方式实现(借助栈)
算法:
1.申请空栈
2.当栈或结点都不为空时循环:
2.1 当结点不为空时:打印当前节点的值,入栈,继续遍历当前结点的左子树
2.2 当栈不为空时:弹出栈顶结点,遍历栈顶节点的右子树
def PreOrder(root):
stack = []
node = root
while node and stack:
while node:
print(node.value)
stack.append(node)
node = node.left
if stack:
node = stack.pop()
node = node.right
中序遍历(左、根、右)
-
递归方式
算法:
1.如果结点为空,返回空
2.否则:递归遍历左子树->打印当前结点的值->递归遍历右子树
def InOrder(node):
if node == None:
return None
else:
InOrder(node.left)
print(node.value)
InOrder(node.right)
-
非递归方式(借助栈)
算法:
1.申请空栈
2.当结点或栈不为空时进行遍历
2.1当结点不为空时:入栈,继续遍历左子树
2.2如果栈不为空:弹出栈顶结点,打印当前结点的值,遍历该结点的右子树。
def InOrder(root):
stack = []
node = root
while node and stack:
while node:
stack.append(node)
node = node.value
if stack:
node = stack.pop()
print(node.value)
node = node.right
后序遍历(左右根)
-
递归方式
算法:
1.如果结点为空,返回空;
2.否则:递归后序遍历左子树->递归后序遍历右子树->打印当前结点的值
def PostOrder(node):
if node == None:
return None
else:
PostOrder(node.left)
PostOrder(node.right)
print(node.value)
-
非递归方式(借助栈和标记位)
算法:
1.申请空栈
2.当结点或栈不为空时循环:
2.1当结点不为空时:将结点的标记位置为1,与结点一起入栈。继续遍历左子树
2.2如果栈不为空,且栈顶结点的标记位为1:将标记位置为2,遍历结点的右子树
2.3如果栈不为空,且栈顶结点的标记位为2:弹出该结点,打印该结点的值。
def PostOrder(root):
stack = []
node = root
while node or stack:
while node:
stack.append([node,1])
ndoe = node.left
if stack and stack[-1][1] == 1:
stack[-1][1] == 2
node = stack[-1][0].right
if stack and stack[-1][1] == 2:
print(stack.pop()[0].vlaue)
总结:
1.用递归方式进行遍历时:
(1)结点为空时递归遍历结束的条件
(2)前序、中序、后序三种不同遍历方式的区别就是遍历左右子树和打印值得顺序。
2.非递归方式进行遍历:
(1)都需要借助栈来保存遍历的结点。
(2)前序和中序的区别是打印结点的值时机不同。前序是在遍历到当前结点的时候就打印,中序是当前结点的左子树遍历完以后打印。
(3)后序遍历使用标记位的作用是:后序遍历需要在某结点的左右子树都遍历完成以后,才能进行访问操作。标记位为1时,代表左子树遍历完成,可以遍历右子树。标记位为2时,代表左右子树都遍历完成,可以进行访问操作。
3.至于递归实现和非递归递归实现,哪种实现更有优势,可以参考知乎上的这个回答: