题目
在旋转之后的已排序数组中查找一个数字
思路一
在已排序数组中查找一个数字我们知道用二分查找,此题目的难点在于中间数(mid)与查找数(key)的大小关系确定后,断点位置与要查找的范围的确定。
数组A 4 5 6 7 8 9 1 2 3
数组B 8 9 1 2 3 4 5 6 7
9 1 为断点位置,
当mid>key时
最简单的情况
当left < key 且 left < mid时,所查找数字在前半段,并且进入普通二分查找的模式
——如在 数组A 中查找 5
除去可跳转的情况,剩下key在断点一侧,断点分别在mid前后两种情况
此时若 left > mid ,断点在前。
——如在 数组B 中查找 1。
否则断点在后。
——如在 数组A 中查找 2。
当mid
写代码
先写普通二分查找
在一定条件下,旋转数组的查找会跳转到普通二分查找,先写出来不会错。
判断其中一个分支中跳转普通二分的条件
确定断点/key位置
另一个分支就简单了
left和right(对应值的调整方式)互换
大于小于互换
最后,没找到,返回-1
代码
int turned_binary_search(const int a[], size_t num, int key)
{
assert(a);
int left = 0;
int right = num - 1;
while (left <= right)
{
int mid = (left + right) >> 1;
if (a[mid] == key)
return mid;
else if (a[mid] > key)
{
if (a[left] == key){
return left;
}
else if (a[left] < key && a[left]<a[mid]){
right = mid - 1;
break;//跳转至普通二分查找,在后面
}
else if(a[left] > a[mid]){//left > key
right = mid - 1;
left++;
}
else{
left = mid + 1;
}
}
else//a[mid]<key
{
if (a[right] == key){
return right;
}
else if (a[right] > key && a[right] > a[mid]){
left = mid + 1;
break;//跳转至普通二分查找,在后面
}
else if(a[right] < a[mid]){
left = mid + 1;
right--;
}
else{
right = mid - 1;
}
}
}
while (left <= right)//二分查找
{
int mid = (left + right) >> 1;
if (a[mid] == key)
return mid;
else if (a[mid] > key)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return -1;
}
void text()//测试所有情况
{
int arr1[] = { 8, 9, 1, 2, 3, 4, 5, 6, 7 };
int arr2[] = { 4, 5, 6, 7, 8, 9, 1, 2, 3 };
int sz = sizeof(arr1) / sizeof(arr1[0]);
int i;
printf("search in arr1 { 8, 9, 1, 2, 3, 4, 5, 6, 7 }\n");
for (i = 0; i <= sz+1; i++){
printf("search %d ,reult : return %d\n", i, turned_binary_search(arr1, sz, i));
}
printf("search in arr2 { 4, 5, 6, 7, 8, 9, 1, 2, 3 }\n");
for (i = 0; i <= sz+1; i++){
printf("search %d ,reult : return %d\n", i, turned_binary_search(arr2, sz, i));
}
}
思路二
- 先判断断点在前在还是后
- 如果mid>left ,说明断点可能在后,否则断点在前
- 判断key是否在非断点区
- 如果key大于非断点区左边界小于右边界,key在非断点区,调整left或right,break进入普通二分查找。
- 否则调整边界继续循环
思路二代码
int turned_binary_search2(const int a[], size_t num, int key)
{
assert(a);
int left = 0;
int right = num - 1;
while (left<=right)
{
int mid = (left + right) >> 1;
if (a[left] < a[mid]){//断点在右
if (a[mid] == key)
return mid;
if (a[left] <= key && a[mid] > key){
right = mid - 1;
break;
}
else{
left = mid + 1;
}
}
else{//断点在左
if (a[mid] == key)
return mid;
if (a[mid] < key && a[right] >= key){
left = mid + 1;
break;
}
else{
right = mid-1;
}
}
}
while (left <= right)
{
int mid = (left + right) >> 1;
if (a[mid] == key)
return mid;
else if (a[mid] > key)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return -1;
}
void text3()
{
int arr1[] = { 8, 9, 1, 2, 3, 4, 5, 6, 7 };
int arr2[] = { 4, 5, 6, 7, 8, 9, 1, 2, 3 };
int sz = sizeof(arr1) / sizeof(arr1[0]);
int i;
printf("search in arr1 { 8, 9, 1, 2, 3, 4, 5, 6, 7 }\n");
for (i = 0; i <= sz+1; i++){
printf("search %d ,result : return %d\n", i, turned_binary_search2(arr1, sz, i));
}
printf("search in arr2 { 4, 5, 6, 7, 8, 9, 1, 2, 3 }\n");
for (i = 0; i <= sz+1; i++){
printf("search %d ,result : return %d\n", i, turned_binary_search2(arr2, sz, i));
}
}
int main()
{
text3();
return 0;
}