二分法及其注意事项(查找数字,区间,快速幂)(C语言)

首先介绍最基本的,所谓二分法就是把数组的元素砍成两半进行查找,前提是必须是有序数组。

时间复杂度为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);
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值