二分查找算法

     ~~~~     在计算机科技中,二分查找算法,也称为折半搜索算法、对数搜索算法,是一种在有序数列中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。
     ~~~~     二分查找算法在情况下的复杂度是对数时间,进行 O ( l o g n ) O(log n) O(logn)次比较操作( n n n在此次是数组的元素数量, O O O是大o记号, l o g log log是对数)。二分查找算法使用常数空间,无论对任何大小的输入数据,算法使用的空间都是一样的。除非输入数据数量很少,否则二分查找算法比线性搜索更快,但数组必须是先被排序。尽管特定的、为了快速搜索而设定的数据结构更有效(比如哈希表),二分查找算法应用更广。
     ~~~~     二分查找算法有许多变种。比如分散层叠可以提升在多个数组中对一个数值的搜索。分散层叠有效的解决了计算几何学和其他领域的许多搜索问题。指数搜索将二分查找算法扩宽到无边界的列表。二叉搜索树和B树数据结构就是基于二分查找算法的。

算法

     ~~~~     二分搜索支队有序数组有效。二分搜索先比较数组中比特素和目标。如果目标值与中比特素相等,则返回其在数组中的位置;如果目标值小于中比特素,则搜索继续在前半部分的数组中进行。如果目标值大于中比特素,则搜索继续在数组上部分进行。由此,算法每次排除掉至少一半的待查数组。

步骤

     ~~~~     给予一个包含 n n n个带值元素的数组 A A A或是记录 A 0 , . . . , A n − 1 A_0,...,A_{n-1} A0,...,An1,使 A 0   ≤ . . . ≤   A n − 1 A_0~\leq...\leq~A_{n-1} A0 ... An1,以及目标值 T T T,还有下列用来查找 T T T A A A中位置的子程序。

1.令 L L L为0, R R R n − 1 n-1 n1
2.如果 L > R L > R L>R,则查找以失败告终。
3.令 m m m(中间值元素为) [ ( L + R ) / 2 ] [(L + R) / 2] [(L+R)/2]。(具体实现中,为防止算法溢出,一般采用 L + ( R − L ) / 2 L + (R - L) / 2 L+(RL)/2代替。)
4.如果 A m < T A_m<T Am<T,令 L L L m + 1 m+1 m+1并回到步骤二。
5.如果 A m > T A_m>T Am>T,令 R R R m − 1 m-1 m1并回到步骤二。
6.当 A m = T A_m=T Am=T,查找结束;会传值 m m m

这个迭代步骤会持续透过两个变量追踪搜索的边界。有些实际应用会在算法的最后放入相等比较,这比较循环更快,但平均而言会多一层迭代。

大致匹配

     ~~~~     以上程序值适用于完全匹配,也就是查找一个目标值得位置。不过,因为有序数组的顺序性,将二分搜索算法扩展到能适用大致匹配并不是很重要。举例来说,二分搜索算法可以用来计算一个赋值的排名(或称跌,比它更小的元素的数量)、前趋(下一个最小元素)、后继(下一个最大元素)以及最近邻。查找两个值之间的元素数目的范围查询可以借由两个排名查询(又称秩查询)来运行。

排名查询可以使用调整版的二分搜索来运行。借助在成功的搜索回传 m m m,以及在失败的搜索回传 L L L,就会取而代之地回传了比起目标值小的元素数目。
前趋和后继查询可以借由排名 查询来运行。一旦知道目标值得排名,其前趋就会是那个位于其排名位置的元素,或者排名位置的上一个元素(因为他是一个目标值得最大元素)。其后继是(数组中的)下一个元素,或是(非数组中的)前趋的下一个元素。目标值得最近邻可能是前趋或后继,取决于何者较为接近。
范围查询也是直接了当。一旦知道两个值的排名,不小于第一个值且小于第二个值得元素就会是两者排名的差。这个值可以根据范围的端点是否在范围内,或是数组是否包含其端点的对应键来增加或减少1。

复杂度分析

时间复杂度:折半搜索每次把搜索区域减少一半,时间复杂度 O ( l o g   n ) O(log~n) O(log n)。(n代表集合中元素的个数)
空间复杂度 O ( 1 ) O(1) O(1)。虽以递归形式定义,但是尾递归,可改写为循环。

应用

除直接在一个数组中查找元素外,可用在插入排序中。

代码示例

int binary_search(const int arr[], int start, int end, int key) {
    int ret = -1;       // 未搜索到数据,返回-1下标
    
	int mid;
	while (start <= end) {
		mid = start + (end - start) / 2; //直接平均可能会溢位,所以用次算法
		if (arr[mid] < key)
			start = mid + 1;
		else if (arr[mid] > key)
			end = mid - 1;
		else {            //最后检测相等是因为多数搜寻状态不是大于就是小于,等于较少 
			ret = mid;  
            break;
        }
	}
	
	return ret;     // 单一出口
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值