有序数列的二分查找问题
二分查找也叫折半查找,它是一种比较高效的查找方法,相比于顺序查找O(n)的时间复杂度来说,其时间复杂度O(log2n)占很明显的优势。
但是并不是所有的数列都可以用二分查找的方法,二分查找要求所给的数列必须是有序的,即是按顺序结构在计算机中存储的,并且必须按关键字的大小有序排列。以整型数据为例,找到了返回该元素的下标,下面来介绍具体的实现方法:
在此之前,我们需要将有序的一组数据存储到数组中,创建arr数组来存放若干个要存放的有序数,我们要将数组折半,就需要得到数组中间元素的下标,要知道中间元素的下标,我们就得知道数组最左边元素的下标和最右边元素的下标,设左下标为 left ,右下标为 right ,显然 left =0 , right =数组元素个数 - 1,数组元素个数 sz = sizeof(arr) / sizeof(arr[0]) ,我们再取左右下标的平均值为中间下标 mid ,万事俱备,接下来进行下一步操作。
首先,我们得到 mid = (left + right) ,将数组下标为 mid 的元素与要查找的数 k 进行比较:
1、arr[mid] < k
中间元素小于要查找的数,说明要查找的数在中间数的右边,所以中间数左边的内容可以舍弃,此时取中间下标右边的数组为下一轮要操作的数组, 令 left = mid +1 , right 不变。
2、 arr[mid] > k
中间元素大于要查找的数,说明要查找的数在中间数的左边,所以中间数右边的内容可以舍弃,此时取中间下标左边的数组为下一轮要操作的数组,令 right = mid - 1, left 不变。
3、 arr[mid] = k
此时 k 被找到, mid 即为其下标。
上面的操作只是一轮,当 left 和 right 不停的在变化,此时就需要循环,当 left < right 时,循环是可以执行的,但是我们要注意,在执行最后一次循环时,可能会出现 left = right =mid 的情况,所以循环条件应该为 left <= right 。
若跳出了循环还没有找到 k ,则数组里找不到这个数。
#include<stdio.h>
int main()
{
int k=7; //要查找的数字
int arr[]={
1,2,3,4,5,6,7,8,9,10};
int left,mid,right;
int sz = sizeof(arr)/sizeof(arr[0]);
left = 0;
right = sz -1;
while(left<=right)
{
//mid = (left+right)/2; 可能会有溢出风险
mid = left + (right - left)/2;
if(arr[mid] < k)
{
left = mid +1;
}
else if(arr[mid] > k)
{
right = mid -1;
}
else
{
printf("找到了,下标是%d\n",mid);
}
}
if(left > right)
{
printf("找不到\n");
break;
}
return 0;
}