数据结构(Python实现)------二叉树

数据结构(Python实现)------二叉树

树的遍历

基本概念

树的遍历 - 介绍

前序遍历
中序遍历
后序遍历
递归和迭代

Python实现

二叉树的前序遍历

在这里插入图片描述

栈实现
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        res = []
        
        stack = [root]

        while  stack:
            cur = stack.pop()
            res.append(cur.val)
            if cur.right:
                stack.append(cur.right)
            if cur.left:
                stack.append(cur.left)

        return res

递归实现
class Solution(object):
    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)

二叉树的中序遍历

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []

        res = []
        stack = []
        temp = root
        while temp or stack:
            if temp != None:
                stack.append(temp)
                temp = temp.left

            else:
                temp = stack.pop()
                res.append(temp.val)
                temp = temp.right

        return res

二叉树的后续遍历

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        stack= [root]
        res = []
        while stack:
            cur = stack.pop()

            if cur.left:
                stack.append(cur.left)
            if cur.right:
                stack.append(cur.right)
            res.insert(0, cur.val)

        return res

二叉树的层序遍历

在这里插入图片描述

运用递归解决树的问题

基本概念

“自顶向下” 的解决方案

“自顶向下” 意味着在每个递归层级,我们将首先访问节点来计算一些值,并在递归调用函数时将这些值传递到子节点。 所以 “自顶向下” 的解决方案可以被认为是一种前序遍历。 具体来说,递归函数 top_down(root, params) 的原理是这样的:

  1. return specific value for null node
  2. update the answer if needed // anwer <-- params
  3. left_ans = top_down(root.left, left_params) // left_params <-- root.val, params
  4. right_ans = top_down(root.right, right_params) // right_params <-- root.val, params
  5. return the answer if needed // answer <-- left_ans, right_ans

例如,思考这样一个问题:给定一个二叉树,请寻找它的最大深度。

我们知道根节点的深度是1。 对于每个节点,如果我们知道某节点的深度,那我们将知道它子节点的深度。 因此,在调用递归函数的时候,将节点的深度传递为一个参数,那么所有的节点都知道它们自身的深度。 而对于叶节点,我们可以通过更新深度从而获取最终答案。 这里是递归函数 maximum_depth(root, depth) 的伪代码:

“自底向上” 的解决方案

总结

Python实现

二叉树的最大深度

在这里插入图片描述

递归方法

递归是最容易想到的一种方法,判断如果传入的节点为空,则返回0,否则返回左节点和右节点的最大值+1。代码如下:
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root == None:
            return 0
        return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1

层次遍历方法:

可以采用层次遍历,每遍历一层,深度值+1。代码如下:
class Solution2(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root == None:
            return  0
        presub = [root]
        p = root
        sub = []
        d = 1
        while p!=None or len(presub)!=0:
            while len(presub) != 0:
                p = presub.pop(0)
                if p.left!= None:
                    sub.append(p.left)

                if p.right!=None:
                    sub.append(p.right)
            presub  = sub
            if len(sub) != 0:
                d+=1
            else:
                return d
            sub = []

        return d

对称二叉树

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        def isSameTree(p,q):
            if not p and not q:
                return True
            if p and q and p.val == q.val:
                l = isSameTree(p.left,q.right)
                r = isSameTree(p.right,q.left)
                return l and r#and 操作,需要l与r皆为true时,才返回真,只用最后一次递归边界return值
            else:
                return False

        if not root:
            return True
        else:
            return isSameTree(root.left,root.right)

路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def hasPathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: bool
        """
        if not root:
            return False

        sum -= root.val
        #左右几点都为空,判断是否与sum相等
        if not root.left and not root.right:
            return sum == 0
        return self.hasPathSum(root.left,sum) or self.hasPathSum(root.right,sum)

从中序与后序遍历序列构造二叉树

在这里插入图片描述

# Definition for a binary tree node.
class TreeNode(object):
     def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None

class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if not postorder:
            return None
        root = TreeNode(postorder[-1])

        root_index = inorder.index(postorder[-1])

        left_inorder = inorder[:root_index]
        right_inorder = inorder[root_index+1:]
        l_left = len(left_inorder)
        
        left_postorder = postorder[:l_left]
        right_postorder = postorder[l_left:-1]
        
        root.left = self.buildTree(left_inorder,left_postorder)
        root.right = self.buildTree(right_inorder,right_postorder)
        
        return root

从前序与中序遍历序列构造二叉树

在这里插入图片描述

# Definition for a binary tree node.
class TreeNode(object):
     def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None

class Solution(object):
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if not preorder:
            return None

        root = TreeNode(preorder[0])
        left_inorder = inorder[:inorder.index(root.val)]
        right_inorder = inorder[inorder.index(root.val)+1:]

        l_left = len(left_inorder)
        left_preorder = preorder[1:l_left+1]
        right_preorder = preorder[l_left+1:]

        root.left = self.buildTree(left_preorder,left_inorder)
        root.right = self.buildTree(right_preorder,right_inorder)
        
        return root

填充每个节点的下一个右侧节点指针

在这里插入图片描述

输入:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}

输出:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1}

解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
在这里插入图片描述

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""


class Solution(object):
    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        #先排除掉不需要处理的情况
        if not root or (not root.left and not root.right):
            return root


        #某一个节点的左孩子的next一定是指向这个节点的右孩子
        root.left.next = root.right


        #当某一个节点的next不为空的时候,这个节点的右孩子的next一定是指向该节点next的left
        if root.next:
            root.right.next = root.next.left
        #递归处理下一层
        self.connect(root.left)
        self.connect(root.right)


        return root

填充每个节点的下一个右侧节点指针 II

在这里插入图片描述
在这里插入图片描述
递归,分类讨论:

当一个Node既有左孩子又有右孩子的时候,显然左孩子的next就是右孩子,右孩子的next得在Node的next里往右找,直到某个节点有孩子,这个孩子就是Node.right的next。

当一个Node只有左孩子的时候,左孩子的next得在Node的next里往右找。

当一个Node只有右孩子的时候,右孩子的next得在Node的next里往右找。

所以不妨用一个辅助函数findCousin(node, parent)来找到node.next,其中node是parent的子节点

对于一个需要找Cousin节点的node, 首先看叔叔节点parent.next有没有孩子,

如果有左孩子,那么很好这个左孩子就是结果,

如果没有左孩子但是有右孩子,那么也不错,这个右孩子是结果,

如果parent.next没有孩子,那么糟了,还得继续找更小的叔叔,即parent.next.next……

一直这么找下去,直到找到一个有孩子的叔叔,那么返回这个孩子,或者找完所有的叔叔,它们都没有孩子……

这道题比较关键的地方在于递归部分要先处理右子树再处理左子树,因为根据上面的分析,找一个节点的next需要用它父亲节点的next一路往右找,所以必须先把右边部分搞定,左子树才能利用正确的next关系进行查找。

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""


class Solution(object):
    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        if not root or (not root.left and not root.right):
            return root

        def findCousin(node,parent):
            tmp = parent.next
            while(tmp):
                if tmp.left:
                    node.next = tmp.left
                    break
                elif tmp.right:
                    node.next = tmp.right
                    break
                tmp = tmp.next

        if root.left and root.right:
                root.left.next = root.right
                findCousin(root.right, root)

        elif root.left:
                findCousin(root.left, root)

        elif root.right:
                findCousin(root.right, root)

        # print root.val, root.right.next
        self.connect(root.right)
        self.connect(root.left)

        return root

二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
在这里插入图片描述

说明:

所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。

思想:
递归,如果当前节点就是p或q,说明当前节点就是最近的祖先,

如果当前节点不是p或p,就试着从左右子树里找pq。

如果pq分别在一左一右被找到,那么当前节点还是最近的祖先返回root就好了,

否则,返回它们都在的那一边

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode
        """
        if not root or root == p or root == q:
            return root
        
        else:
            left = self.lowestCommonAncestor(root.left,p,q)
            right = self.lowestCommonAncestor(root.right,p,q)
            
            if left and right:
                return root
            elif left:
                return left
            elif right:
                return right
            
            else:
                return 

二叉树的序列化与反序列化

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Codec:
    def serialize(self, root):
        """Encodes a tree to a single string.

        :type root: TreeNode
        :rtype: str
        """
        if not root:
            return []
        return_list = []
        current_level = [root]
        while len(current_level):
            new_level = []
            for current_node in current_level:
                if current_node:
                    return_list.append(str(current_node.val))
                    new_level.append(current_node.left)
                    new_level.append(current_node.right)

                else:
                    return_list.append(None)

            current_level= new_level
        return return_list

    def deserialize(self, data):
        """Decodes your encoded data to tree.

        :type data: str
        :rtype: TreeNode
        """

        if len(data) == 0:
            return None
        return_node = TreeNode(int(data[0]))
        current_level = [return_node]
        data = data[1:]
        while len(current_level):
            new_level = []
            count = 0
            for current_node in current_level:
                if current_node:
                    count+=1

            if not count:
                break
            new_level_data = data[:count*2]
            data = data[count*2:]
            count = 0
            for current_node in current_level:
                if current_node:
                    if new_level_data[count]:
                        current_node.left = TreeNode(int(new_level_data[count]))
                    count +=1
                    new_level.append(current_node.left)
                    if new_level_data[count]:
                        current_node.right = TreeNode(int(new_level_data[count]))
                    count += 1
                    new_level.append(current_node.right)
                    
            current_level = new_level
        return return_node




        # Your Codec object will be instantiated and called as such:
        # codec = Codec()
        # codec.deserialize(codec.serialize(root))
发布了64 篇原创文章 · 获赞 9 · 访问量 4343

猜你喜欢

转载自blog.csdn.net/Avery123123/article/details/103752214