动态存储和查找(跳表 VS 散列表 VS 二叉查找树)

跳表和二叉查找树是基于有序序列的查找,排序是为了更快的查找。

散列表是基于 hash 映射的存储和查找。

二叉查找树

二叉查找树要求:在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。 

二叉查找树的中序遍历就是排序的结果。

二叉查找树的时间复杂度不稳定,最好O(log n),对应于完全二叉树;最差O(n2),对应于二叉树退化为链表。

为了解决时间复杂度高的问题,维护一个平衡二叉查找树,常见的是AVL树,红黑树。

二叉查找树的源码:

class BinarySearchTree:
    class Node:
        Value = None
        Left = None
        Right = None
        def __init__(self, value):
            self.Value = value

    __root = None

    def insert(self, value):
        if (self.__root == None):
            self.__root = BinarySearchTree.Node(value)
            return
        p = self.__root
        while(p):
            if (value < p.Value):
                if (p.Left == None):
                    p.Left = BinarySearchTree.Node(value)
                    return
                p = p.Left
            else:
                if (p.Right == None):
                    p.Right = BinarySearchTree.Node(value)
                    return
                p = p.Right
    def search(self, value):
        if (self.__root == None):
            return None
        p = self.__root
        while(p):
            if (p.Value == value):
                return p
            elif (value < p.Value):
                if (p.Left):
                    p = p.Left
                else:
                    return None
            else:
                if (p.Right):
                    p = p.Right
                else:
                    return None
        return None
    def delete(self, value):
        if (self.__root == None):
            return
        pp = None
        p = self.__root
        while(p and p.Value != value):
            pp = p
            if (value < p.Value):
                p = p.Left
            else:
                p = p.Right
        # 没找到,返回
        if (p == None):
            return

        # 第一种情况,左右子树都非空
        if (p.Left and p.Right):
            #取右子树最小(左)值,替换
            minp = p.Right
            minpp = p
            while(minp.Left):
                minpp = minp
                minp = minp.Left
            #替换
            p.Value = minp.Value
            #问题转换成,删除这个右子树最左节点
            p = minp
            pp = minpp
            #(因为最左节点不能再有左子树了,所以问题转换成第二/第三种情况,不会再转换成第一种情况)
        
        #第二种情况,只一边有子树
        #第三种情况,左右子树均空
        if (p == pp.Left):
            pp.Left = p.Left or p.Right
        else:
            pp.Right = p.Left or p.Right

    def __mot(tree):
        if (tree == None):
            return []
        else:
            return BinarySearchTree.__mot(tree.Left) + [tree.Value] + BinarySearchTree.__mot(tree.Right)
    def MiddleOrder(self):
        return BinarySearchTree.__mot(self.__root)

    def __init__(self, values):
        for x in values:
            self.insert(x)
            
if (__name__ == "__main__"):
    bst = BinarySearchTree([5, 6, 3, 1, 0, 2, 4, 8, 7, 9])
    print(bst.MiddleOrder())
    bst.delete(3)
    print(bst.MiddleOrder())
    bst.delete(8)
    print(bst.MiddleOrder())

二叉查找树 VS 散列表

插入后的维护:二叉查找数是有序维护的,散列表是无序维护的。所以插入删除操作,散列表的性能更高;但是输出排序结果,单靠散列表做不到。

散列表经常与二叉树结合,解决散列表 hash 冲突。这有点类似于基于计数的排序与基于比较的排序结合:先用桶排序进行数量级的排序,桶内部再用比如快速排序实现有序。

跳表 VS 二叉查找树

跳表方便返回区间结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值