力扣Day14(3.2)| 第六章 二叉树 (144. 二叉树的前序遍历 145. 二叉树的后序遍历 101. 对称二叉树)

本文详细介绍了如何使用递归和迭代方法实现二叉树的前序、后序和中序遍历。对于前序遍历,递归法直观简洁,迭代法利用栈模拟递归过程。后序遍历的迭代法较为复杂,可以借助前序遍历并翻转结果,或者直接用栈模拟。中序遍历的递归和迭代实现则相对直观。
摘要由CSDN通过智能技术生成

题一: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  #相当于在回溯!!如果右儿子不为空,则又是一次入栈的流程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值