题一:144. 二叉树的前序遍历
链接
力扣实战
思路一:递归法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 递归实现前序遍历:确定递归函数的参数和返回值;确定终止条件;确定单层递归的逻辑
res=[]
def func(cur):
if cur==None: # cur == None:
return
res.append(cur.val)
func(cur.left)
func(cur.right)
return res
func(root)
return res
# 反思1:
思路二 迭代法
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 因为递归很多都是用栈实现,所以也可以使用栈来模拟递归的效果:先中节点入栈,然后弹出,获取val(中),右进栈,左进栈,第一段
# 迭代结束;然后第二段迭代末尾出栈,获取val,右左儿子进栈
res=[]
stack = []
if not root:
return res
stack.append(root)
while stack: #stack is not none
tem = stack.pop()
res.append(tem.val)
if tem.right: #中左右,但是为了用数组来模拟,所以先放入右,这样pop时弹出的就是左
stack.append(tem.right)
if tem.left:
stack.append(tem.left)
return res
题二:145. 二叉树的后序遍历
链接
力扣实战
思路一:递归法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 后续遍历指的是中在最后,也就是左右中
res = []
def func(cur):
if cur ==None: #退出条件 要放在左之前,先判断这个节点是不是空,如果左行在前且左为空,则其无左右儿子
return
func(cur.left) # 左
func(cur.right) # 右
res.append(cur.val) #中
return res
func(root)
return res
# 反思1:
思路二 迭代法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 后续遍历直接用栈来模拟有点恶心,可以考虑用前序间接获得,先中右左,然后再reverse
res = []
if not root:
return res
stack = [root]
while stack: #前序遍历中访问节点(遍历节点)和处理节点(将元素放进result数组中)可以同步处理,但是中序就无法做到同步
tem = stack.pop()
res.append(tem.val)
if tem.left: #若想获得中右左的结果,需要左中右的方式进栈
stack.append(tem.left)
if tem.right:
stack.append(tem.right)
j =len(res)-1
i = 0
while i<j:
res[i],res[j]=res[j],res[i]
i+=1
j-=1
return res
思路三 不采用前序翻转法,而是直接用栈模拟,相当于hard
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 后续遍历直接用栈来模拟有点恶心,可以考虑用前序间接获得,先中右左,然后再reverse
# 也可以直接怼:思路为一直往左怼,边怼边进栈,直到为空时,处理栈顶的右儿子,右儿子处理完
# 之后,获取值,然后回溯,然后回去之后需要跳过处理左右儿子的逻辑,因为左右儿子处理过了
# 所以需要指针来记录已经处理过的右儿子
res = []
cur = root
if not root:
return res
stack = []
pre = None #记录已经输出过得节点,当遍历点的右是pre时,说明右儿子已经遍历过了,此时把右
while stack or cur: #儿子看成空即可
while cur: #一直往左怼,为空时,说明左右中的左已经考虑完,接下来处理右中
stack.append(cur)
cur = cur.left
cur = stack.pop() #取出点,若其右为空或者pre直接输出到res,记录pre,回溯;若右不为
if not cur.right: #空,说明右儿子还没遍历过,需要放入栈,且cur指向他对他操作,从看
res.append(cur.val) #他的左儿子开始
pre = cur #值已经返回,用pre记录下这个儿子已经访问过
cur = None #回溯操作,但是已经入栈的都不要看左儿子,所以跳过while流程即可
elif cur.right == pre:
res.append(cur.val)
pre = cur
cur = None
else: # 若右儿子不为空,在从右儿子返回时,则老头也直接返回,但需要保存老头的右儿子,
stack.append(cur) #这一行不能少,不然当过根的节点都输出不了,也就是右儿子不是空
cur = cur.right # 也没访问过,说明右边的树没探索过,需要加入从左儿子开始探索
return res
题三:94. 二叉树的中序遍历
链接
力扣实战
思路一:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 中序遍历,左中右
res = list()
def func(cur):
if not cur :
return
func(cur.left)
res.append(cur.val)
func(cur.right)
return res
func(root)
return res
# 反思1:
思路二
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 中序遍历,左中右
res = list()
cur = root #cur表示指针,指向当前遍历的元素,而不是操作的元素,操作的元素只有在左儿子
if not cur: #为空时,才会把指针指向操做元素,也就是从指针处获取值,存入res
return res
stack = []
while stack or cur: #只要有一个不是空,就说明有元素还没处理,或者还没有遍历
if cur: #当前不是为空,是为了把这个节点入栈,一直找到空节点时,此时不需要入栈了
stack.append(cur) #指针不用盯着树了,而是盯着栈,弹出栈头,因为栈头元素的左
cur=cur.left #儿子已经判断为空,此时按照左中右的顺序应该操作中,所以虽然当前
else: #节点是一个左儿子(叶节点),但是他却是因为,他自身的昨儿子为空,才会操作到自身
cur = stack.pop() #指针指向栈尾,表示对中进行操作,也就是对中获取值
res.append(cur.val)
cur = cur.right # 左儿子为空,中已经取值,所以指向右儿子,如果再为空,指向的栈尾
return res #相当于在回溯!!如果右儿子不为空,则又是一次入栈的流程