[14]二叉树的中序遍历和二叉树的锯齿形层次遍历

*内容来自leetcode

1.二叉树的中序遍历

题目描述

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

中序遍历,即依次遍历左子树、根结点和右子树

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

示例 1:

输入:root = [1,null,2,3]
输出:[1,3,2]

思路
如题目所说,可以通过递归和迭代两种方式来完成,其中递归更为简单。

虽然递归也写了好一会才整明白。。。

# 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]:
        #递归版本
        def inorder(root,result):
            if root == None:
                return []
            else:
                left = inorder(root.left,result)
                if left:
                    result = left
                result.append(root.val)
                right = inorder(root.right,result)
                if right:
                    result = right
            return result
        result = []
        return inorder(root,result)

上面这个总感觉很别扭。。。于是简化了一下,简化之后确实用递归完成很简单。。。

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        #递归版本
        def inorder(root):
            if root == None:
                return []
            else:
                result = []

                result = result + inorder(root.left)               
                result.append(root.val)
                result = result + inorder(root.right)
            return result
        return inorder(root)

迭代的难点在于要确保每个节点都被遍历到,所以需要使用栈来保存节点。官方只给出思路,没有pyhton的具体实现,时间复杂度和空间复杂度均为O(n)。

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        #迭代版本
        result = []
        stk = []
        while root != None or stk:
            while root:
                stk.append(root)
                root = root.left
            
            root = stk.pop()
            result.append(root.val)
            root = root.right
        return result

另外官方还提出了Morris中序遍历,来将迭代过程的空间复杂度降低为O(1),具体步骤如下

Morris 遍历算法整体步骤如下(假设当前遍历到的节点为 x):

如果 x无左孩子,先将 x的值加入答案数组,再访问 x的右孩子,即 x=x.right。
如果 x 有左孩子,则找到 x 左子树上最右的节点(即左子树中序遍历的最后一个节点,x 在中序遍历中的前驱节点),我们记为 predecessor。根据 predecessor的右孩子是否为空,进行如下操作。
如果 predecessor 的右孩子为空,则将其右孩子指向 x,然后访问 x 的左孩子,即 x=x.left。
如果 predecessor 的右孩子不为空,则此时其右孩子指向 x,说明我们已经遍历完 x 的左子树,我们将 predecessor的右孩子置空,将 x 的值加入答案数组,然后访问 x的右孩子,即 x=x.right
重复上述操作,直至访问完整棵树。

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        #迭代版本
        answer = []
        while root:
            if root.left:
                predecessor = root.left
                while predecessor.right and predecessor.right != root:
                    predecessor = predecessor.right
                if predecessor.right:
                    predecessor.right = None
                    answer.append(root.val)
                    root = root.right
                else:
                    predecessor.right = root
                    root = root.left
            else:
                answer.append(root.val)
                root = root.right
        return answer

2.二叉树的锯齿形层次遍历

题目要求

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

示例 1:


输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]

思路

其实就是二叉树的层次遍历,只不过有的层的保存顺序需要颠倒一下。可以按照正常的顺序存储后将需要颠倒的颠倒后再输出。

基础的层序遍历不需要考虑层与层之间的区别(指输出为一个一维的列表)。在实际实现过程中,为了区分不同的层,用了两个栈来间隔存储每一层的每一个节点,同时为了实现锯齿形层次遍历,可以通过改变左右节点的存入顺序来实现。

# 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 zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []
        stk1 = [root]
        stk2 = []
        result = []
        while stk1 or stk2:
            res = []
            while stk1:
                root = stk1.pop()
                res.append(root.val)
                if root.left:
                    stk2.append(root.left)
                if root.right:
                    stk2.append(root.right)
            if res:
                result.append(res)
                continue
            while stk2:
                root = stk2.pop()
                res.append(root.val)
                if root.right:
                    stk1.append(root.right)
                if root.left:
                    stk1.append(root.left)
            result.append(res)
        return result

这样的时间复杂度和空间复杂度均为O(n)。

这里使用两个栈的原因如上所说,就是为了对层进行区分。官方使用了一个栈,每个循环的取栈次数为取栈前栈内节点数决定,这样就不会在一个取到新加进来的节点,也可以做到对层进行区分。这种办法应该更普遍一些。。。不过效果类似。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值