要解决的问题:
1,给定一个有序(不降序)数组arr,求任意一个i使得arr[i]等于v,不存在则返回-1。
2,给定一个有序(不降序)数组arr,求最小的i使得arr[i]等于v,不存在则返回-1。
3,给定一个有序(不降序)数组arr,求最大的i使得arr[i]等于v,不存在则返回-1。
4,给定一个有序(不降序)数组arr,求最大的i使得arr[i]小于v,不存在则返回-1。
5,给定一个有序(不降序)数组arr,求最小i使得arr[i]大于v,不存在则返回-1。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1,给定一个有序(不降序)数组arr,求任意一个i使得arr[i]等于v,不存在则返回-1。
举例:
待查找数组:arr[8] = {2,3,3,3,3,5,6,7};
待查找数:v=3.
返回结果:可以返回i=1,2,3,4中任意一个位置
注:这是最一般的二分查找。
代码:
#include <iostream>
using namespace std;
/*
寻找key,
找到后直接返回下标,
没找到返回-1
*/
int BinarySearch(int* arr,int key,int len)
{
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if (key > arr[mid])
{
low = mid + 1;
}
else if (key < arr[mid])
{
high = mid - 1;
}
else
{
return mid;//找到key后,直接返回
}
}
return -1;
}
int main()
{
int arr1[8] = {3,3,3,3,3,3,3,3};
int arr2[8] = {2,3,3,3,3,5,6,7};
int arr3[8] = {2,3,3,3,3,5,6,7};
cout<<BinarySearch(arr1,3,8)<<endl;//返回3
cout<<BinarySearch(arr2,3,8)<<endl;//返回3
cout<<BinarySearch(arr3,4,8)<<endl;//返回-1
system("pause");
}
注意:对于增序序列,当命中失败时,即在待查找序列中没有要找的key,
low 最后指向 紧挨着key且大于key 的值。
high 最后指向 紧挨着key且小于key 的值
如:待查找序列为:arr[8] = {2,3,3,3,3,5,6,7};
待查找元素:v = 4
程序最终的结果指向为:
low = 5(表示下标):指向5,第一个比4大的元素
high = 4(表示下标):指向3,第一个比4小的元素
下面求比V小或大的元素时,可以用到这个点
记忆:程序终止的条件 : high < low
即,low在high前面,即arr[high] < key < arr[low]
2、给定一个有序(不降序)数组arr,求最小的i使得arr[i]等于v,不存在则返回-1。
举例:
待查找数组:arr[8] = {2,3,3,3,3,5,6,7};
待查找数:v=3.
返回结果:i=1(第一个出现3的位置)
代码:
#include <iostream>
#include <assert.h>
using namespace std;
int BinarySearch(int* arr,int key,int len)
{
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if (key > arr[mid])
{
low = mid + 1;
}
else //相等时仍要往下标为0出走
{
high = mid - 1;
}
}
assert(low > -1);
if (low < len && arr[low] == key)
{
return low;
}
else
{
return -1;
}
}
int main()
{
int arr1[8] = {3,3,3,3,3,3,3,3};
int arr2[8] = {2,3,3,3,3,5,6,7};
int arr3[8] = {2,3,3,3,3,5,6,7};
int arr4[8] = {2,2,2,2,2,2,2,2};
cout<<BinarySearch(arr1,3,8)<<endl;//返回0
cout<<BinarySearch(arr2,3,8)<<endl;//返回1
cout<<BinarySearch(arr3,4,8)<<endl;//返回-1
cout<<BinarySearch(arr4,3,8)<<endl;//返回-1
system("pause");
}
注意:对于增序序列,最终low和high的位置(一定是low > high.)
low:在不越界的情况下,会指向第一个大于或等于key的值
high:在不越界的情况下,会指向最后一个小于key的值
具体来说,如果待查找序列中有key值,即能命中。
则,low肯定指向第一个key。 high指向key左边的值
如果待查找序列中没有key值,即不能命中
则,low肯定指向第一个比key大的值。(如果所有的值均比key值小,则low越界)
high指向最后一个比key小的值(如果所有的值均比key大,则high越界)。
此时,也能保证 low > high.
举例:
(1)能命中key值
待查找序列:3,3,3,3,3,3,3,3 : 查找3
最终,low = 0 high = -1
待查找序列:2,3,3,3,3,5,6,7 : 查找3
最终,low = 1 high = 0
(2)不能命中key值
待查找序列:2,3,3,3,3,5,6,7 : 查找4
最终,low = 5(指向5) high = 4(指向3)
待查找序列:2,2,2,2,2,2,2,2 : 查找3
最终,low = len(越界),high = 7(最后一个2)
待查找序列:2,2,2,2,2,2,2,2 : 查找1
最终,low = 0,high = -1(越界)
总上例子可见,虽然low和high都可能越界,但是由于我们最后只取low值,而且low越界时只能为Len,故考虑low的越界时,只需设置为low < len即可
3、给定一个有序(不降序)数组arr,求最大的i使得arr[i]等于v,不存在则返回-1。
举例:
待查找数组:arr[8] = {2,3,3,3,3,5,6,7};
待查找数:v=3.
返回结果:i=4(最后一个出现3的位置)
代码:
#include <iostream>
#include <assert.h>
using namespace std;
/*
查找出现key的最高位置,
如果有key,返回最高位置
如果没有key,返回-1
*/
int BinarySearch(int* arr,int key,int len)
{
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if (key >= arr[mid])
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
if (high > -1 && high < len && arr[high] == key)//此时low指向第一个比key大的数,high指向key
{
return high;
}
else
{
return -1;
}
}
int main()
{
int arr1[8] = {3,3,3,3,3,3,3,3};
int arr2[8] = {2,3,3,3,3,5,6,7};
int arr3[8] = {2,3,3,3,3,5,6,7};
int arr4[8] = {2,2,2,2,2,2,2,2};
cout<<BinarySearch(arr1,3,8)<<endl;//返回7
cout<<BinarySearch(arr2,3,8)<<endl;//返回4
cout<<BinarySearch(arr3,4,8)<<endl;//返回-1
cout<<BinarySearch(arr4,3,8)<<endl;//返回-1
cout<<BinarySearch(arr4,1,8)<<endl;//返回-1
system("pause");
}
4、给定一个有序(不降序)数组arr,求最大的i使得arr[i]小于v,不存在则返回-1。
举例:
待查找数组:arr[8] = {2,3,3,3,3,5,6,7};
待查找数:v=3. 返回结果:i=0(最后一个比key小的元素)
待查找数:v=4 返回结果:i=4
代码:
#include <iostream>
#include <assert.h>
using namespace std;
/*
查找比key小的最大值
如果有,返回下标
如果没有,返回-1
*/
int BinarySearch(int* arr,int key,int len)
{
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if (key > arr[mid])
{
low = mid + 1;
}
else //相等时仍要往下标为0出走
{
high = mid - 1;
}
}
assert(high < len);
if (high > -1)
{
return high;
}
else
{
return -1;
}
}
int main()
{
int arr1[8] = {3,3,3,3,3,3,3,3};
int arr2[8] = {2,3,3,3,3,5,6,7};
int arr3[8] = {2,3,3,3,3,5,6,7};
int arr4[8] = {2,2,2,2,2,2,2,2};
cout<<BinarySearch(arr1,3,8)<<endl;//返回-1
cout<<BinarySearch(arr2,3,8)<<endl;//返回0
cout<<BinarySearch(arr3,4,8)<<endl;//返回4
cout<<BinarySearch(arr4,3,8)<<endl;//返回7
cout<<BinarySearch(arr4,1,8)<<endl;//返回-1
system("pause");
}
注意:如果high值不越界,high值总是指向比key值小的最大数,low指向比arr[high]大的数。
5、给定一个有序(不降序)数组arr,求最小i使得arr[i]大于v,不存在则返回-1。
举例:
待查找数组:arr[8] = {2,3,3,3,3,5,6,7};
待查找数:v=3. 返回结果:i=5(下标)(第一个比key大的元素)
待查找数:v=4 返回结果:i=5(表示下标)
待查找数:v=7 返回结果:i=-1(没有比7大的元素)
代码:
#include <iostream>
#include <assert.h>
using namespace std;
/*
查找比key大的最小值
如果有,返回下标
如果没有,返回-1
*/
int BinarySearch(int* arr,int key,int len)
{
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if (key >= arr[mid])
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
if (low > -1 && low < len)//此时low指向第一个比key大的数,high指向key出现的最大位置或比key小的那个数(key不存在)
{
return low;
}
else
{
return -1;
}
}
int main()
{
int arr1[8] = {3,3,3,3,3,3,3,3};
int arr2[8] = {2,3,3,3,3,5,6,7};
int arr3[8] = {2,3,3,3,3,5,6,7};
int arr4[8] = {2,2,2,2,2,2,2,2};
cout<<BinarySearch(arr1,3,8)<<endl;//返回-1
cout<<BinarySearch(arr2,3,8)<<endl;//返回5
cout<<BinarySearch(arr3,4,8)<<endl;//返回5
cout<<BinarySearch(arr4,3,8)<<endl;//返回-1
cout<<BinarySearch(arr4,1,8)<<endl;//返回0
system("pause");
}
注意:如果low值不越界,low值总是指向大于key的最小元素,high指向比arr[low]小的数。
更简单的版本:
#include <iostream>
using namespace std;
/*
查找比key大的最小值
如果有,返回下标
如果没有,返回-1
*/
int BinarySearch(int* arr,int key,int len)
{
int low = 0;
int high = len - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if (key >= arr[mid])
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
if (low != -1 && low != len && arr[low] > key)//low和high总有一个变量代表着结果,可以都检测一遍
{
return low;
}
else if (high != -1 && high != len && arr[high] > key)
{
return high;
}
else
{
return -1;
}
}
int main()
{
int arr1[8] = {3,3,3,3,3,3,3,3};
int arr2[8] = {2,3,3,3,3,5,6,7};
int arr3[8] = {2,3,3,3,3,5,6,7};
cout<<BinarySearch(arr1,3,8)<<endl;
cout<<BinarySearch(arr2,3,8)<<endl;
cout<<BinarySearch(arr3,4,8)<<endl;
system("pause");
}
这里总结下,设置low和high值时的原则
(1)Low右移条件:待查找元素在mid的右侧
(2)High左移条件:待查找元素在mid的左侧