首先介绍最基本的,所谓二分法就是把数组的元素砍成两半进行查找,前提是必须是有序数组。
时间复杂度为O(logn)。相比于遍历数组逐项查找,时间复杂度更低。
二分法需要左,中,右三项,通过用中间项对比被查找数字,判断是从左边还是从右边缩小范围(详见代码)
#include "stdio.h"
int cmp(const void*e1,const void *e2)//排序
{
return *((int *)e1)-*((int *)e2);
}
int search(int m,int *num,int N)
{
int right=0,left=N-1;
while(right<=left)//当左边等于右边的时候查找就结束了
{
int mid=(right+left)/2;
if(m<num[mid])//中间项大于被查数说明中间项在靠右边
left=mid-1;//缩小左边的范围
else if(m>num[mid])//中间项小于说明他在靠左边
right=mid+1;//从右边缩小范围
else return mid;//找到了返回
}
return -1;//查找结束,没有返回数字
}
int main()
{
int n;
printf("请输入数字的个数\n");
scanf("%d",&n);
int num[n];
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);//读入数组
}
qsort(num,n,sizeof(num[0]),cmp);//进行递增排序
int m;
printf("请输入需要查找的数字m\n");
scanf("%d",&m);
int a=search(m,num,n);//进行查找
if(a==-1)
printf("没有数字");
else
printf("%d",a);
}
二分法查找范围 eg:要在一个数组中查找一个数的所处的范围(数组中可能会含有重复的数字)
查找范围意味着有左右区间,这里我们要求是左闭右开区间,要分为两个步骤,1是查找左区间,2是查找右区间。
查找左区间
int searchleft(int m,int *num,int N)
{
int left=0,right=N-1;
while(left<right)
{
int mid=(left+right)/2;
if(num[mid]>=m)
right=mid;
else
left=mid+1;
}
return left;
}
查找右区间
int searchright(int n,int *num,int N)
{
int left=0,right=N-1;
while(left<right)
{
int mid=(right+left)/2;
if(num[mid]>n)
right=mid;
else
left=mid+1;
}
return left;
}
(左边)这里面while的执行标志没有了“=”相比于查找数字,因为我们要的的是返回区间的左区间,找到了的情况是(也就是最后确定下来的值,直接返回的话就会有数字没有包含到)left=right,而查找的情况则是:只要找到了就返回,没找到就另外返回。确定右区间同理。
这里我们需要注意一个问题(以左区间为例):
int mid=(left+right)/2;
if(num[mid]>=m)
right=mid;
else
left=mid+1;
在写的时候我们可能会有疑问:问什么num[mid]不是>m而是>=m呢?
由此产生的代码如下
int mid=(left+right)/2;
if(num[mid]>m)
right=mid-1;
else
left=mid;
看上去好像很合理,的确在针对一部分数据时的确可以处理,但是有例外:如果left=4,right=5
则无法结束循环,因为mid始终等于4,始终执行else的语句。mid是整型的,他会忽略掉后面的小数点。
那如何解决这个问题呢?那就是不让else的条件中包含“=”这种情况(即不让left=mid执行),如第一段代码所示。
二分法的一个应用:快速幂
条件1:如果是偶数,那么有a^b=a^b/2 * a^b/2;
2: 如果是奇数,那么有a^b=a*a^(b-1);
#include "stdio.h"
long long bindarypow(int a,int b)
{
if(b==0)
return 1;
else if(b%2==0)
{
long long mul=bindarypow(a,b/2);//用mul把每一次的结果统计起来
return mul*mul;//a^b=a^b/2 * a^b/2;
}
else
return a*bindarypow(a,b-1);//a^b=a*a^(b-1);
}
int main()
{
int a,b;
printf("请输入底数a和指数b");
scanf("%d %d",&a,&b);
long int sum=bindarypow(a,b);
printf("%ld",sum);
}