pat每日刷题计划--day70

二分法

  • binarySearch找的是出现在a数组中的,数值等于num的数的下标。(有多个的时候是随机的输出了一个)
  • lowerbound找的是在a数组中出现的第一个,数值大于等于num的数的下标
  • upperbound找的是a数组中出现的第一个,数值大于num的数的下标

找具体的某个数,是使用mid进行判断,而另外的两个是使用的left和right夹逼。

也正是因此,根据定义可以判断,在binarySearch中,不是对应返回值的a[mid]里面一定不包含正确答案,所以在转移的过程中不需要带上mid

在递增序列里面,binarySearch在a[mid]变迁:

  • a[mid]==num ----> return mid
  • a[mid]>num  ----> right=mid-1
  • a[mid]left=mid+1
  • 判定条件:left<=right,(只要mid,left,right都是合法的就有可能,因此需要带上等号)

而在lowerbound中,最终的一个位置是left==right,然后返回left的下标,在走完数组之前,并不知道当前的位置是真正的第一个。

  • a[mid]>=num  ----> 结果一定在[left,mid]中,right=mid
  • a[mid]可以确定mid处是不可能的,所以left=mid+1
  • 循环条件:left

在upperbound中,最终也是left==right

  • a[mid]>num ---->结果一定在[left,mid]中,right=mid
  • a[mid]<=num ---->mid是不在范围内的,left=mid+1
  • 循环判定:left<=right,最终以left=right退出循环

lowerbound和upperbound都可以被称为:寻找有序序列中第一个满足某条件元素的位置,只要设置好对应的边界判定就可以完成转换

binarySearch对应的判断问题是:判断一个有序序列中是否存在某个元素,如存在找出位置

#include
#include
#include<string.h>
using namespace std;
int binarySearch(int a[],int left,int right,int num)//找出num在a数组的位置
{
    int mid=(left+right)/2;
    while(left<=right)
    {
        mid=(left+right)/2;
        if(a[mid]==num)
            return mid;
        if(a[mid]>num)
            right=mid-1;
        else
            left=mid+1;
    }
    return -1;
}
int lowerbound(int a[],int left,int right,int num)//找出大于等于num的第一个数在a数组的位置
{
    int mid=(left+right)/2;
    while(left<right)
    {
        mid=(left+right)/2;
        if(a[mid]>=num)
        {
            right=mid;
        }
        else
            left=mid+1;
    }
    return left;
}
int upperbound(int a[],int left,int right,int num)//找出第一个大于num的数在a数组中的位置
{
    int mid=(left+right)/2;
    while(left<right)
    {
        mid=(left+right)/2;
        if(a[mid]>num)
            right=mid;
        else
            left=mid+1;
    }
    return left;
}
int main()
{
    int n=5;
    int a[15]={1,3,3,3,6};
    /*for(int i=0;i*/
    printf("%d\n",binarySearch(a,0,n-1,3));
    printf("%d\n",lowerbound(a,0,n-1,3));
    printf("%d\n",upperbound(a,0,n-1,3));
    return 0;
}
View Code

 二分法求根号2近似(精确到1e-5)

注意这里面具体数字,直接等于mid就行,不用加减

left和right对应的是根号2的范围,然后mid*mid对应的是根号2平方以后的范围。

(比如换成根号3,left和right还是1和2(根号三大于1小于2),mid*mid是对应的3)

#include
#include
#include<string.h>
using namespace std;
int main()
{
    double left=1;
    double right=2;
    double eps=1e-5;
    double mid=(left+right)/2;
    while(right-left>eps)
    {
        mid=(right+left)/2;
        if(mid*mid==2)
        {
            printf("%f",mid);
        }
        if(mid*mid>2)
            right=mid;
        else
            left=mid;
    }
    printf("%f",mid);
    return 0;
}
View Code

 

你可能感兴趣的:(pat每日刷题计划--day70)