二分查找用于有序序列的查找,能够快速判断待查找的内容是否存在于序列中,算法的时间复杂度为log2(n)。主要有两种设计方法,迭代和递归。通常采用迭代形式,可以减少函数递归的栈操作,消耗的内存更少,速度也更快。
递归形式比较简单。如下所示。每次递归通过计算中间位置,减少查找范围。
template <typename T>
bool binary_search(T &arr, int high, int low, int value) {
if (high < low)
return false;
int mid = (high - low) / 2 + low;
if (arr[mid] == value)
return true;
if (arr[mid] < value)
return binary_search(arr, high, mid + 1, value);
return binary_search(arr, mid - 1, low, value);
}
迭代形式主要通过high>=low这个条件控制迭代的退出,其次是每次迭代的过程中,当arr[mid]不等于待查找的值时,更新high或low时,需要将mid加1或减1,而不能直接用mid更新范围,否则可能出现死循环。
template <typename T>
bool binary_search(T &arr, int high, int low, int value) {
int mid = 0;
while(high >= low) {
mid = (high - low) / 2 + low;
if (arr[mid] == value)
return true;
if (arr[mid] > value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return false;
}
代码中通过(high-low)/2+low计算中间位置是因为采用(high+low)/2的形式,当high和low均比较大时,可能出现溢出,导致出错;采用int表示序列的首元素和末尾元素的位置,同样是为了避免出现死循环,如待查找的值小于首元素的值时。采用模板表示数值序列,只要序列是有序顺序存储的类型该函数都可以正常工作,如std::vector,std::array,std::deque等。