【二分搜寻演算法】
在计算机科学中，二分查找算法（binary search algorithm），也称折半搜索算法（half-interval search algorithm）、对数搜索算法（logarithmic search algorithm）loc=§6.2.1 ("Searching an ordered table"), subsection "Binary search"，是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始，如果中间元素正好是要查找的元素，则搜索过程结束；如果某一特定元素大于或者小于中间元素，则在数组大于或小于中间元素的那一半中查找，而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空，则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。
二分查找算法在最坏情况下是对数时间复杂度的，需要进行次比较操作（在此处是数组的元素数量，是大O记号，是对数）。二分查找算法使用常数空间，对于任何大小的输入数据，算法使用的空间都是一样的。除非输入数据数量很少，否则二分查找算法比线性搜索更快，但数组必须事先被排序。尽管一些特定的、为了快速搜索而设计的数据结构更有效（比如哈希表），二分查找算法应用面更广。
二分查找算法有许多种变种。比如分散层叠可以提升在多个数组中对同一个数值的搜索的速度。分散层叠有效的解决了计算几何学和其他领域的许多搜索问题。4=指数搜索将二分查找算法拓宽到无边界的列表。二叉搜索树和B树数据结构就是基于二分查找算法的。
== 演算法 ==
二分搜索只对有序数组有效。二分搜索先比较数组中位-{}-元素和目标值。如果目标值与中位-{}-元素相等，则返回其在数组中的位置；如果目标值小于中位-{}-元素，则搜索继续在前半部分的数组中进行。如果目标值大于中位-{}-元素，则搜索继续在数组上部分进行。由此，算法每次排除掉至少一半的待查数组。
=== 步骤 ===
给予一个包含个带值元素的阵列或是记录，使，以及目标值，还有下列用来搜寻在中位置的子程式loc=§6.2.1 ("Searching an ordered table"), subsection "Algorithm B"。
# 令为，为。
# 如果，则搜寻以失败告终。
# 令（中间值元素）为。（具体实现中，为防止算术溢出，一般采用代替。）
# 如果，令为并回到步骤二。
# 如果，令为并回到步骤二。
# 当，搜寻结束；回传值。
这个叠代步骤会持续透过两个变数追踪搜索的边界。有些实际应用会在演算法的最后放入相等比较，让比较回圈更快，但平均而言会多一层叠代。
=== 大致匹配 ===
以上程序只适用于完全匹配，也就是寻找一个目标值的位置。不过，因为有序阵列的顺序性，将二分搜索算法扩展到能适用大致匹配并不是很重要。举例来说，二分搜索算法可以用来计算一个赋值的排名（或称秩，比它更小的元素的数量）、前趋（下一个最小元素）、后继（下一个最大元素）以及最近邻。搜寻两个值之间的元素数目的范围查询可以借由两个排名查询（又称秩查询）来执行loc=§3.1, subsection "Rank and selection"。
* 排名查询可以使用调整版的二分搜索来执行。借由在成功的搜索回传，以及在失败的搜索回传，就会取而代之地回传了比起目标值小的元素数目loc=§3.1, subsection "Rank and selection"。
* 前趋和后继查询可以借由排名查询来执行。一旦知道目标值的排名，其前趋就会是那个位于其排名位置的元素,或者排名位置的上一个元素（因为它是小于目标值的最大元素）。其后继是（阵列中的）下一个元素，或是（非阵列中的）前趋的下一个元素pp=461–463。目标值的最近邻可能是前趋或后继，取决于何者较为接近。
* 范围查询也是直接了当的。一旦知道两个值的排名，不小于第一个值且小于第二个值的元素数量就会是两者排名的差。这个值可以根据范围的端点是否算在范围内，或是阵列是否包含其端点的对应键来增加或减少1loc=§3.1, subsection "Range queries"。
==复杂度分析==
时间复杂度: 折半搜索每次把搜索区域减少一半，时间复杂度为。（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 (arrmid > khey)
return binary_search(arr, start, mid - 1, khey);
else if (arrmid
===C 版本- while 循环===
int binary_search(const int arr, int start, int end, int key) {
int ret = -1;       // 未搜索到数据返回-1下标
int mid;
while (start  key)
end = mid - 1;
else {            // 最后检测相等是因为多数搜寻状况不是大于要不就小于
ret = mid;
break;
}
}
return ret;     // 单一出口
}
===javascript 版本===
var arr = 1, 3, 5, 7, 9, 10, 11, 12, 14, 15, 19, 20;
const binarySearch = (arr, target) => {
const search = (start, end) => {
if (start > end) return -1;
const mid = start + Math.floor((end - start) / 2);
if (arrmid > target) {
return search(0, mid - 1);
} else if (arrmid
===Python3 版本 while 循环===
def binary_search(arr, left, right, hkey):
while left  hkey:
right = mid - 1
return -1
=== Python3 版本 递归 ===
def binary_search(arr, start, end, hkey):
if start > end:
return -1
mid = start + (end - start) // 2
if arrmid > hkey:
return binary_search(arr, start, mid - 1, hkey)
if arrmid
=== C# 版本 ===
static int binary_search(int arr, int start, int end, int khey)
{
int mid;
while (start  khey)
end = mid - 1;
else
return mid;
}
return -1;
}
#this is c++
===Swift 版本===
import Foundation
/// 二分搜索完全匹配
///
/// - Parameters:
///   - arr: 有序数组
///   - start: 起始位置
///   - end: 结束点
///   - khey: 特点目标值
/// - Returns: 返回查找结果
func binarySearch(arr: Int, start: Int, end: Int, khey: Int) -> Int? {
if start > end {
return nil
}
let mid = start + (end - start) / 2
if arrmid > khey {
return binarySearch(arr: arr, start: start, end: mid - 1, khey: khey)
} else if arrmid
===golang 递归版本===
func binary_search(arr int, low, high, hkey int) int {
if low > high {
return -1
}
mid := low + (high-low)/2
if arrmid > hkey {
return binary_search(arr, low, mid-1, hkey)
} else if arrmid
===golang 非递归版本===
func binarySearch(arr int, hkey int) int {
low, high := 0, len(arr)-1
for low  arrmid {
low = mid + 1
}
}
return -1
}
===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 (arrmid > hkey)
return binarySearch(arr, start, mid - 1, hkey);
if (arrmid
===Java while 循环===
public static int binarySearch(int arr, int start, int end, int hkey){
int result = -1;
while (start  hkey)
end = mid - 1;
else if (arrmid
===Julia (程式语言)===
# Julia Sample : BinarySearch
function BinarySearch(A,Key)
left,right = 1,length(A)
while(leftAmid
left = mid+1
end
end
return -1
end
# Main Code
A = 1,3,16,31,43,354,586   # Already Arrange
println(A)                   # Original Array
println(BinarySearch(A,43))  # BinarySearch Search Array
println(BinarySearch(A,354)) # BinarySearch Search Array
println(BinarySearch(A,3))   # BinarySearch Search Array
==历史==
在1946年，约翰·莫奇利在Moore School Lectures上第一次提出二分搜索的概念。loc=§6.2.1 ("Searching an ordered table"), subsection "History and bibliography"1957年，William Wesley Peterson发表了第一个应用插值搜索的算法loc=§6.2.1 ("Searching an ordered table"), subsection "History and bibliography"。在此时，每个发表的二分搜索算法只对长度为2的幂减一的数组有用。直到1960年，德里克·亨利·莱默发表了一个对于所有长度的数组都适用的算法。1962年，赫尔曼·博滕布鲁赫发表了一个用ALGOL 60写的二分搜索，将判断相等的步骤放到算法末尾。虽然将平均迭代次数增加一，但是每次迭代中的比较次数减少了1次。均匀二分搜索则是史丹佛大学的A. K.钱德拉在1971年发明的loc=§6.2.1 ("Searching an ordered table"), subsection "History and bibliography"。1986年，伯纳德·查泽尔和列奥尼达斯·吉巴斯引入了分散层叠来解决计算几何中大量存在的搜索问题。
==实现中的问题==
尽管二分查找的基本思想相对简单，但细节可以令人难以招架 ... — 高德纳loc=§6.2.1 ("Searching an ordered table"), subsection "Binary search"
当乔恩·本特利将二分搜索问题布置给专业编程课的学生时，百分之90的学生在花费数小时后还是无法给出正确的解答，主要因为这些错误程序在面对边界值的时候无法运行，或返回错误结果。loc=§4.1 ("The Challenge of Binary Search")1988年开展的一项研究显示，20本教科书里只有5本正确实现了二分搜索。不仅如此，本特利自己1986年出版的《编程珠玑》一书中的二分搜索算法存在整数溢出的问题，二十多年来无人发现。Java语言的库所实现的二分搜索算法中同样的溢出问题存在了九年多才被修复。