二分查找的进一步学习

(本博客基于算法笔记)
算法笔记中有一句话“二分查找的过程与序列的下标从0还是从1开始无关”,我一开始觉得这句话明显有误,毕竟一个数组,如果是从1开始岂不是少了一个数字?我觉得作者在这里应该指的是,有些人使用的数组,习惯从1开始存储,有的人习惯从0开始,我们的重点不应该放在下标上,而是放在数组的起始位置上(这就是我的理解)

第一版本:

void BinarySearch(int A[],int left,int right,int x)
{
    int mid;//left和right的中点
    while(left<=right)
    {
        mid = (left+right)/2; //两个int类型的数字相除,直接省去小数部分
        //mid = left+(right-left)/2
        if(A[mid]==x)
        {
            printf("%d",mid);
            exit(0);
        }
        else if(A[mid]>x)
            right = mid -1;
        else
            left = mid+1;
    }
    printf("查找失败\n");
}

如果数组过大,mid值就有可能越界,所以设置
mid = left + (right-left)/2

第二版本

如果递增序列A中存在重复元素,X为待查询元素,目的是找到序列中第一个大于等于X的位置与第一个大于X的位置,这两个位置构成一个集合[L,R},此集合中全部都是X数值。
先看第一个问题,第一个大于等于X的位置,问题发生了改变,即使是序列中没有X元素,那么也应该返回位置n。
所以循环的条件变成了 while(left 第二个问题,第一个大于X的位置,修改if语句中的条件即可。
我们就得到一个固定的查找模板

int solve(int left ,int right)
{
int mid;
while(left+1

二分查找的拓展

牛顿迭代法:
各种函数
木棒切割问题:
给出几根木棒的长度,然后给出切割的数目,求切割的最大长度是多少
一开始我没有动脑筋,直接设置

int left = *min_element(A,A+n);
int right = 0;
int mid = (right+left)/2

这当然是错误的,寻找切割的最大长度应该是一个“在一个递减序列中,找到第一个满足要求的数值位置”。当然也可以直接就查找:

void test5()
{
    int n;//木头的数目
    scanf("%d",&n);
    int A[n];
    for(int i =0;i0)
    {
        int result=0;
        for(int i =0;i=k)
        {
            printf("找到最大长度为%d",left);
            exit(0);
        }
        else
            left=left-1;
    }
    printf("找不到满足题意的解");
}

木棒分割怎么着都会有解的,这个代码其实有点问题。
结合前文,代码应该修改为:

void test5()
{
    int n;//木头的数目
    scanf("%d",&n);
    int A[n];
    for(int i =0;i=k)
        {
            left = mid;
        }
        else
            right = mid;
    }
    printf("%d",mid);
}

while的终止条件尤其值得注意。

快速幂

递归思想的求幂算法。
这里插一个小知识:
typedef:
如果放在所有函数之外,它的作用域就是从它定义开始直到文件尾;
如果放在某个函数内,定义域就是从定义开始直到该函数结尾;
#define:
不管是在某个函数内,还是在所有函数之外,作用域都是从定义开始直到整个文件结尾。

快速幂当然就是递归的思想,以a^10为例:
a^10 = a ^ 5 * a ^ 5
a ^ 5 = a * a ^ 4
a ^ 4 = a ^ 2 * a ^ 2
a ^ 2 = a ^ 1 * a ^ 1
a ^ 1 = a * a ^ 0(虽然是句废话,但是在编程的时候就不是废话了)

long long test6(long long a,long long b,long long m)
{
    if(b==0)
        return 1;// a ^ 0 = 1;
    if(b & 1)//位与操作,执行速度更快
        return a*test6(a,b-1,m);
    else
    {
        long long mul = test6(a,b/2,m);
        return mul*mul%m;  //因为题目是求a^b%m,如果只是求幂就需要更改。
    }
}

而快速幂的迭代写法,可以这样理解:
a ^13 = a ^ 8 * a ^4 * a ^ 1
要求必须使用二进制来表示;

//快速幂的而迭代写法
long long test6(long long a,long long b,long long m)
{
    //把迭代写法理解成a进制与十进制的转换即可
    //这个需要使用二进制
    long long ans = 1;
    while(b>0)
    {
        if(b & 1)
        {
            ans = ans *a %m;
        }
        a = a*a %m;
        b>>1;
    }
    return ans;
}

你可能感兴趣的:(随笔流水账)