转载:https://www.cnblogs.com/bjwu/p/9284534.html
一、中序遍历
左中右
递归实现:
class Solution:
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)
循环实现:
对于树的遍历,循环操作基本上要用到栈(stack)这个结构
对于中序遍历的循环实现,每次将当前结点(curr)的左子结点push到栈中,直到当前结点(curr)为None。这时,pop出栈顶的第一个元素,设其为当前结点,并输出该结点的value值,且开始遍历该结点的右子树。
对于上图的一个二叉树,其循环遍历过程如下表:
可见,规律为:当前结点curr不为None时,每一次循环将当前结点curr入栈;当前结点curr为None时,则出栈一个结点,且打印出栈结点的value值。整个循环在stack和curr皆为None的时候结束
class Solution:
def inorderTraversal(self, root):
stack = []
sol = []
curr = root
while stack or curr:
if curr:
stack.append(curr)
curr = curr.left
else:
curr = stack.pop()
sol.append(curr.val)
curr = curr.right
return sol
二 、前序遍历和后续遍历
1. 递归实现
class Solution:
def preorderTraversal(self, root): ##前序遍历
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
return [root.val] + self.inorderTraversal(root.left) + self.inorderTraversal(root.right)
def postorderTraversal(self, root): ##后序遍历
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
return self.inorderTraversal(root.left) + self.inorderTraversal(root.right) + [root.val]
2.循环实现:
先看前序遍历。我们仍然使用栈stack,由于前序遍历的顺序是中左右,所以我们每次先打印当前结点curr,并将右子结点push到栈中,然后将左子结点设为当前结点。入栈和出栈条件(当前结点curr不为None时,每一次循环将当前结点curr入栈;当前结点curr为None时,则出栈一个结点)以及循环结束条件(整个循环在stack和curr皆为None的时候结束)与中序遍历一模一样。
再看后序遍历。由于后序遍历的顺序是左右中,我们把它反过来,则遍历顺序变成中右左,是不是跟前序遍历只有左右结点的差异了呢?然而左右的差异仅仅就是.left和.right的差异,在代码上只有机械的差别。
class Solution:
def preorderTraversal(self, root): ## 前序遍历
stack = []
sol = []
curr = root
while stack or curr:
if curr:
sol.append(curr.val)
stack.append(curr.right)
curr = curr.left
else:
curr = stack.pop()
return sol
def postorderTraversal(self, root): ## 后序遍历
stack = []
sol = []
curr = root
while stack or curr:
if curr:
sol.append(curr.val)
stack.append(curr.left)
curr = curr.right
else:
curr = stack.pop()
return sol[::-1]
三、层序遍历
层序遍历也可以叫做宽度优先遍历:先访问树的第一层结点,再访问树的第二层结点…然后一直访问到最下面一层结点。在同一层结点中,以从左到右的顺序依次访问。
1.递归实现
递归函数需要有一个参数level,该参数表示当前结点的层数。遍历的结果返回到一个二维列表sol=[[]]中,sol中的每一个子列表保存了对应index层的从左到右的所有结点value值。
class Solution:
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
def helper(node, level):
if not node:
return
else:
sol[level-1].append(node.val)
if len(sol) == level: # 遍历到新层时,只有最左边的结点使得等式成立
sol.append([])
helper(node.left, level+1)
helper(node.right, level+1)
sol = [[]]
helper(root, 1)
return sol[:-1]
PS:
Q:如果仍然按层遍历,但是每层从右往左遍历怎么办呢?
A:将上面的代码left和right互换即可
Q:如果仍然按层遍历,但是我要第一层从左往右,第二层从右往左,第三从左往右…这种zigzag遍历方式如何实现?
A:将sol[level-1].append(node.val)进行一个层数奇偶的判断,一个用append(),一个用insert(0,)
if level%2==1:
sol[level-1].append(node.val)
else:
sol[level-1].insert(0, node.val) # insert插入指定位置
2.循环实现
这里的循环实现不能用栈了,得用队列queue。因为每一层都需要从左往右打印,而每打印一个结点都会在队列中依次添加其左右两个子结点,每一层的顺序都是一样的,故必须采用先进先出的数据结构。
class Solution:
def levelOrder(self, root):
if not root:
return []
sol = []
curr = root
queue = [curr]
while queue:
curr = queue.pop(0)
sol.append(curr.val)
if curr.left:
queue.append(curr.left)
if curr.right:
queue.append(curr.right)
return sol