二分查找,猜数游戏及其实现

本文介绍二分查找,并使用C++进行实现

二分查找

二分查找也称为折半查找,即每次查找的时候都从中间位置去查找,其要求线性表必须是顺序存储的(数组)结构,而且顺序表中的元素是有序排列的。

如下图就是一种满足折半查找要求的存储结构:
在这里插入图片描述

二分查找的步骤

我们令表中元素按升序排列,则二分查找的步骤为:

  • 将中间位置的记录与给定数据进行比较,如果相等,则查找成功
  • 否则使用中间位置将表分为两个子表
  • 若给定数据大于中间位置元素,则从中间位置以后到结尾位置构成的子表中进行二分查找
  • 若给定数据小于中间位置元素,则从开始位置到中间位置构成的子表中进行二分查找
  • 重复以上过程,若找到,则查找成功;若查找到子表不存在,则给定数据不在表中

我们以在有序表8,12,20,68,76,89,91,120,155查找68为例子对以上过程进行说明(图中s表示开始查找的位置,e表示结尾查找的位置,mid表示中间位置,我们令 m i d = ⌊ ( s + e ) / 2 ⌋ mid=\lfloor (s+e)/2\rfloor mid=(s+e)/2):

  1. 表长为9,中间位置为4,将68与第4号的数据进行比较,不相等,68小于76,在左边子表中进行查找:e变为3
    在这里插入图片描述
  2. 表长为4,中间位置为1,将68与第1号元素进行比较,不相等,68大于12,在右边子表中进行查找,s变为2
    在这里插入图片描述
  3. 表长为2,中间位置为2,将68与第2号元素进行比较,不相等,68大于12,在右边子表中进行查找,s变为3
    在这里插入图片描述
  4. 表长为1,中间位置为3,将68与第3号元素进行比较,相等数据找到,返回数据位置
    在这里插入图片描述

以上查找过程通过4次查找到了想要查找的数据

二分查找的C++实现

以上例子中查到例子的代码如下:

#include <iostream>
using namespace std;
int s,e;
int bin_search(int arr[],int s,int e,int data){
    if(s<=e){
        int mid=(s+e)/2;
        if (arr[mid]==data){
            return mid;
        }else if(data<arr[mid]){
            e=mid-1;
            bin_search(arr,s,e,data);
        }else{
            s=mid+1;
            bin_search(arr,s,e,data);
        }
    }else{
        return -1;
    }
}
int main(){
    int arr[]={8,12,20,68,76,89,91,120,155};
    s=0,e=8;
    cout<<"place="<<bin_search(arr,s,e,68);
    return 0;
}

代码运行结果为:

place=3

猜数游戏

通过对二分查找的过程分析我们发现,对于一个数 n n n,我们采用二叉查找最多需要查找 ⌊ l o g 2 n ⌋ + 1 \lfloor log_2n \rfloor+1 log2n+1次便可以找到该数。

那么假如有一个1000以内的一个数,我们最多需要比较10次就可以找到这个数,让我们换种玩法:

让别人先心里默念1000以内的一个数,我们通过让这个人人说出与自己心里想的大小关系来猜数,在10次以内我们必然猜到他心里想的数。

比较过程与查找类似,我们直接上代码:

#include <iostream>
#define Num 1000
using namespace std;
int choice,s,e,judge;
int arr[Num];
int guess(int s,int e){
    if(s<=e){
        cout<<"是"<<arr[(s+e)/2]<<"吗(1.是2.不是)?";
        cin>>judge;
        if(judge==1){
            cout<<"哈哈哈,被我猜到了吧!"<<endl;
        }else if(judge==2){
            cout<<"大了还是小了?(1.大了2.小了)";
            cin>>choice;
            switch(choice){
            case 1:
                e=(s+e)/2-1;
                guess(s,e);
                break;
            case 2:
                s=(s+e)/2+1;
                guess(s,e);
                break;
            default:
                cout<<"输入有误,继续猜啊!\n";
                guess(s,e);
            break;
        }
        }else{
            cout<<"输入有误,继续猜啊!\n";
            guess(s,e);
        }
    }else{
        cout<<"撒谎了还怎么玩游戏呢!\n"<<endl;
    }
}
int main(){
    for(int i=0;i<Num;i++)arr[i]=i+1;
    s=0,e=999;
    guess(s,e);
    return 0;
}

让我们猜个999玩一玩,猜的过程(运行结果)如下:

是500吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是750吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是875吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是938吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是969吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是985吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是993吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是997吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是999吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是1000吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
撒谎了还怎么玩游戏呢!

可以看到我们在第九步猜到了

才疏学浅,难免有错误和不当之处,欢迎交流批评指正!
同时有问题的话欢迎留言或邮箱联系(ljt_IT@163.com)。

创作不易,觉得写得不错就微信扫码奖励一下吧!

Reward

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值