二分查找算法

要解决的问题:

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的左侧

 

 

 

 

 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值