来看看标准的二分查找,复杂度O(lgn)
int BinarySearch(const int *a,int low,int high,int key){
int mid;
while(low <= high){ //注意这里是 <=,在low跑到跟high回合的时候还在进行,直到low>high
mid = low + (high-low)>>1; //防止( low + hign ) 会发生溢出
if(a[mid] == key){
return mid;
}else if(a[mid]<key){
low = mid + 1;
}else
hign = mid - 1;
}
return low;
}
现在来看看,什么是循环递增数组,如A[]={ 17 19 20 25 1 4 7 9} 就是个循环递增数组,那在这样的一个区间中寻找某个key,怎样操作,看看标准的二分是怎样做的,先知道mid所在的元素,然后让key跟mid所在元素比较,因为总能保持low所在元素比mid小,high所在元素比mid大,但是在循环递增数组中是不会保持这样的性质的(在某些情况下是会保持),这样寻找的key的位置就有这样几种可能:
(1)key将前后的数组分成两部分,key刚好是第一部分的最后元素,这样整个数组还是循环递增的
(2)key将落在原来数组的第二部分,这样整个数组以key为准,又分割成了一个循环递增数组,前面循环递增后面严格递增
(3)key将落在原来数组的第一部分,这样以key为准,分割成了循环递增数组,前面严格递增后面循环递增
比如上面的数组中,如果查找20,那么前17 19 是个严格的递增数组和后面 25 1 4 7 9 就又是个循环递增数组
如果查找19,那么前17 和后面的 20 25 1 4 7 9也满足上述性质
如果查找4,那么前面的是个循环递增数组和后面的严格递增数组
所以循环递增数组就有个这样的性质:key将数组分割成两部分,一部分要么是循环递增,另一部分要么是严格递增,或者相反(针对升序数组)
所以在写的时候就要在原来二分的基础上加点条件:
设要查找的元素是key,数组的首元素是a[low],中间元素是a[mid],最后一个元素是a[high],当a[mid]!=key时:
(1)当a[low]<a[mid]说明前半部分是严格递增的,那么后半部分就是循环递增的,如果a[key]<a[mid]&&a[key]>=a[low],那就key就落在前半部分,否则就在后半部分的循环递增数组中。
(2) 当a[mid]<a[high] 那么前半部分就是循环递增,后半部分就是严格递增的,那么a[key]>a[mid] && a[key]<=a[high],那key就落在后半部分,否在就在前半部分的循环递增数组中。根据这样的思路写出代码:
// 改进后的二分搜索
int Search(int A[],int n, int num)
{
int left = 0 ;
int right = n - 1 ;
int mid = 0 ;
int pos = -1 ;
while(left <= right)
{
mid = (left + right)/2 ;
if (A[mid] == num)
{
pos = mid ;
break;
}
if (A[left] <= A[mid]) //前半部分是严格递增的,后半部分是一个更小的循环递增数组
{
if(A[left] <= num && num < A[mid] )
{
right = mid - 1 ;
}
else
{
left = mid + 1 ;
}
}
else //后半部分是严格递增的,前半部分是一个更小的循环递增数组
{
if ( A[mid] < num && num <= A[right])
{
left = mid + 1 ;
}
else
{
right = mid - 1 ;
}
}
}
return pos;
}
所以循环递增数组的核心还是在怎样寻找合适的low和high,而不是平常的二分的low=mid+1或者hign = mid-1.
以下给出一个完整的在循环递增数组中查找元素的例程:
<pre name="code" class="cpp" style="color: rgb(51, 51, 51); font-size: 14.399999618530273px; line-height: 26px;">#include<iostream>
using namespace std;int findPos(int *arr,int key,int low,int high){int pos = -1;// if can't find the element,return -1 reprement no find
int mid;
while(low <= high){
mid = (low+high)/2;
if(arr[mid]==key){
pos = mid;
break;
}
if(arr[low]<=arr[mid]){ // the first part is gradually increase
if(arr[mid]>key && arr[low]<=key ) high = mid-1;
else low = mid+1;
}else{
if(arr[mid]<key && arr[high]>=key) low = mid +1;
else high = mid -1;
}
}
return pos;
}
int main(){
int arr[]={17,19,20,25,1,4,7,9};
cout<<findPos(arr,19,0,7)<<endl;
return 0;
}
-- INSERT --