想要在一个有序数组中中查找某个具体的数字,可以先在主函数里实现,再将查找功能封装在一个函数里,该功能采用折半查找法。
折半查找原理
假设有一有序数组v[1,2,3,4,5,6,7,8,9,10],共有十个元素,下标分别为0~9。
建立两个变量left和right,分别等于该数组的第一个元素的下标和最后一个元素的下标。
再给出一个变量mid=(v[left]+v[right])/2,与要查找的数字x作比较,如果x>r[mid],则表明x的可能存在范围缩小到r[mid+1]与r[right之间],若x<r[mid],它的可能存在范围就是r[left]到r[mid-1]之间。再让x与这个新的范围的中值比较,直到最后得出结果。
在上述的数组中,初始化赋值left=0,right=9,mid=(0+9)/2=4(因为mid设置为int类型,只能是整数,所以编译器算出的结果是4),就可以知道v[mid]=v[4]=5。
假设我们输入的想要查找的数字x为6,6>5,可以得到新的x范围在v[5]到v[9]之间。
将left置为mid+1,right保持不变,新的mid=7,v[mid]=v[7]=8,6<8,x就在v[5]到v[6]之间。
right置为mid-1=6,新的mid=6,x=mid,就可以打印“找到了”。
但如果输入的x并不在这个数组里,应该怎么停止这个查找的循环体呢?我们可以通过(left<=right)来判断,满足条件进入循环,否则跳出。假设我们要查找数字11,经过几次循环,left和right都指向10,11将与数组最大的数字10相比,发现11>10,left+1=11,right=10,这时left>right,打印“找不到”的结果,跳出循环。
在主函数里查找
#include<stdio.h> //引输入输出的头文件
int main()
{
int v[]={1,2,3,4,5,6,7,8,9,10}; //有序数组
int x=0;
int n=sizeof(v)/sizeof(v[0]);
int left=0; //初始化为数组的左下标
int right=n-1; //初始化为数组的右下标
int mid=0;
printf("请输入要查找的数字:");
scanf("%d",&x);
while(left<=right)
{
mid=(left+right)/2;
if(x<v[mid])
{
right=mid-1;
}
else if(x>v[mid])
{
left=mid+1;
}
else if(x==v[mid])
{
printf("找到了,下标是%d\n",mid);
break;
}
else
{
if(left > right)
printf("找不到\n");
}
}
return 0;
}
函数实现查找
#include<stdio.h>
//查找函数,括号里的是形参,从主函数中传过来进行计算
//这里的v[]本质上是一个指针,指向v数组的第一个元素即v[0],所以这里也可以把v[]写成*v
int binsearch(int x,int v[],int n)
{
int left=0;
int right=n-1;
int mid=0;
while(left<=right)
{
mid=(left+right)/2;
if(x<v[mid])
{
right=mid-1;
}
else if(x>v[mid])
{
left=mid+1;
}
else if(x==v[mid])
{
return mid; //找到x时,把mid的值也就是x的下标传回主函数
}
else
return -1; //没找到时返回-1
}
}
int main()
{
//初始化
int v[]={1,2,3,4,5,6,7,8,9,10};
int x=0;
int ret=0;
int n=sizeof(v)/sizeof(v[0]);
//输入x
printf("请输入要查找的数字:");
scanf("%d",&x);
//引用查找函数
ret=binsearch(x,v,n); //括号里的是实参,因为计算需要x,n以及v数组的值
//注意这里数组的实参只要给出数组名,如果写成v()编译器会报错
if(ret==-1) //函数执行完返回-1
printf("找不到");
else //返回其他值也就是mid
printf("找到了,下标是%d",ret);
return 0;
}