二叉树的迭代遍历
1.栈与递归
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
2.二叉树的前序遍历(迭代法)
二叉树的前序遍历的进栈动画:
总的来说分为三步:
1. 首先根节点入栈,然后出栈
2. 然后加入根节点的右孩子
3. 然后加入根节点的左孩子,然后出栈
为什么要先进右孩子,后进左孩子呢?因为只有这样出栈的时候才是根节点->左孩子->右孩子,符合前序遍历的要求。
代码如下:
def preordertraversal(root):
result = [] # 存放结果,存放节点数值
stack = [] # 栈,存放节点指针
# 如果树为空树,则直接返回空
if root == None:
return result
# 如果树不为空
# 先对栈进行初始化,将root压入栈中
stack.append(root)
# 判断当栈不为空时
while stack:
# 栈顶元素出栈
node = stack.pop()
result.append(node.value)
# 栈顶元素的右孩子进栈
if node.right != None:
stack.append(node.right)
# 栈顶元素的左孩子进栈
if node.left != None:
stack.append(node.left)
return result
3.二叉树的中序遍历(迭代法)
总体步骤如下:
- 先使用一个指针一直向左遍历,然后将遍历到的节点存入栈中。
- 将栈顶元素出栈,将栈顶元素的数值存入result中,然后将指针指向该栈顶元素的右孩子。
- 重复第2步,直到指针指向空或者栈为空。
代码如下:
def inordertraversal(root):
result = [] # 存放结果,存放节点数值
stack = [] # 栈,存放节点指针
# 如果树为空树,则直接返回空
if root == None:
return result
# 如果树不为空
# 先对指针进行初始化
cur = root
# 判断当栈不为空时
while cur != None or stack:
# 一直向左遍历
if cur != None:
stack.append(cur)
cur = cur.left # 获取左孩子
else:
# 栈顶元素出栈
cur = stack.pop()
result.append(cur.value)
# 获取栈顶元素的右孩子
cur = cur.right
return result
4.二叉树的后序遍历(迭代法)
直接使用栈来迭代二叉树的后序遍历实现难度很大,我们可以换一个思路;因为前序遍历很容易写并且容易理解,所以我们从前序遍历入手,调整一下前序遍历的入栈顺序,先让前序遍历根节点入栈,然后左孩子入栈,然后右孩子入栈,这样获得的结果就是中右左,然后我们再将result逆序即可。
代码如下:
def postordertraversal(root):
result = [] # 存放结果,存放节点数值
stack = [] # 栈,存放节点指针
# 如果树为空树,则直接返回空
if root == None:
return result
# 如果树不为空
# 先对栈进行初始化,将root压入栈中
stack.append(root)
# 判断当栈不为空时
while stack:
# 栈顶元素出栈
node = stack.pop()
result.append(node.value)
# 栈顶元素的左孩子进栈
if node.left != None:
stack.append(node.left)
# 栈顶元素的右孩子进栈
if node.right != None:
stack.append(node.right)
return result[::-1]
5.总结
算法
-
先序遍历注意点:
(1)初始化stack,将root传入stack中
(2)然后stack栈顶元素出栈,把结果放入result中,然后右孩子入栈,再左孩子入栈即可。
(3)循环判断条件为stack不为空 -
中序遍历注意点:
(1)初始化一个指针,用来遍历当前的节点
(2)首先需要让指针一直向左直到指向节点没有左孩子。
(3)然后弹出栈顶元素,将栈顶元素的数值传入result
(4)然后让指针指向栈顶元素的右孩子
(5)循环判断条件为指针不为空或者栈不为空 -
后序遍历注意点:
(1)将前序遍历的入栈顺序改为中右左
(2)然后再逆序result数组就变味了左右中,即为后序遍历的顺序。