使用递归和迭代的思想完成二叉树的遍历,在时间复杂度和空间复杂度上都是O(n)和O(n)。Morris提出了一种遍历的方式,使得遍历可以在线性时间、常数空间上完成遍历,即O(n)和O(1),它的核心思想就是利用树中大量的空指针,实现空间的缩减。
具体地,按照思想,先中序遍历:
1. 如果当前结点的左节点为空,输出当前结点,设置当前结点为其右节点
2. 如果当前结点的左节点不为空:寻找当前结点的左子树的最右结点predecessor(也就是中序遍历是的前一个结点)
1) 如果predecessor的右指针为空,将其右指针设置为当前结点,当前结点设置为其左节点
2) 如果predecessor的右指针不为空,将该指针恢复为空,输出当前结点,并将当前结点设置为其右节点
循环1.2
提示:predecessor即当前结点向左走一步,然后一直向右走直到无法走为止
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
result = []
if not root:
return result
while root: # 用root来标记当前结点
if root.left is None:
result.append(root.val)
root = root.right
else:
predecessor = root.left
while predecessor.right and predecessor.right != root:
predecessor = predecessor.right
if predecessor.right is None:
predecessor.right = root
root = root.left
else:
predecessor.right = None
result.append(root.val)
root = root.right
return result
先序遍历: 和中序遍历对比着记忆
1. 如果当前结点的左节点为空,输出当前结点, 设置当前结点为其右节点
2. 如果当前结点的左节点不为空:寻找当前结点的左子树的最右结点predecessor(也就是中序遍历是的前一个结点)
1) 如果predecessor的右指针为空,将其右指针设置为当前结点,输出当前结点, 当前结点设置为其左节点
2) 如果predecessor的右指针不为空,将该指针恢复为空,并将当前结点设置为其右节点
循环1.2
提示:predecessor即当前结点向左走一步,然后一直向右走直到无法走为止
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
result = []
if not root:
return result
while root: # 用root来标记当前结点
if root.left is None:
result.append(root.val)
root = root.right
else:
predecessor = root.left
while predecessor.right and predecessor.right != root:
predecessor = predecessor.right
if predecessor.right is None:
predecessor.right = root
result.append(root.val)
root = root.left
else:
predecessor.right = None
root = root.right
return result
后序遍历: 要新建一个临时结点,也要对比着记
设置一个临时结点root,令其左节点为根节点
1. 如果当前结点的左节点为空,设置当前结点为其右节点
2. 如果当前结点的左节点不为空:寻找当前结点的左子树的最右结点predecessor(也就是中序遍历是的前一个结点)
1) 如果predecessor的右指针为空,将其右指针设置为当前结点,当前结点设置为其左节点
2) 如果predecessor的右指针不为空,将该指针恢复为空,倒序输出从当前结点的左节点到predecessor路径上的所有结点,并将当前结点设置为其右节点
循环1.2
提示:·predecessor即当前结点向左走一步,然后一直向右走直到无法走为止
·从当前结点的左节点到predecessor路径上的所有结点——从当前结点一直向右直到为predecessor
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
result = []
if not root:
return result
r = TreeNode()
r.left = root
root = r
while root: # 用root来标记当前结点
if root.left is None:
root = root.right
else:
predecessor = root.left
while predecessor.right and predecessor.right != root:
predecessor = predecessor.right
if predecessor.right is None:
predecessor.right = root
root = root.left
else:
predecessor.right = None
# 倒序输出,因为使用这种方法的目的是减少空间的使用,所以这里在倒序的时候,不能再使用一个数组完成
# dao = []
# temp = root.left
# while temp != predecessor:
# dao.append(temp.val)
# temp = temp.right
# dao.append(predecessor.val)
# dao = dao[::-1]
# for i in range(len(dao)):
# result.append(dao[i])
temp = root.left
count = 0
while temp: # predecessor一定是最后一个right不然它不可能是predecessor
count += 1
result.append(temp.val)
temp = temp.right
# 完成倒序:
i = len(result) - count
j = len(result) - 1
while i < j:
temp_0 = result[i]
result[i] = result[j]
result[j] = temp_0
i += 1
j -= 1
root = root.right
return result