二分查找也称折半查找(Binary Search)
1、目的:给定一个数组和一个目标值,返回该目标值在数组中第一次出现位置的下标。
2、限制:(1)该数组必须满足顺序存储结构。(2)必须按关键字大小有序排列。
3、原理:每次取数组正中间的值与目标值比较,若相等则返回该中间值的下标,若目标值大于中间的值则取中间值的后半部分作为一个新的数组(保留原下标)重复第一步的操作,若目标值小于中间的值则取该中间值的前半部分的作为一个新的数组(保留原下标)重复第一步的操作。
例子:给定数组num[10]={1,2,3,4,5,6,7,8,9,10};目标值target为3;
第一步:取数组中间的值,中间下标mid = (0+9)/2 = 4,num[mid] = 5; 因为3<5 ,取5的前半部分作为一个新的数组,即{1,2,3,4},该数组保留原来的下标值
第二步:重复第一步,中间下标mid =(0+3)/2 = 1,num[1] = 2;因为3>2,取2的后半部分作为一个新的数组,即{3,4},该数组保留原来的下标值
第三步:重复第一步,中间下标mid =(2+3)/2 = 2,num[2] = 3;因为3 =3,所以返回值为2;
代码实现
int binarySearch(int num[],int low,int high ,int key)
{
while (low <= high)
{
int mid = (low + high) / 2;
if (num[mid] == key) return mid;
else if (num[mid] > key) high = mid - 1;
else low = mid + 1;
}
return -1;
}
至此,我们已经完成了二分查找的一般情况下的解决方法,但是我们还要考虑一种情况:当数组存在重复元素的时候就会导致答案可能出错,因为我们要查找的是第一次出现的位置。
例如:num[5] = {1,2,2,2,3};target = 2 ;采用上面的方法得出的是下标2,而我们需要的答案是小标1.
所以对上面的代码进行改进如下,若目标值小于或等于中间的值则继续对前一部分进行操作
int binarySearch(int num[], int low, int high, int key)
{
int mid = (low + high) / 2;
while (low < high)
{
if (num[mid] >= key) high = mid;
else if (num[mid] < key) low = mid + 1;
mid = (low + high) / 2;
}
return num[mid] == key ? mid : -1;
}