首页 > 其他 > 详细

二分查找

时间:2019-07-28 21:57:52      阅读:122      评论:0      收藏:0      [点我收藏+]

1.猜数

(以下故事纯属虚构,如有雷同,不胜荣幸)

小海:“小云,你现在心里想一个1000以内的数,信不信我最多只要问你十个问题,我就能猜出这个数是什么?”

小云:“真的么? 我不信。”

小海:“不信? 那就来试一试怎么样?”

小云:“哟,还来劲了,来啊。”

小海:“那现在给你十秒钟时间想这个数字。”

小云:“.......(沉默)”

小海:“10,9,8,...”

小云:“别点啦,我已经想好了。”

小海:“这么快啊,不多想会儿? 不然等下你又说我作弊。”

小云:“我.......(-_-||),快点开始吧。”

小海:“OK,那现在开始了,你想的数比500大吗?”

小云:“嗯,对,比500大。”

小海:“嗯,那好,这个数比750大吗?”

小云:“没有。”

小海:“比625大吗?”

小云:“没有呢。”

小海:“比562大吗?”

小云:“没有,你怎么老是问同样的问题,能不能换个有趣一点的。”

小海:“这个问题怎么就无趣了,继续,这个数比531大吗?”

小云:“没有,你不能换个有新意的问法吗? emmmmm”

小海:“奥,要有新意啊,那这个数比428加87更大吗?”

小云:“这。。。428加87.......,我...,等我算一下。”

小云:“428加87等于515,比515更大,你还是用原来的问法吧。-_—”

小海:“哈哈哈哈哈哈,你不是要有趣的问法吗,那这个数比523大吗?”

小云:“这个叫有趣...(小声),额,没有,比523更小。”

小海:“昂,就要接近真像了,这个数比519更大吗?”

小云:“嗯嗯,比他更大。”

小海:“这个数有比521更大吗?”

小云:“不会做真的能猜出来吧。。。(心想),嗯,没。”

小海:“这个数有比520更大吗?”

小云:“没有。(假装镇定)”

小海:“奥,这样啊。这个数是520”

(场面突然升温)

小云:“嗯呢,(3秒的沉默),520。”

(小海凝望着小云)

小海:“怎么样,我厉害吧。”

小云:“(石化4秒)?????????????????? 我 ..... , 你....(老娘话都到这儿了,你........)”

小海:“嘿嘿,想学吗??”

小云:“(死亡微笑)再见。”

(小云转身走了)

小海:“嗯? 喂! 不学就不学呗,干嘛走啊??? 我是说错了什么吗???(默默追上了小云)”

......

.....

....

...


2.情侣的毁灭能手:二分

不管你信不信,上面小海跟小云玩的小游戏就是二分查找的核心。

在这个游戏中,小云心中想的数其实就是我们要在有序数字序列中查找的x,而小海说的1000内任意数字其实就是序列的长度。

这个算法的核心思想就是不断地用当前序列区间中点的值value与x比较,若x比中间值value大,则在当前区间的右半区间继续查找x,否则在当前区间的左半区间查找,直到x被找出来。

每一次操作,都能减少当前区间一半的查找量。 这样也就使得查找的效率大大提高。

举个栗子:

假设有序数字序列a为: 1 5 14 21 29 31 34 35

需要查找的数x为: 14

假设该数字序列下标从1开始,则序列区间为[1,8]

设l为区间左端点,r为区间右端点。

初始情况l = 1, r = 8,中点mid = (l+r)/ 2 = (1+8)/ 2 = 4 (C语言中用int直接取整)

将中点的值a[mid] = a[4] = 21 与 x = 14进行对比

x < a[mid] 成立

则在当前区间的左半边进行查找,令l = l = 1,r = mid-1 = 3

那现在的区间是[1,3]

序列为:1 5 14

重复上述过程

mid = (l+r) / 2 = (1+3) / 2 = 2

a[mid] = 5

x = 14

x < a[mid] 不成立

x > a[mid] 成立

所以令l = mid + 1 = 3, r = r = 3

新缩小后的区间为[3,3]

序列为:14

mid = (l+r) / 2 = (3+3)/2 = 3

a[mid] = 14

x = 14

x < a[mid] 不成立

x > a[mid] 不成立

x == a[mid] 成立

令position = mid = 3

所以最后寻找得到x的位置是3


3.C语言代码

#include<stdio.h>

int main()
{
    int a[100],i,x,n;
    scanf("%d",&n);
    for(i = 1; i <= n; i++)
        scanf("%d",&a[i]);
    scanf("%d",&x);
    
    int l = 1,r = n,mid,pos = -1;
    
    do{
        mid = (l+r)/2;    //序列下标中点计算
        if(x < a[mid])
            r = mid-1;   // 缩小区间,在当前区间左边查找
        else if(x > a[mid])
            l = mid+1;   //在当前区间右边查找
        else {          //找到就退出循环
            pos = mid;
            break;
        }
    }while(l <= r);
    
    if(pos == -1)printf("Not find!\n");      //pos初始化的时候是-1,如果该变量没有被改变过,则序列中没有这个元素
    else printf("position is %d\n",pos);
    return 0;
}

该程序的输入是序列长度n,有序序列a,以及待查元素x。

二分查找

原文:https://www.cnblogs.com/bingdada/p/11260962.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!