美文网首页
二叉查找树

二叉查找树

作者: 慧鑫coming | 来源:发表于2019-02-20 05:39 被阅读0次

    相关概念

    • BST(Binary Search Tree),在树中的任一节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都要大于这个节点的值。

    BST查找操作

    • 先取根节点,如果它等于要查找的数据,那就返回;如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def bstFind(self, tree, val):
            if not tree:
                return None
            while tree:
                if tree.val < val:
                    tree = tree.right
                elif tree.val > val:
                    tree = tree.left
                else:
                    return tree
            return None
    

    BST的插入操作

    • 类似于查找操作,需要从根节点开始,依次比较要插入的数据和节点的大小关系。如果要插入的数据比节点数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再遍历左子树,查找插入位置。
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def bstInsert(self, tree, val):
            if not tree:
                tree = TreeNode(val)
                return
            while tree:
                if tree.val < val:
                    if tree.right is None:
                        tree.right = TreeNode(val)
                        return
                    tree = tree.right
                else:
                    if tree.left is None:
                        tree.left = TreeNode(val)
                        return
                    tree = tree.left
    

    BST删除操作

    • state1,如果要删除的节点没有子节点,只需直接将父节点中指向要删除节点的指针置为null。
    • state2,如果要删除的节点中只有1个子节点,只需更新父节点中指向要删除节点的指针,让它指向要删除节点的子节点。
    • state3,如果要删除的节点有2个子节点,需要找到这个节点的右子树中的最小节点(因为这个节点满足大于被删除节点左子树的所有节点,小于被删除节点右子树中除自身外的所有节点,它可以取代被删除节点的位置),把它替换到要删除的节点上,然后再删除掉这个右子树的最小节点,因为最小节点肯定没有左子树,所以可用state1或state2来进行这个删除操作。
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    class Solution:
        def bstDelete(self, tree, val):
            # 记录待删除节点的父节点
            pp = None
            while p and p.val != val:
                pp = p
                if val > p.val:
                    p = p.right
                else:
                    p = p.left
            # 没有找到要删除的节点
            if p is None:
                return 
    
            # 要删除的节点有2个子节点
            if p.left and p.right:
                min_p = p.right
                min_pp = p
                # 找右子树中最小节点,记录其父节点,待做删除操作
                while min_p.left:
                    min_pp = min_p
                    min_p = min_p.left
                # 这里的赋值是将现在右子树中最小节点的值给要删除的节点,这个值给过来之后,
                # 就相当于删除了p节点了,并不动p节点的左右节点
                p.val = min_p.val
                # 对于state3,此时已经删除了p节点,还需要删除右子树中最小的节点,
                # 此时将变量p作为右子树中最小节点的引用,转换为state1或state2
                p = min_p
                pp = min_pp
    
            # 删除min_p或者删除只有1个子节点的节点
            child = None
            if p.left:
                child = p.left
            elif p.right:
                child = p.right
            else:
                child = None
            # 删除根节点,且根节点只有一个子节点
            if not pp:
                tree = child
            elif pp.left is p:
                pp.left = child
            else:
                pp.right = child
    

    BST的其他特性

    • 中序遍历BST,可以输出有序的数据序列,时间复杂度是O(n),因此,BST也叫二叉排序树。

    BST的两种存储形式

    • 链式存储法:
        每个节点有3个字段,一个存储数据,另外两个是指向左右子节点的指针,只要拎住根节点,就能通过左右子节点的指针,把整棵树都串起来。大部分二叉树代码都是通过这种结构实现的。
    • 顺序存储法:(基于数组)
        如果节点X存储在数组下标为i的位置,那么下标为2*i的位置存储的就是左子节点,下标为2*i+1的位置存储的就是右子节点。反过来,下标为i//2的位置存储的就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般为了方便计算子节点,根节点会存储在下标为1的位置),这样就可以通过下标计算,把整棵树都串起来。

    BST时间复杂度分析

    • 最不理想情况
      左右节点极度不均衡,退化成链表,时间复杂度变为O(n)。
    • 最理想情况
      一棵完全二叉树(或满二叉树)。此时时间复杂度和树的高度成正比O(height),此时,问题转变为如何求一棵包含n个节点的完全二叉树的高度。
      包含n个节点的满二叉树中,第一层包含1个节点,第二程包含2个节点,第三层4个...,第k层包含2^(k-1)个节点。
      对于完全二叉树来说,最后一层节点个数在1个到2^(L-1)个之间(假设最大层数是L)。
    n >= 1+2+4+8+...+2^(L-2)+1
    n <= 1+2+4+8+...+2^(L-2)+2^(L-1)
    

    借助等比数列的求和公式,可算出L的范围是[log2(n+1), log2n+1],完全二叉树的层数小于等于log2n+1,也就是说,完全二叉树的高度小于等于log2n。
    当二叉树极度不平衡的时候,它的查找性能不能满足我们的需求。我们需要构建一种不管怎么删除、插入数据,在任何时候,都能保持任意节点左右子树都比较平衡的平衡二叉查找树,它的高度接近logn,插入、操作、查找操作的时间复杂度也比较稳定,是O(logn)。

    相关文章

      网友评论

          本文标题:二叉查找树

          本文链接:https://www.haomeiwen.com/subject/ansyeqtx.html