题目:
对已排好序的数组A,一般来说可用二分查找可以很快找到。现有一特殊数组A[],它是循环递增的,如A[]={ 17 19 20 25 1 4 7 9},试在这样的数组中找一元素x,看看是否存在。请写出你的算法,必要时可写伪代码,并分析其空间、时间复杂度。
类似题目:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个排好序的数组的一个旋转,
输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
思路:
对于递增的数组A[],我们可采用二分法来查找,故空间复杂度为O(1),时间复杂度为O(lgn);而对于循环递增的数组A[],我们任可采用相似做法,首先我们可以确定数组A[]有至少一半是递增的,这个特性可以使我们采用分治法的原理来确定元素x。传入search(left,right)
计算mid = (left+right)/2得A[mid],
比较A[mid]大于等于A[left]值,说明mid左边是递增的,右边仍是循环递增。
比较A[mid]小于A[left]值,说明mid左边是循环递增的,右边仍是递增的。
此时根据A[mid],A[left],A[right]的可判断x是否属于递增的序列,采用二分法来查找,否则继续进入循环递增序列采用上述方法来查找。
虽然增加了两个变量,但空间复杂度仍为O(1),时间复杂度也仍为O(lgn).
程序实现:
#include<stdio.h>
#include<stdlib.h>
int binary_search(int x, int A[], int left, int right)
{
if(left > right)
return 0;
int mid = (left + right) / 2;
//printf("binary:%d\n", A[mid]);
if(A[mid] == x){
return 1;
} else if(A[mid] < x){
return binary_search(x, A, mid + 1, right);
}else{
return binary_search(x, A, left, mid - 1);
}
}
int search_method(int x, int A[], int left, int right)
{
if(left > right){
return 0;
}
if(left == right){
return A[left] == x ? 1 : 0;
}
int mid = (left + right) / 2;
if(A[mid] >= A[left]){
if(x <= A[mid] && x>= A[left]){
return binary_search(x, A, left, mid);
} else {
return search_method(x, A, mid + 1, right);
}
} else {
if(x >= A[mid] && x<= A[right]){
return binary_search(x, A, mid, right);
} else {
return search_method(x, A, left, mid - 1);
}
}
}
int main(void)
{
int A[] = {6,20,21,25,29,36,57,99,-10,-3,-2,0,2,4};
int i;
printf("A[]:");
for(i = 0; i < sizeof(A) /sizeof(A[0]) ; i++){
printf("%d ", A[i]);
}
printf("\n");
int x;
scanf("%d", &x);
if(search_method(x, A, 0, sizeof(A) /sizeof(A[0]) - 1) ){
printf("success search!!!");
} else {
printf("fail search!!!");
}
return 0;
}