跳表和二叉查找树是基于有序序列的查找,排序是为了更快的查找。
散列表是基于 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 二叉查找树
跳表方便返回区间结果