二分查找是针对有序序列来说的,在有序序列中使用二分查找能大大提高查找效率。
二分算法步骤
前提:有序数组中查找关键词所在的位置
① 首先确定整个查找区间的中间位置 mid
② 用待查关键字key值与中间位置的关键字值进行比较;
若相等,则查找成功
若大于,则在后(右)半个区域继续进行折半查找
若小于,则在前(左)半个区域继续进行折半查找
③ 对确定的缩小区域再按折半公式,重复上述步骤。
中间位置mid的表示:
(1)简单的写法
mid = (start + end) / 2
但这种写法有个缺点:mid可能会溢出。
我们可以举一个简单的例子来证明这一事实。
比如,当start = 1000 ,
end = INT_MAX。
INT_MAX
是int
数据类型可以存储的上限。这时start + end的和就溢出了。
(2)保险的写法
mid = start + (end - start) / 2
这样的写的好处大概有两个:
第一 :不会产生溢出
第二 :从通用性考虑,适用于对指针或者迭代器的操作。如果start和end同时是指针或者同时是迭代器时无法编译通过,因为俩指针或者俩迭代器运算不支持相加运算,只支持相减运算。
为什么指针和迭代器运算不支持相加运算,只支持相减运算?
我发现网上很少提及这个问题的原因。本人认为原因是这样的:两个迭代器相加,或者两个指针相加后所表示的位置对于vector容器就越界了,失去的意义。但是相减就可以,位置还在容器之中。
(3)(2)的另一种写法
mid = start + ((end - start) >> 1)
这种写法和(2)一样。
“>>”:表示向右移。value >> num:即value的二进制数整体向右移num位,表示在十进制上就是value除以2的num次方,value >> 1就是value 除以2。
“<<”:表示左移。value << num,就是指value的二进制形式整体向左移动num位,表示在十进制上就是value乘以2的num次方,value << 1就是value乘以2。
故(end - start) >> 1,即为(end - start) / 2。
二分查找算法
非递归写法:
/**
*Copyright (c) 2019 Young Fan.All Right Reserved.
*Author: Young Fan
*Date: 2019.04.26
*IDE: Visual Studio 2017
*Description:
*/
#include <iostream>
using namespace std;
int binarySearch(int numbers[], int length, int target) {
int length_ptr = sizeof(numbers) / sizeof(int);
cout << length_ptr << endl;//输出为1,sizeof会把从主函数中传进来的字符数组当作是指针来处理。
//指针的大小又是由机器来决定,32位编译器指针变量的大小为4字节,64位编译器指针变量的大小为4字节
if (length == 0)
return -1;
int start = 0, end = length - 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (numbers[mid] == target)
return mid; //查找到了则返回数据数组的下标
else if (numbers[mid] > target)
end = mid - 1;
else
start = mid + 1;
}
return -1;
}
int main()
{
int numbers[] = { 1, 2, 3, 4, 5, 6, 7}; //有序的
int length = sizeof(numbers) / sizeof(int); //n得7
cout << "length = " << length << endl;
int a = binarySearch(numbers, length, 7); //返回数据数组的下标
cout << a << endl;
return 0;
}
递归写法:
int binarySearch(int[] a, int start, int end, int target) {
if(start > end)
return -1;
int mid = start + (end - start) / 2;
if(a[mid] == target)
return mid;
else if(a[mid] > target)
return binarySearch(a, start, mid-1, target);
else
return binarySearch(a, mid+1, end, target);
}