在计算机科学中,二分搜寻(英语:binary search),也称折半搜寻(英语:half-interval search)、对数搜寻(英语:logarithmic search),是一种在有序数组中查找某一特定元素的搜寻算法。搜寻过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜寻过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜寻算法每一次比较都使搜寻範围缩小一半。
基本介绍
- 中文名:二分搜寻
- 外文名:binary search
- 又称:折半搜寻、对数搜寻
- 类别:一种搜寻算法
- 数据结构:数组
原理
计算步骤







令
为
,
为
。




如果
,则搜寻以失败告终。

令
(中间值元素)为
。


如果
,令
为
并回到步骤二。



如果
,令
为
并回到步骤二。



当
,搜寻结束;回传值
。


这个叠代步骤会持续通过两个变数追蹤搜寻的边界。有些实际套用会在算法的最后放入相等比较,让比较循环更快,但平均而言会多一层叠代。
大致匹配
以上程式只适用于完全匹配,也就是查找一个目标值的位置。不过,因为有序数组的顺序性,将二分搜寻算法扩展到能适用大致匹配并不是很重要。举例来说,二分搜寻算法可以用来计算一个赋值的排名(或称秩,比它更小的元素的数量)、前趋(下一个最小元素)、后继(下一个最大元素)以及最近邻。搜寻两个值之间的元素数目的範围查询可以藉由两个排名查询(又称秩查询)来运行。
- 排名查询可以使用调整版的二分搜寻来运行。藉由在成功的搜寻回传{\displaystyle m},以及在失败的搜寻回传{\displaystyle L},就会取而代之地回传了比起目标值小的元素数目。
- 前趋和后继查询可以藉由排名查询来运行。一旦知道目标值的排名,其前趋就会是那个位于其排名位置的元素,或者排名位置的上一个元素(因为它是小于目标值的最大元素)。其后继是(数组中的)下一个元素,或是(非数组中的)前趋的下一个元素。目标值的最近邻可能是前趋或后继,取决于何者较为接近。
- 範围查询也是直接了当的。一旦知道两个值的排名,不小于第一个值且小于第二个值的元素数量就会是两者排名的差。这个值可以根据範围的端点是否算在範围内,或是数组是否包含其端点的对应键来增加或减少1。
複杂度分析
- 时间複杂度
折半搜寻每次把搜寻区域减少一半,时间複杂度为
。(n代表集合中元素的个数)

- 空间複杂度

示例代码
C 版本- 递归
int binary_search(const int arr[], int start, int end, int khey) {if (start > end)return -1; int mid = start + (end - start) / 2; //直接平均可能会溢位,所以用此算法if (arr[mid] > khey)return binary_search(arr, start, mid - 1, khey);else if (arr[mid] < khey)return binary_search(arr, mid + 1, end, khey);else return mid; //最后检测相等是因为多数搜寻状况不是大于要不就小于}
C 版本- while 循环
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; // 单一出口}
javascript 版本
Array.prototype.binary_search = function(low, high, khey) {if (low > high)return -1;var mid = parseInt((high + low) / 2);if (this[mid] > khey)return this.binary_search(low, mid - 1, khey);if (this[mid] < khey)return this.binary_search(mid + 1, high, khey);return mid;};
Python3 版本 递归
def binary_search(arr,start,end,hkey):if start > end:return -1mid = start + (end - start) / 2if arr[mid] > hkey:return binary_search(arr, start, mid - 1, hkey)if arr[mid] < hkey:return binary_search(arr, mid + 1, end, hkey)return mid
Python3 版本 while 循环
def binary_search(arr, start, end, hkey):while start <= end:mid = start + (end - start) // 2if arr[mid] < hkey:start = mid + 1elif arr[mid] > hkey:end = mid - 1else:return mid
C# 版本
static int binary_search(int[] arr, int start, int end, int khey) { int mid; while (start <= end) { mid = (start + end) / 2; if (arr[mid] < khey) start = mid + 1; else if (arr[mid] > khey) end = mid - 1; else return mid; } return -1; }
Swift 版本
import Foundation/// 二分搜寻完全匹配////// - Parameters:/// - arr: 有序数组/// - start: 起始位置/// - end: 结束点/// - khey: 特点目标值/// - Returns: 返回查找结果func binarySearch(arr: [Int], start: Int, end: Int, khey: Int) -> Int? { guard start < end else { return nil } let mid = start + (end - start) / 2 if arr[mid] > khey { return binarySearch(arr: arr, start: start, end: mid - 1, khey: khey) } else if arr[mid] < khey { return binarySearch(arr: arr, start: mid + 1, end: end, khey: khey) } else { return mid }}
Java 递归
public static int binarySearch(int[] arr, int start, int end, int hkey){ if (start > end) return -1; int mid = start + (end - start)/2; //防止溢位 if (arr[mid] > hkey) return binarySearch(arr, start, mid - 1, hkey); if (arr[mid] < hkey) return binarySearch(arr, mid + 1, end, hkey); return mid; }
Java while 循环
```Java public static int binarySearch(int[] arr, int start, int end, int hkey){ int result = -1; while (start <= end){ int mid = start + (end - start)/2; //防止溢位 if (arr[mid] > hkey) end = mid - 1; else if (arr[mid] < hkey) start = mid + 1; else { result = mid ; break; } } return result; }