二分查找(Binary Search)
1.无序数组
def binary_search(data,target,low,hight):
'''二分查找 O(log(N))'''
if low > hight:
return False
else:
mid = (low+hight)//2
if target == data[mid]:
return True
elif target < data[mid]:
return binary_search(data,target,low,mid-1)
else:
return binary_search(data,target,mid+1,hight)
2.有序数组
def binary_search(data,target,low,hight):
'''回归方法'''
if low > hight:
return False
else:
mid = (low+hight)//2
if target == data[mid]:
return True
elif target < data[mid]:
return binary_search(data,target,low,mid-1)
else:
return binary_search(data,target,mid+1,hight)
def binary_search(data,target,low,hight):
'''迭代方法'''
if low > hight:
return False
while low <= hight:
mid = (low+hight)//2
if target < data[mid]:
hight = mid -1
elif target > data[mid]:
low = mid + 1
else:
return True
return False
二叉查找树(Binary Search Trees)
一种将链表插入的灵活性和有序数组查找的高效性结合起来的符号表。
在二叉查找树(BST)中,每个节点包含一个Comparable的键(以及相应的值),且每个节点的键都大于其左子树的任意节点的键而小于右子树的任意节点的键。即前向遍历是键的递增序列
first() | 返回最低级别键的位置,如果树为空返回None |
last() | 返回最高级别键的位置,如果树为空返回None |
before(p) | 返回位置p处键的前一个键所处位置,如果p是最低级别键则返回None |
after(p) | 返回位置p处键的后一个键所处位置,如果p是最高级别键则返回None |
Algorithm after(p):
if right(p) is not None then {successor is leftmost position in p’s right subtree}
walk = right(p)
while left(walk) is not None do
walk = left(walk)
return walk
else {successor is nearest ancestor having p in its left subtree}
walk = p
ancestor = parent(walk)
while ancestor is not None and walk == right(ancestor) do
walk = ancestor
ancestor = parent(walk)
return ancestor
查找
Algorithm TreeSearch(T, p, k):
if k == p.key() then
return p {successful search}
else if k < p.key() and T.left(p) is not None then
return TreeSearch(T, T.left(p), k) {recur on left subtree}
else if k > p.key() and T.right(p) is not None then
return TreeSearch(T, T.right(p), k) {recur on right subtree}
return p {unsuccessful search}
插入
Algorithm TreeInsert(T, k, v):
Input: A search key k to be associated with value v
p = TreeSearch(T,T.root(),k)
if k == p.key() then
Set p’s value to v
else if k < p.key() then
add node with item (k,v) as left child of p
else
add node with item (k,v) as right child of p
删除
如果p有一个节点那就删除节点,用子节点替换。若p有两个节点,则按照下列顺序处理:
- 找到小于位置p的键的最大键位置r。即r=before(p).
- 将r的键值对替换掉p。这样就保证了p位置的有序性。左子树<= p(r) < 右子树
- 删除位置r,由于r为最右节点,没有右子节点,可以按照一个子节点的方法删除
在由N个随机键构造的二叉查找树中,查找命中平均所需的比较次数为1.39lgN,插入操作和查找未命中平均所需比较次数为1.39lgN
算法(数据结构) | 最坏情况运行时间 | 平均情况运行时间 | ||
查找 | 插入 | 查找命中 | 插入 | |
顺序查找(无序链表) | N | N | N/2 | N |
二分查找(有序数组) | lgN | N | lgN | N/2 |
二叉树查找 | N | N | 1.39lgN | 1.39lgN |
平衡查找树(Balanced Search Trees)
- 2-节点,含有一个键(及其对应的值)和两条连接,左连接指向的键都小于该节点,右连接都大于该结点
- 3-节点,含有两个键(及其对应的值)和三条连接,左连接指向的键都小于这两个键,中连接指向的键介于这两个键之间,右连接指向的键都大于该结点
一个完美平衡的2-3查找树中的所有空链接到根节点的距离应该相同。
查找
插入
要在2-3树中插入一个新节点,可以和二叉查找树一样先进行一次未命中的查找,然后把新节点挂在树的底部,但这样无法保证平衡。如果未命中查找结束于一个2节点,只需将2节点变为3节点;如果未命中查找结束于一个3节点,事情就麻烦些。
向2-节点中插入新键
向3-节点中插入新建