二叉树的遍历和重建


二叉树的定义

class TreeNode(object):
    def __init__(self,value,left=None,right=None):
        self.val=val
        self.left=left
        self.right=right

递归遍历 和迭代遍历
递归的终止条件!

深度优先遍历

前序遍历 根左右

144. 二叉树的前序遍历

递归

def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        res=[]
        def preorder(root):
            if root is None: return
            res.append(root.val)
            preorder(root.left)
            preorder(root.right)
        preorder(root)
        return res

迭代

因为顺序为根左右,所以需要借助栈,栈是先入后出的,所以,先读取cur.val,然后往里放他的子节点,先放right再放left

def preorderTraversal(self, root):
        # 根结点为空则返回空列表
        if root is None:return []
        stack=[root]
        res=[]
        while stack:
            curnode=stack.pop()
            res.append(curnode.val)
            if curnode.right:
                stack.append(curnode.right)
            if curnode.left:
                stack.append(curnode.left)
        return res

中序遍历 左根右

94. 二叉树的中序遍历

递归

def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        res=[]
        def inorder(root):
            if root is None:return 
            inorder(root.left)
            res.append(root.val)       
            inorder(root.right)
        inorder(root)
        return res

迭代

因为要先读最左边的,所以要一直向左压栈,压到没有后,栈弹出,读取,然后cur=cur.right

def inorderTraversal(self, root):
        if not root:
            return []
        stack = []  # 不能提前将root结点加入stack中
        result = []
        cur = root
        while cur or stack:
            # 先迭代访问最底层的左子树结点
            if cur:     
                stack.append(cur)
                cur = cur.left		
            # 到达最左结点后处理栈顶结点    
            else:		
                cur = stack.pop()
                result.append(cur.val)
                # 取栈顶元素右结点
                cur = cur.right	
        return result

后序遍历 左右根

145. 二叉树的后序遍历

递归

def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        res=[]
        def postorder(root):
            if root is None:return
            postorder(root.left)
            postorder(root.right)
            res.append(root.val)
        postorder(root)
        return res

迭代

方法一:把前序遍历的顺序调整为根右左,然后翻转列表

def postorderTraversal(self, root):
        if not root:
            return []
        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            # 中结点先处理
            result.append(node.val)
            # 左孩子先入栈
            if node.left:
                stack.append(node.left)
            # 右孩子后入栈
            if node.right:
                stack.append(node.right)
        # 将最终的数组翻转
        return result[::-1]

方法二

class Solution(object):
    def postorderTraversal(self, root):
        if not root:
            return []
        stack = []
        result = []
        cur=root
        pre=root
        while cur:
            while cur.left:
                #print('append',cur.val)
                node = stack.append(cur)
                cur=cur.left
            #print('cur',cur.val)
            while cur and (cur.right is None or cur.right ==pre):
                #当前结点非空且右孩子已经被访问过了
                #print('res',cur.val)
                result.append(cur.val)
                #print('res2',result)
                pre=cur
                if not stack :
                    #print('yes') 
                    return result
                cur=stack.pop()
            stack.append(cur)
            #print('a',cur.val)
            cur=cur.right
        #print('result',result)
        return result

广度优先遍历(层次遍历)

102. 二叉树的层序遍历
迭代用队列

递归

# 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 levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        res = []
        def helper(root, depth):
            if not root: return []
            if len(res) == depth: res.append([]) # start the current depth
            res[depth].append(root.val) # fulfil the current depth
            if  root.left: helper(root.left, depth + 1) # process child nodes for the next depth
            if  root.right: helper(root.right, depth + 1)
        helper(root, 0)
        return res

迭代

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        results = []
        if not root:
            return results
        
        from collections import deque
        que = deque([root])
        
        while que:
            size = len(que)
            result = []
            for _ in range(size):
                cur = que.popleft()
                result.append(cur.val)
                if cur.left:
                    que.append(cur.left)
                if cur.right:
                    que.append(cur.right)
            results.append(result)
        return results

二叉树的重建

根据前序和中序遍历重建二叉树

剑指 Offer 07. 重建二叉树

  1. 根据前序序列的第一个元素建立根结点;
  2. 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
  3. 在前序序列中确定左右子树的前序序列(根据中序中分割的左右子树的长度)
  4. 由左子树的前序序列和中序序列建立左子树;
  5. 由右子树的前序序列和中序序列建立右子树。
    用递归实现
    细节:用哈希表存储步骤2中中序序列个元素值与下标的关系,避免频繁查找浪费的时间
class Solution(object):
    def buildTree(self, preorder, inorder):
        self.index={element:i for i,element in enumerate(inorder)}
        def build(preorder, inorder,id_in):
            #1、递归结束条件
            if not preorder: return None
                #2、从前序找根节点
            val=preorder[0]
            root=TreeNode(val)
                #3、找中序根节点位置
            idx=self.index[val]-id_in
                #4、分割中序
            in_left=inorder[0:idx]
            in_right=inorder[idx+1:]
                #5、分割前序
            pre_left=preorder[1:1+len(in_left)]
            pre_right=preorder[1+len(in_left):]
            root.left=build(pre_left,in_left,id_in)
            root.right=build(pre_right,in_right,id_in+idx+1)
            return root
        return build(preorder, inorder,0)

根据中序加后序遍历重建二叉树

构造该二叉树的过程如下:

  1. 根据后序序列的最后一个元素建立根结点;
  2. 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
  3. 在后序序列中确定左右子树的后序序列;
  4. 由左子树的后序序列和中序序列建立左子树;
  5. 由右子树的后序序列和中序序列建立右子树。
class Solution(object):
    def buildTree(self, inorder, postorder):
        self.index = {element: i for i, element in enumerate(inorder)}
        def build(inorder, postorder,id_in):
            #1、递归结束条件 特殊情况讨论: 树为空. (递归终止条件)
            if not postorder:return None
            #2、从后序找当前根 后序遍历的最后一个就是当前的中间节点.
            val=postorder[-1]
            root=TreeNode(val)
            #3、找中序的根 找切割点. 
            #print(val,inorder)
            idx=self.index[val]-id_in
            #4、切割  切割inorder数组. 得到inorder数组的左,右半边
            in_left=inorder[:idx]
            in_right=inorder[idx+1:]
            #5、切割 切割postorder数组. 得到postorder数组的左,右半边.
            #⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的. 
            po_left=postorder[:len(in_left)]
            po_right=postorder[len(in_left):len(postorder)-1]
            #6、递归重建
            root.left=build(in_left,po_left,id_in)
            root.right=build(in_right,po_right,id_in+idx+1)
            return root 
        return build(inorder, postorder,0)

前序加后序不能重建二叉树

前序和后序在本质上都是将父节点与子结点进行分离,但并没有指明左子树和右子树的能力,因此得到这两个序列只能明确父子关系,而不能确定一个二叉树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值