小航猜数字 | 趣味C++课堂
看电脑怎么用最少的次数猜中你想的数字!
3大模块、12个知识点,标注重点
每次取搜索区间的中间值,根据反馈判断目标在左半还是右半区间,将范围缩小一半,重复直到找到目标。
"分而治之":把大问题不断拆成一半大小的小问题,每次排除一半的可能性。
查字典、找东西、快递分拣、电脑文件搜索,都是二分法思想的应用。
n个元素中查找,最多需要⌈log₂(n+1)⌉次。1-1000最多10次,1-100万最多20次。
while(true)条件永远为真,会一直执行循环体,必须用break才能跳出。适合"不知道循环多少次"的场景。
break语句立即终止当前循环,执行循环后面的代码。猜对数字时用break结束游戏。
left是当前搜索区间的左边界,right是右边界。每次猜测后根据反馈更新其中一个。
mid=(left+right)/2,取当前区间的中间值作为猜测值。整数除法自动向下取整。
猜小了→left=mid+1(目标在右边);猜大了→right=mid-1(目标在左边)。+1/-1避免死循环。
count记录猜测次数,初始值为1(第一次猜测),每次循环末尾count++。
用if/else if/else判断用户输入:1=猜小了,2=猜大了,3=猜对了。注意用==比较。
初始化边界→循环:取中值→输出猜测→读取反馈→更新边界或break→计数+1→结束输出总次数。
① 二分法定义(取中间、缩区间、重复)
② 二分法效率(log₂n次,1000个数最多10次)
③ while(true)无限循环(需配合break跳出)
④ 区间更新逻辑(left=mid+1, right=mid-1)
⑤ 中间值计算(mid=(left+right)/2)
填写代码空缺,让电脑用二分法猜中你想的数字!
3道拓展代码填空,每道可在线调试、提交判分
难度:⭐ | 填空数:2
任务描述:在原猜数字程序基础上,每次猜测后额外输出一行"当前范围:left ~ right",让玩家清楚知道还剩哪些可能的数字。
提示:在输出猜测信息之后、询问用户反馈之前,增加一行cout输出当前的left和right。
难度:⭐⭐ | 填空数:4
任务描述:当剩余范围小于等于10时,程序自动提示"答案就在这几个数中:X X X ...",把所有可能的数字列出来帮助玩家。
提示:用if判断范围大小(right-left+1),满足条件时用for循环从left遍历到right输出每个数。
难度:⭐⭐ | 填空数:2
任务描述:猜对数字后,程序输出"理论最多10次,你用了X次",让玩家知道二分法的最优效率和自己的表现。
提示:在else分支(猜对了)中,输出猜测次数count,并与理论最多次数10进行对比。1-1000范围二分法最多10次(因为2^10=1024≥1000)。
完成拓展任务后,输入老师/家长提供的密码,查看3道拓展题的完整答案与详细解析。
填空答案:
解析:cout输出"当前范围:"后,需要输出左边界left和右边界right两个变量的值,中间用" ~ "连接。这是最基本的变量输出练习,注意变量名要和定义时一致(小写left和right)。
运行效果:每次猜测后会多输出一行,如"当前范围:1 ~ 1000",让玩家清楚知道搜索范围在不断缩小。
填空答案:
解析:
① 范围大小计算:right-left+1 计算当前区间内有多少个数字。例如left=1,right=10时,10-1+1=10个数。注意要+1,因为左右边界都包含在内。
②③ for循环遍历区间:for(int i=left; i<=right; i++) 是遍历一个区间最经典的写法——从左边界开始,到右边界结束(包含右边界,所以用<=)。
④ i++:每次循环后i自增1,逐个输出区间内的每个数字。
运行效果:当范围缩小到10以内时(如最后阶段),程序会自动列出所有可能的数字,如"答案就在这几个数中:75 76 77 78 79"。
填空答案:
解析:
① 为什么是10?二分法每次范围缩小一半,k次后范围为1000/2^k。当范围≤1时就找到了,即2^k ≥ 1000。因为2^9=512<1000,2^10=1024≥1000,所以最多需要10次。这里范围固定1-1000,所以直接写常量10即可。
② count变量:count是计数器,记录玩家实际猜了多少次。猜对后输出count,和理论最多次数10对比,让玩家知道自己的表现是否达到最优。
运行效果:猜对后输出"理论最多10次,你用了6次",如果≤10次说明达到了二分法的最优效率。
密码由老师/家长提供,输入正确后可查看3道拓展题的完整答案与详细解析。
5道单选 + 3道判断,提交后查看判分与解析
二分法的核心就是"分而治之"——每次取当前范围的中间值,根据反馈(大了/小了)判断目标在左半区间还是右半区间,从而把搜索范围直接缩小一半。重复这个过程就能快速找到目标。
每次猜测范围缩小一半,k次后范围大小为1000/2^k。当范围≤1时就找到了,即2^k ≥ 1000。因为2^9=512<1000,2^10=1024≥1000,所以最多需要10次。这就是二分法的威力——1000个数最多10次就能猜中!
mid是middle(中间)的缩写,(left+right)/2就是取左边界和右边界的平均值,即当前区间的正中间值。二分法每次都猜中间值,这样无论反馈是"大了"还是"小了",都能把范围缩小一半。整数除法会自动向下取整,对结果没有影响。
"猜小了"说明目标数字比mid大,所以目标一定在右半区间(mid的右边)。左边界应该更新为mid+1,而不是mid——因为mid已经猜过了,而且确认比目标小,可以直接排除。如果写成left=mid,当left和right相邻时(如left=5,right=6),mid=5,猜5小了,left=mid=5,下一轮mid还是5,就会死循环!+1就是为了避免这种情况。
while(true)的条件永远为真,所以会一直执行循环体,是无限循环。必须在循环体内用break语句才能跳出。猜数字游戏正好适合用while(true)——因为不知道要猜几次,猜对了才用break结束。如果忘记写break,程序就会一直运行下去(死循环),需要手动终止。
正确!二分法每次猜中间值,如果"大了"就排除右半区间,如果"小了"就排除左半区间,无论哪种情况都排除了一半的可能性,所以区间大小每次都缩小一半。这就是二分法效率高的根本原因。
错误!"猜小了"说明目标比mid大,目标在右半区间,应该更新左边界 left = mid + 1。更新 right = mid - 1 是"猜大了"的时候的操作——目标比mid小,在左半区间,所以右边界移到mid-1。一定要分清楚方向:小了→往右找(left+1),大了→往左找(right-1)。
正确!+1有两个重要作用:①mid已经猜过了,确认比目标小,可以直接排除,不需要再包含在范围内;②更关键的是防止死循环——假设left=5, right=6,如果写成left=mid,那么mid=(5+6)/2=5,猜5小了,left=mid=5,下一轮mid还是5,永远卡在5,程序死循环!写成left=mid+1=6,下一轮mid=6,就能继续推进了。所以+1/-1是二分法边界更新的关键细节。
回顾本节课的重点知识