题目
回顾一下联系2.1-3中提到的查找问题,注意如果序列A是已排序的,就可以将该序列的中点与v进行比较。根据比较的结果,原序列中有一半就可以不用再做进一步的考虑了。二分查找就是一个不断重复这一过程的算法。写出二分查找的伪代码,可以是迭代的,也可以是递归的。说明二分查找的最坏情况运行时间是为什么是
分析
分别给出迭代形式和递归形式的分析,从分析可以看出迭代和递归是等价的,递归的解法比较直观,迭代的空间代价是较小的。
迭代形式分析
给定参数A,p,r,v,A[p...r]是排序好的序列。需要一个变量q记录中点的位置,然 后就是迭代的循环:
q被赋值为
试着写出迭代的二分查找的循环不变式:在循环的每次迭代开始前,必然满足不等式A[p]<=v或A[r]>=v,且是排序好的。
为满足循环不变式,加入对断点的判断
v==A[q],找到了v,返回q值;
v>A[q],p被赋值为q+1;
v<A[q],r被赋值为q-1;
循环的终止条件是p<=r。
这里必须有等号,否则对于单个数据的数组没法查找了
试着写出迭代的二分查找的循环不变式:在循环的每次迭代开始前,必然满足不等式A[p]<=v或A[r]>=v,且是排序好的。
伪代码
BINARY-SEARCH-ITERATION(A, p, r, v) | cost | times |
if A[p] > v or A[r] < v | c1 | 1 |
then return NIL | c2 | 1或0 |
while p <= r | c3 | ti |
q <- | c4 | ti-1 |
if v == A[q] then return q else if v > A[q] then p <- q+1 else r <- q-1 | c5 | ti-1 |
if A[p] > v or A[r] < v | c6 | ti-1 |
then return NIL | c7 | 1或0 |
return NIL | c8 | 1 |
为满足循环不变式,加入对断点的判断
时间复杂度分析
由伪代码的分析可以看出,整个程序的运行时间由ti决定,所以,
,而在最坏情况下,即v与A[p]或A[r]相等,由于每次搜索范围都是上一次的一半,所以此种情况下,while循环运行
次,因此
递归形式分析
伪代码
BINARY-SEARCH-RECURSION(A, p, r, v)
1 if p <= r
2 then q <-
3 if A[q] == v
4 then return q
5 else if A[q] > v
6 then return BINARY-SEARCH-RECURSION(A, p, q-1, v)
7 else return BINARY-SEARCH-RECURSION(A, q+1, r, v)
1 if p <= r
2 then q <-
3 if A[q] == v
4 then return q
5 else if A[q] > v
6 then return BINARY-SEARCH-RECURSION(A, p, q-1, v)
7 else return BINARY-SEARCH-RECURSION(A, q+1, r, v)
8 retrun NIL
时间复杂度分析
使用分治法分析:
分解:这一步需要求出中点的位置,并进行比较,步骤是常数,因此
解决:递归的解决规模为n/2的子问题,所以时间为T(n/2)
合并:显然,二分查找直接返回v的位置,不需要合并,因此C(n)=0
因此,二分查找的递归式为
通过画出递归树或主定理都可以得到二分查找的最坏运行时间为
分解:这一步需要求出中点的位置,并进行比较,步骤是常数,因此
解决:递归的解决规模为n/2的子问题,所以时间为T(n/2)
合并:显然,二分查找直接返回v的位置,不需要合并,因此C(n)=0
因此,二分查找的递归式为
通过画出递归树或主定理都可以得到二分查找的最坏运行时间为
Pyhton实现
迭代
def binary_search_ite(a, p, r, v):
if a[p] > v or a[r] < v:
return None
while p <= r:
q = (p + r) / 2
if a[q] == v:
return q
elif a[q] > v:
r = q - 1
elif a[q] < v:
p = q + 1
if a[p] > v or a[r] < v:
return None
return None
递归
def binary_search(a, p, r, v):
if p <= r:
q = (p + r) / 2
if a[q] == v:
return q
elif a[q] > v:
return binary_search(a, p, q-1, v)
elif a[q] < v:
return binary_search(a, q + 1, r, v)
return None