您的位置:首页 > 编程语言

二分搜索总结

2013-08-11 09:54 232 查看
编程之美上有节说各种二分的查找,于是便写了下,并给出了一些测试代码

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息