前几篇文章写了排序和排序相关的几个简单易懂的算法。
查找,是和排序密不可分的一个话题。
一般而言,排序之后才能完成查找.如果没有排序,那必须至少把所有数据都遍历一遍才能完成查找,否则将无法保证没有遗漏元素。常见的查找算法是二分查找。
使用二分查找的前提是,待查找的数组必须已经完成了排序。
int binary_search(int* arr, int st, int ed, int number)
//arr代表待查找的数组的地址,注意这个数组必须已经排好序了。st代表数组的起始位置的下标,ed代表数组的结束位置的下标,number代表带查找的数字。
{
// The array should be sorted
int mid=0;
while(st<=ed)//注意不能写成st<ed,否则会漏掉最后只剩一个元素的情况,比如,将无法通过测试案例:{0,2}中查找2的测试案例,{2}中查找2和测试案例
{
mid = st + (ed-st)/2;//避免(st+ed)/2这种写法可能造成的溢出。
if(arr[mid]<number)
{
st = mid+1;
}
else if(arr[mid]>number)
{
ed = mid-1;
}
else
{
return mid;
}
}
return -1;
}
它的main函数如下
int main()
{
int sorted_arr[10]={4,6,9,11,12,27,27,27,29,30};
std::cout<<binary_search(sorted_arr, 0, 9, 27)<<std::endl;
}
输出结果:7
也就是说,27位于数组中的第5,6,7位,二分查找输出结果为第7位。现在略微增加一个要求,如果当待查找的数字在数组中有多个时,指定输出第一次出现的数字,该如何改写呢?可以这样改写,
int binary_search(int* arr, int st, int ed, int number)
{
// The array should be sorted
int mid=0;
while(st<=ed)
{
mid = st + (ed-st)/2;
if(arr[mid]<number)
{
st = mid+1;
}
else if(arr[mid]>number)
{
ed = mid-1;
}
else
{
int temp = mid - 1;
/**当数组中有多个待查数字时,找到最小的index**/
while(arr[mid] == arr[temp])
{
temp--;
mid--;
}
/**当数组中有多个待查数字时,找到最小的index**/
return mid;
}
}
return -1;
}
最近又写了写二分查找,这次写的是递归版本了。使劲儿do search work进行了一个100% bug free和效率优化的过程。
int binary_search(int* array,int left, int right, int key) {
if(left<=right){ //注意① if条件不能少。
int mid=left+((right-left)>>1);//注意② 这样的写法和"int mid=(left+right)/2"相比,不仅能够避免溢出,而且能够提高效率(右移高于除法)。
if(array[mid]<key)
return binary_search(array, mid+1, right, key);
else if(array[mid]>key)
return binary_search(array, left, mid-1, key);
else
return mid; //注意③ 把相等的情况放在最后是因为相等的情况比不等的情况更少见。
}else{
return -1; //注意④ 若找不到key,在这里处理。
}
}