二分搜索总结

编程之美上有节说各种二分的查找,于是便写了下,并给出了一些测试代码

1)二分查找元素key的下标,如无 return -1


2)二分查找返回key(可能有重复)第一次出现的下标,如无return -1

3)二分查找返回key(可能有重复)最后一次出现的下标,如无return -1

4)二分查找返回刚好小于key的元素下标,如无return -1

5)二分查找返回刚好大于key的元素下标,如无return -1

写中间有一些需要注意的地方,都在代码中写了,关键还是要处理好边界问题,下面是代码

#include <cstdio>
#include <cmath>  
#include <cstdlib>  
// 1.二分查找元素key的下标,如无 return -1
int binarySearch( int *arr, int fisrt, int last, int key )
{
//	 err check
// 	if ( arr == NULL || fisrt > last )
// 		return -1;
	// 注意查找的范围 
	// 左闭右开、左闭右闭
	int low = fisrt;
	int upper = last;
	while ( low <= upper )
	{
		int m = low + (( upper - low ) >> 1);
		if ( arr[m] == key ) 
			return m;
		else if ( arr[m] < key )
			low = m + 1;   // 此处因为搜索区间所以是 m+1
		else 
			upper = m - 1; // 此处因为搜索区间所以是 m-1
	}
	return -1;
}
// 2)二分查找返回key(可能有重复)第一次出现的下标,如无return -1
int getFirstIndexOfKey( int *arr, int fisrt, int last, int key )
{
	//	 err check
	// 	if ( arr == NULL || fisrt > last )
	// 		return -1;
	int low = fisrt;
	int upper = last;
	while ( low <= upper )
	{
		int m = low + (( upper - low ) >> 1);
		// 此处的关键是怎么处理 arr[m] == key
		// 举个例子:1 1 2 2 3
		//     下标:0 1 2 3 4
		//        m = ( 0 + 4) / 2 = 2;
		//    此时 arr[2] == 2,那么此时应该明确前面是否有2了,
		//    接着 求 [0,1] 中是否有2了,假如没有了,那结束的时候,low == upper + 1,此时查看low处是否是2,是则返回
		if ( key <= arr[m] )
			upper = m - 1;   // 当arr[m] == key 时,则 位置m 可能是第一次出现的下标
		else 
			low   = m + 1;
	}

	if ( low <= last && arr[low] == key )
		return low;
	else 
		return -1;
}
//3)二分查找返回key(可能有重复)最后一次出现的下标,如无return -1
// 关键是处理arr[m] == key时怎么办,此时应该是找 [m+1,upper]里面是否有key了
// 当没有时候时候,此时结束条件是upper=m,故此时判断是否arr[upper] == key
int getLastIndexOfKey( int *arr, int fisrt, int last, int key )
{
	int low   = fisrt;
	int upper = last;
	while ( low <= upper )
	{
		int m = low + (( upper - low ) >> 1);
		if ( key >= arr[m] )
			low = m + 1;
		else 
			upper = m - 1;
	}
	if ( upper >= fisrt && arr[upper] == key )
		return upper;
	else 
		return -1;
}

//4)二分查找返回刚好小于key的元素下标,如无return -1
// 分几种情况考虑
// 1.假设[low,upper]中有数等于key,即arr[m] == key
// 则此时应该找 [low,m-1],并假设此时是最后一个  arr[m] == key,则此时[low,m-1] < key,结束条件是low==m,返回upper即可
// 2.假设[low,upper]没有key即,arr[low]<key<arr[uperr],则必然缩小到最后有 low + 1 = upper,此时结束时返回upper
// 3.特殊情况考虑:key < [low,upper] , 则结束时 upper < low,返回-1
// [4.low,upper] < key, 则结束时,low >upper,返回upper
int binarySearchJustSmaller( int *arr, int fisrt, int last, int key )
{
	int low   = fisrt;
	int upper = last;
	while( low <= upper )
	{
		int m = low + (( upper - low ) >> 1);
		if ( key <= arr[m] )
			upper = m - 1;
		else 
			low = m + 1;
	}
	if ( upper >= fisrt || arr[upper] < key )
		return upper;
	else
		return -1;
}
// 5)二分查找返回刚好大于key的元素下标,如无return -1
// 分几种情况 
// 1.假设[low,upper]中有数等于key,即arr[m] == key,则查找[m+1,upper],返回low即可
// 2.假设[low,upper]没有key即,arr[low]<key<arr[uperr],则必然缩小到最后有 low + 1 = upper,此时结束时返回low
// 3.特殊情况考虑:key < [low,upper] , 则结束时 upper < low,返回low
// [4.low,upper] < key, 则结束时,low >upper,返回-1
int binarySearchJusBigger( int *arr, int fisrt, int last, int key )
{
	int low   = fisrt;
	int upper = last;
	while( low <= upper )
	{
		int m = low + (( upper - low ) >> 1);
		if ( arr[m] <= key )
			low = m + 1;
		else 
			upper = m - 1;
	}
	if ( low <= last || arr[low] > key )
		return low;
	else
		return -1;
}

#define GetSize(arr) ( sizeof arr / sizeof arr[0])


void Test( char *name, int *arr, int size, int key, int *index )
{
	if ( name != NULL )
		printf("===============%s begin===================\n",name);

	if ( binarySearch(arr,0,size-1,key) == index[0] )
		printf("binarySearch passed.\n");
	else
		printf("	binarySearch failed.\n");

	if ( getFirstIndexOfKey(arr,0,size-1,key) == index[1] )
		printf("getFirstIndexOfKey passed.\n");
	else
		printf("	getFirstIndexOfKey failed.\n");

	if ( getLastIndexOfKey(arr,0,size-1,key) == index[2] )
		printf("getLastIndexOfKey passed.\n");
	else
		printf("	getLastIndexOfKey failed.\n");

	if ( binarySearchJustSmaller(arr,0,size-1,key) == index[3] )
		printf("binarySearchJustSmaller passed.\n");
	else
		printf("	binarySearchJustSmaller failed.\n");

	if ( binarySearchJusBigger(arr,0,size-1,key) == index[4] )
		printf("binarySearchJusBigger passed.\n");
	else
		printf("	binarySearchJusBigger failed.\n");

	if ( name != NULL )
		printf("===============%s end=================\n",name);
}
// 常规测试
void Test1()
{
	int arr[] = {1,2,3,4,5};
	int size = GetSize(arr);
	int index[] = {0,0,0,-1,1};
	Test("test1",arr,size,1,index);
}

void Test2()
{
	int arr[] = {1,2,3,4,5};
	int size = GetSize(arr);
	int index[] = {1,1,1,0,2};
	Test("test2",arr,size,2,index);
}

void Test3()
{
	int arr[] = {1,2,3,4,5};
	int size = GetSize(arr);
	int index[] = {4,4,4,3,-1};
	Test("test3",arr,size,5,index);
}
// 全都一样时
void Test4()
{
	int arr[] = {1,1,1,1,1};
	int size = GetSize(arr);
	int index[] = {2,0,4,-1,-1};
	Test("test4",arr,size,1,index);
}
// 都大
void Test5()
{
	int arr[] = {1,2,3,4,5};
	int size = GetSize(arr);
	int index[] = {-1,-1,-1,-1,0};
	Test("test5",arr,size,0,index);
}
// 都小
void Test6()
{
	int arr[] = {1,2,3,4,5};
	int size = GetSize(arr);
	int index[] = {-1,-1,-1,4,-1};
	Test("test6",arr,size,6,index);
}

void Test7()
{
	int arr[] = {1,2,4,5,6};
	int size = GetSize(arr);
	int index[] = {-1,-1,-1,1,2};
	Test("test7",arr,size,3,index);
}
int main()
{
	Test1();
	Test2();
	Test3();
	Test4();
	Test5();
	Test6();
	Test7();

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值