
本文共 1972 字,大约阅读时间需要 6 分钟。
二分查找
引言
- 二分查找是顺序表或线性链表表示的静态查找表
- 表内元素有序
1、定义
\quad \quad 二分查找针对的是一个有序的数据集合,每次通过跟区间中间的元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间缩小为0。
2、思想
\quad \quad 假设表中元素是有序的,将表的中间位置的关键字与所需的关键字比较,相等则成功,否则分为前后两个子表,若所需的值大于中间元素,则在后半部分查找,否则在前半部分查找。不断重复这个过程,直到查找成功。否则查找失败。需要两个移动指针p,r,分别指向列表的上界与下界。
3、算法
伪代码
python:
#非递归实现import numpy as npdef binary_search(A,x): A=np.sort(A)#先将A排序 n=len(A) #搜索区间范围:左闭右闭[left,right] p=0#p:头指针 r=n-1#r:尾指针 while p<=r: q=(p+r)//2#//符号:商取整 #或q=p+(r-p)//2,防止溢出,最好使用这种取中值的方法 if A[q]==x: return q elif A[q]>x: r=q-1 else: p=q+1 return print("NOT FOUND")
另一种非递归模板:
import numpy as npdef binary_search(A,x): A=np.sort(A)#先将A排序 n=len(A) #区间范围:左闭右开[left,right) p=0#p:头指针 r=n#r:尾指针 while p<r: q=(p+r)//2#//符号:商取整 #或q=p+(r-p)//2,防止溢出,最好使用这种取中值的方法 if A[q]==x: return q elif A[q]>x: r=q else: p=q+1 return print("NOT FOUND")
#递归实现(p,r)一般刚开始是(0,len(A)-1)也就是列表中第一个与最后一个位置def recursive_binary_search(A,p,r,x): A=np.sort(A)#先将A排序 if p>r: return print("NOT FOUND") else: q=(p+r)//2 if A[q]==x: return q elif A[q]>x: return recursive_binary_search(A,p,q-1,x) else: return recursive_binary_search(A,q+1,r,x)
中位数的计算方法:
1、mid = (left + right) / 2
; 是初级写法,是有 bug 的:有可能会溢出。
2、 mid = left + (right - left) / 2
; 是正确的写法,考虑到了整型溢出的风险;
3、mid = (low + high) >> 1
; 右移运算符>>
,运算结果正好能对应一个整数的二分之一值,这就正好能代替数学上的除2运算,但是比除2运算要快。
4、查找性能(ASL)
【时间复杂度】: O ( l o g 2 n ) O(log_2n) O(log2n)
【空间复杂度】:
- 递归实现: O ( l o g 2 n ) O(log_2n) O(log2n)
- 非递实现: O ( 1 ) O(1) O(1)
5、特点
优点:比较次数少,时间性能相对于顺序查找要好,效率要快
缺点:要求待查表为有序表,且限于顺序存储结构(对线性链表无效)。
局限性:
1.二分查找依赖的是顺序表结构,即数组。
2.二分查找针对的是有序数据,因此只能用在插入、删除操作不频繁,一次排序多次查找的场景中。
3.数据量太小不适合二分查找,与直接遍历相比效率提升不明显。但有一个例外,就是数据之间的比较操作非常费时,比如数组中存储的都是长度超过300的字符串,那这是还是尽量减少比较操作使用二分查找吧。
4.数据量太大也不是适合用二分查找,因为数组需要连续的空间,若数据量太大,往往找不到存储如此大规模数据的连续内存空间。
发表评论
最新留言
关于作者
