第三单元第5课《经典算法-枚举与递归》教学课件-2025-2026学年青岛版初中信息科技第四册
2026-05-28
|
35页
|
58人阅读
|
0人下载
普通
资源信息
| 学段 | 初中 |
| 学科 | 信息科技 |
| 教材版本 | 初中信息科技青岛版第四册 |
| 年级 | - |
| 章节 | 第5课 经典算法-枚举与递归 |
| 类型 | 课件 |
| 知识点 | - |
| 使用场景 | 同步教学-新授课 |
| 学年 | 2025-2026 |
| 地区(省份) | 山东省 |
| 地区(市) | 青岛市 |
| 地区(区县) | - |
| 文件格式 | PPTX |
| 文件大小 | 2.72 MB |
| 发布时间 | 2026-05-28 |
| 更新时间 | 2026-05-28 |
| 作者 | 从现在开始努力 |
| 品牌系列 | - |
| 审核时间 | 2026-05-28 |
| 下载链接 | https://m.zxxk.com/soft/58095124.html |
| 价格 | 1.00储值(1储值=1元) |
| 来源 | 学科网 |
|---|
摘要:
该初中信息科技课件聚焦枚举与递归算法,通过密码锁破解、阶乘计算等生活场景导入,构建“生活问题-算法定义-步骤案例-对比选择-实操应用”的学习支架,帮助学生逐步理解算法核心逻辑。
其亮点是以生活案例为载体,用“试钥匙”“俄罗斯套娃”等类比培养计算思维,结合鸡兔同笼、汉诺塔案例引导问题分解与建模,实操任务与课后挑战促进数字化学习与创新。学生能直观掌握算法思想,教师可借助丰富案例提升教学效果。
内容正文:
青岛版(新教材)初中信息科技第四册
2025-2026学年
经典算法之旅-枚举与递归
1.7.2013
同学们好!欢迎来到今天的信息科技课。今天,我们将开启一场奇妙的“经典算法之旅”,一起探索计算机是如何像聪明的侦探和将军一样,解决各种复杂问题的。我们将学习两种非常重要的算法思想——枚举与递归。准备好和我一起解锁计算机解决问题的智慧了吗?让我们开始吧!
‹#›
生活中的算法(一):密码锁的烦恼
😱 突发状况!你的行李箱密码锁意外打不开了,只记得密码是一个神秘的 3 位数(000-999)。既没有密码提示,也找不到说明书,现在的你被困在原地,第一反应会怎么做来解开这个锁呢?
🤔 大脑飞速运转:难道只能像个“笨小孩”一样,从 000 开始,一个数字一个数字地去试吗?虽然这个过程听起来有点繁琐,甚至会让人觉得很“傻”,但在没有其他线索的情况下,这好像是目前唯一能确保成功的办法了……
💡 算法小词典
枚举
逐一尝试,直到成功
最朴素也最有效的策略!
其实在计算机科学里,这种方法就叫枚举算法。当我们找不到更聪明的捷径时,这种看似“暴力”却极其可靠的方式,能让计算机通过遍历所有可能性,一步步找到问题的正确答案。
1.7.2013
我们先来看一个生活中的场景。假设你的行李箱密码锁打不开了,密码是个三位数。你会怎么做呢?相信很多同学都会想到,从000开始,一个一个试,直到找到正确的密码。这个过程虽然听起来有点笨,但非常有效。在计算机科学里,这种方法就叫做“枚举”。
‹#›
生活中的算法(二):数学的奥秘
先来算一算:什么是 5 的阶乘?
我们通常会这样一步步计算:
5! = 5 × 4 × 3 × 2 × 1 = 120
这是一种非常直接的计算方式,但如果数字很大,这样算是不是有点麻烦?
💡 灵光一闪:换个思路拆解问题
能不能先算出 4!,再乘以 5 得到 5! 呢?
就像搭积木一样:
5! = 5 × 4! → 4! = 4 × 3! → ... → 1! = 1
把大问题拆成了一模一样的小问题!
✨ 这就是“递归”算法!
核心思想就是“大事化小”:将一个复杂的大问题,拆解成结构相同但规模更小的子问题,直到小问题可以直接得出答案。这在计算机解决复杂任务时可是大有用处的智慧哦!
1.7.2013
再来看一个数学问题。计算5的阶乘,我们知道是5乘以4乘以3一直乘到1。但换个角度想,我们是不是可以先算出4的阶乘,再用结果乘以5呢?这就是把一个大问题,分解成了一个更小的、但结构完全相同的问题。这种“大事化小”的思想,就是我们今天要学习的第二种算法——递归。
‹#›
本节课,我们将一起探索...
理解枚举算法
掌握枚举“一一列举、逐个验证”的核心思想,熟悉从问题出发、逐步排查的解题步骤,建立对基础算法的直观逻辑认知。
学会将实际问题拆解为可枚举的范围,运用枚举法快速解决简单的查找、匹配与条件判断类问题。
理解递归算法
深入理解递归“大事化小、小事化了”的核心原理,牢牢掌握“递推关系”与“终止条件”两大关键要素,看懂自我调用的奥秘。
针对有重复子问题的场景,学会用递归思维简化代码结构,高效解决阶乘、斐波那契数列等典型的数学与逻辑问题。
学会算法选择
横向对比枚举与递归的优缺点,清晰认知枚举的直观性与递归的简洁性,理解不同算法在执行效率与资源消耗上的差异。
建立灵活的算法选型思维,根据问题规模、数据特征和效率要求,为不同场景挑选“最趁手”的算法工具。
探索小目标:从基础概念到动手实践,我们将一起把抽象的算法逻辑变得生动有趣!通过这节课,你将学会像计算机一样思考,轻松掌握解决问题的核心算法思路。
1.7.2013
通过刚才的例子,大家对枚举和递归有了初步的印象。这节课,我们的目标就是深入学习这两种算法。我们会学习它们的核心思想、解题步骤,并且通过案例来实践。最后,我们还会学会如何根据不同的问题,选择最合适的算法。希望通过这节课,大家都能从“算法小白”成长为“算法大师”!
‹#›
枚举算法:地毯式搜索
核心定义:穷举的智慧
这是一种“地毯式”的搜索策略。核心思想是在已知的有限范围内,将所有可能的候选答案毫无遗漏地全部列举出来,然后按照既定的条件逐一进行检验和验证。只要条件设置正确,最终总能从这些可能性中筛选出符合要求的正确解。
生活场景:试钥匙开门
想象一下你手里有一大串钥匙,却不知道哪一把能打开眼前的这扇门。最直接有效的办法就是:从第一把开始,一把一把地往锁孔里插,直到听见“咔哒”一声锁开了为止。这个过程不需要复杂的推理,只需要耐心地逐一尝试,这就是枚举算法最通俗的体现。
💡 算法心法:“笨办法”往往最可靠
虽然枚举法看起来像是一种“笨办法”,但在数据规模有限的情况下,它是最直观、最容易实现的方法。计算机拥有极快的运算速度,正好可以弥补这种方法“重复劳动”的缺点,将人类从繁琐的逐一验证中解放出来。
1.7.2013
好,我们先来深入了解枚举算法。它还有个名字叫“穷举法”,意思就是把所有的可能性都列举出来。这个过程就像地毯式搜索,或者像你拿着一大串钥匙去开门,一把一把地试,总能找到正确的那一把。它的核心就是“逐一尝试,逐个验证”。
‹#›
枚举的核心:逐一排查,筛选有效解
逐一排查
不遗漏任何一个可能性。就像面对一大串钥匙,我们需要把所有的钥匙都拿出来,而不是只挑其中几把。
“把所有潜在的答案都摊在桌面上,一个都不能少!”
筛选有效解
根据问题的条件做“裁判”。拿到每一把钥匙后,都要去试一下锁孔,看看能不能顺利插进去并转动。
“用规则当尺子,量一量哪个才是对的!”
排除无效解
果断放弃错误选项。如果钥匙插不进去,或者转不动,那就直接换下一把,直到找到那把完美匹配的。
“不对就Pass,别在错误的路上浪费时间!”
核心逻辑总结:把所有钥匙都拿出来 → 挨个用锁去试 → 排除不合适的 → 找到唯一能打开门的那把!这就是枚举法从“海量可能”到“唯一正确”的寻宝过程。
1.7.2013
枚举算法的核心思想可以概括为三步:首先,要把所有可能的情况都列出来,做到不遗漏;然后,根据问题给出的条件,去判断每一个可能性是不是我们想要的答案;最后,把不符合条件的排除掉,直到找到那个符合条件的有效解。
‹#›
步骤一:确定枚举范围
在开始尝试之前,我们必须先明确问题所有可能的答案区间。这就像是在寻找宝藏前,先确定藏宝图的有效范围,是枚举法能够高效、正确执行的核心前提。
范围必须是“有限”的
如果答案有无穷多种可能,计算机永远也试不完。我们需要将问题限制在一个可计算的数量级内,就像在沙滩上找特定的贝壳,而不是在大海里捞针。
边界必须“精准”无漏
既要确保不遗漏任何一个潜在的正确答案,也要剔除不必要的重复和无效数据。精准的范围能减少计算机的工作量,让我们用最快的速度找到正确解。
经典示例:密码锁
一个三位数的密码锁,其可能的答案范围被严格限定在000 到 999之间。这是一个完美的有限且精准的范围,总共只有 1000 种可能性,既不会因为太多而无法计算,也不会因为太少而漏掉正确密码。
1.7.2013
使用枚举法的第一步,也是非常关键的一步,就是确定枚举的范围。这个范围必须是有限的,否则计算机永远也试不完。同时,范围要精准,既不能漏掉可能的答案,也不要包含太多无关的东西,否则会降低效率。比如刚才的密码锁问题,范围就是000到999。
‹#›
步骤二:逐一列举验证
核心心法:全面 + 有序
就像小侦探破案一样,我们要对范围内所有的可能性进行“地毯式”排查。不可以跳着找,也不能漏掉任何一个,必须严格按照顺序执行,保证每一个线索(可能性)都被检查到,只有这样才能确保答案不会悄悄溜走哦!
举个栗子:解锁数字密码
如果密码是一个三位数,范围是 000 到 999。我们就从 000 开始,接着是 001、002、003……像数数一样,一直按顺序尝试到 999。不管数字有多少,只要坚持这个节奏,就一定能找到那个唯一正确的组合!
💡 为什么要这么做?
这个方法虽然看起来有点“机械”,但却是最稳妥的笨办法!当我们面对复杂的问题,暂时找不到更巧妙的捷径时,把大问题拆解成一个个简单的重复小步骤,有序地穷举能帮我们避开混乱,稳稳当当地接近正确答案。
1.7.2013
确定了范围之后,第二步就是逐一去尝试。这个过程需要全面且有序,就像我们数数字一样,从0开始,一个一个数下去,确保每一个数字都被检查到。在密码锁的例子里,就是从000开始,然后是001,002,一直到999。
‹#›
步骤三:筛选有效结果
根据问题给出的具体条件,从所有可能性中精准筛选出符合要求的解,这是我们找到正确答案的关键一步!
核心要求:明确标准
判断条件一定要清晰,得出的结果必须准确。不能模棱两可,否则就会在错误的选项里兜圈子。只有设定好清晰的“通关规则”,我们才能在复杂的线索中,快速定位到那个唯一正确的目标。
趣味示例:打开宝箱
想象你正在解锁一个神秘宝箱,手里有好多把钥匙。判断条件很简单:“这把钥匙能不能顺利插进锁孔并打开箱子?”。如果能打开,这把钥匙就是有效解;如果转不动或者插不进,就果断换下一把!
筛选就像寻宝游戏里的“验货环节”!不看表象看实效,不凭感觉凭规则。当你找到那个完全符合所有条件的结果时,就像拿到了通关钥匙,之前所有的尝试和计算都有了完美的答案,问题也就迎刃而解啦~
1.7.2013
最后一步,就是筛选。我们需要设定一个明确的判断条件,来检验每一个尝试的结果是否正确。比如,对于密码锁,判断条件就是“这个密码能不能打开箱子”。一旦找到了符合条件的那个答案,我们的任务就完成了。
‹#›
案例分析:鸡兔同笼
经典数学谜题挑战
笼子里一共住着一群小鸡和小兔子,数了数发现总共有35 个头,但脚下却有94 只脚。因为小兔子总是爱把耳朵藏起来,直接数不清数量,你能帮我们算一算笼子里鸡和兔各有几只吗?
看着这可爱的画面,是不是觉得问题也变得有趣起来了?其实不用一只只数,用一个简单的方法就能快速找到答案!
枚举法
小妙招
简单直接
快速试错
核心逻辑:化繁为简,逐一验证
我们不需要复杂的方程,只需要从“鸡的数量”入手枚举。假设鸡有 0 只、1 只、2 只……一直到 35 只,对应的兔子数量就是总头数减去鸡的数量。再根据“鸡 2 只脚,兔 4 只脚”的常识,计算出每种假设下的总脚数,只要总脚数等于 94,就能立刻锁定正确答案啦!
1.7.2013
理论说完了,我们来看一个经典的数学问题——鸡兔同笼。问题是:一个笼子里有35个头,94只脚,问鸡和兔各有多少只?这个问题用枚举法怎么解决呢?很简单,我们可以假设鸡的数量是从0到35之间的某个数,然后兔子的数量自然就是35减去鸡的数量。
‹#›
用枚举法解决鸡兔同笼
确定枚举范围
笼子里一共关了35个头,所以鸡的数量可能是 0 到 35 只之间的任意整数。我们需要逐个尝试这个范围内的每一个数字,去验证是否符合脚数的条件。
核心判断逻辑
对于每一个假设的鸡数量,先算出兔子数(兔子 = 35 - 鸡),再计算总脚数(总脚数 = 鸡×2 + 兔×4)。如果计算出的总脚数恰好等于94,那这组数量就是正确答案!
假设:鸡有 10 只
兔子就有 25 只,总脚数是 10×2 + 25×4 = 120 只。
结果:120 ≠ 94,不符合条件。
假设:鸡有 20 只
兔子就有 15 只,总脚数是 20×2 + 15×4 = 100 只。
结果:100 ≠ 94,还差一点点!
不断尝试不同的数字,直到我们找到那个让总脚数等于 94 的组合,这就是枚举法的核心思想——“逐一排查,命中目标”。
找到正确答案啦!
鸡 23 只 + 兔 12 只
计算验证:23×2 + 12×4 = 94
完美符合题目中的总脚数条件!
1.7.2013
具体来说,我们的枚举范围就是鸡的数量从0到35。对于每一个鸡的数量,我们都可以算出兔子的数量,然后计算总脚数。我们的判断条件就是:算出来的总脚数是否等于94。一旦相等,我们就找到了答案。比如,当鸡是23只,兔子是12只时,总脚数正好是94。
‹#›
鸡兔同笼问题的算法流程
启动:设定初始值
程序开始运行,首先把小鸡的数量设为 0。
已知笼子里总头数是 35,这是我们解题的基础条件哦!
循环:逐个排查
让小鸡数量从 0 一直试到 35。
就像我们一个个去数一样,把所有可能的情况都检查一遍,绝不放过任何一种可能性!
推导:算兔子数量
因为总头数是 35,所以:
兔子数量 = 35 - 小鸡数量。
只要知道小鸡有几只,兔子的数量马上就能算出来啦。
关键:脚数对吗?
检查总脚数是否等于 94:
2×小鸡 + 4×兔子 = 94?
这是判断答案正确与否的核心标准哦!
Bingo!找到答案
如果脚数刚好对,那就太棒了!
直接输出小鸡和兔子的具体数量,然后结束程序,问题解决啦!
不对,继续试
如果脚数不对,说明这次猜错了。
小鸡数量加 1,回到循环里,重新计算兔子数量,再检查一遍!
1.7.2013
我们可以把这个过程用一个流程图来表示。从开始,设置鸡的数量为0,然后进入一个循环。在循环里,计算兔子数量,并判断总脚数是否符合条件。如果符合,就输出答案并结束;如果不符合,就把鸡的数量加1,继续下一次循环。这个流程非常清晰地展示了枚举算法的执行过程。
‹#›
枚举算法的优缺点
逻辑简单,易于实现
思路非常直白,就像我们日常生活中的“逐个排查”一样,不需要复杂的数学推导或逻辑转换。对于编程新手来说,理解这种“暴力搜索”的思想几乎没有门槛,能快速把问题转化为代码。
结果准确,绝不遗漏
这是枚举算法最核心的优势。只要我们设定的搜索范围覆盖了所有可能的正确答案,并且判断条件无误,无论问题多复杂,程序都一定能从海量可能性中找到那个唯一的解,不会出现算法逻辑错误导致的答案偏差。
致命短板:效率较低,耗时严重
枚举本质上是“笨办法”,需要对每一种可能性进行逐一验证。如果问题的解空间非常庞大(例如破解一个8位的数字密码就有1亿种可能),程序会进行海量的循环和判断,这会占用大量的计算资源,导致运行时间极长。在对响应速度有要求的场景下,这种效率问题往往是不可接受的。
1.7.2013
那么,枚举算法有什么优缺点呢?优点很明显,它的逻辑非常简单,就像我们刚才看到的,思路很直接,容易理解和编写程序。而且只要你的范围没搞错,它一定能找到正确答案。但缺点也同样突出,就是效率问题。如果可能性非常多,比如密码是8位数,那枚举起来就要花费大量时间了。
‹#›
什么时候用枚举?
解的数量较少
当问题的候选答案数量不多时,我们不需要复杂的算法,通过简单的穷举就能覆盖所有可能性,计算成本极低。
核心特征:候选集规模小,穷举耗时短。
范围有限明确
当问题的边界清晰、条件可以被具体定义时,我们能轻松划定搜索区间,像在一个圈好的范围内寻宝,不会做无用功。
核心特征:搜索范围可控,无模糊地带。
需要精确答案
当我们需要一个准确无误的解,而非估算或近似值时,枚举法通过逐一验证每一种情况,能100%确保结果的正确性。
核心特征:拒绝模糊,追求绝对准确。
💡 核心心法:简单直接,逐一排查,不重不漏!就像在抽屉里找钥匙,把所有抽屉都看一遍,总能找到那把对的。
1.7.2013
所以,我们什么时候应该使用枚举算法呢?记住这几个关键词:当问题的可能答案数量不多,范围很明确,而且我们需要一个精确的答案时,枚举法就是一个很好的选择。它简单可靠,是解决这类问题的利器。
‹#›
递归算法:神奇的自我复制
什么是递归?
一个函数或过程在运行过程中,会主动地自我调用。这就像是程序里的“分身术”,在执行任务时不断复刻自己,直到满足某个特定条件才会停下来。
核心:大事化小
面对复杂的大问题,我们把它拆解成规模更小、结构相同的子问题。就像搭积木一样,先解决小积木的问题,最后拼在一起,大问题自然就迎刃而解啦。
生活:无限镜像
就像两面镜子面对面对照!你会看到无数个层层嵌套、越来越小的自己。递归就是这样,问题在不断“复刻”中变得简单,直到触达那个不再需要复制的“终点”。
💡 递归小秘籍:找准“出口”是关键!
递归虽然神奇,但如果没有终止条件,就会像镜子里的影像一样无限循环下去,导致程序崩溃。所以写递归代码时,一定要先找到问题的“递推公式”和“终止条件”,让问题在变小的过程中能找到停下来的那个“最小自己”。
1.7.2013
好了,学完了枚举,我们来看看另一种强大的算法——递归。递归的定义听起来有点绕,就是一个函数自己调用自己。它的核心思想,就是我们开头说的“大事化小”,把一个复杂的问题,分解成和它结构一样、但规模更小的子问题来解决。就像两面镜子对着照,会看到一个无穷无尽、越来越小的自己。
‹#›
递归就像俄罗斯套娃
想象一下,你手里有一个色彩鲜艳的俄罗斯套娃。当你打开这个大大的娃娃时,发现里面藏着一个一模一样但尺寸小一点的娃娃;再打开这个小娃娃,里面居然还有一个更小的……这个层层嵌套、不断“打开”的过程,和编程里的递归逻辑简直如出一辙!
第一步:拿到大娃娃
面对一个复杂的大问题,就像面对这个巨大的套娃,我们首先尝试把它“打开”,看看里面是什么。
第二步:发现小娃娃
每次打开都能看到一个同类型但更简单的小问题,于是我们继续对这个小娃娃执行同样的“打开”操作。
第三步:不断重复
这个过程不会一直持续下去,总会有一个终点,让我们知道什么时候该停下来。
核心概念:终止条件(Base Case)
当打开最里面那个不能再打开的实心娃娃时,游戏就结束了。在递归算法中,这就是防止程序无限循环的“终止条件”——它是递归能够安全停止、并开始回溯结果的关键节点。
1.7.2013
递归的过程非常像我们玩的俄罗斯套娃。一个大娃娃里面套着一个小娃娃,小娃娃里面还有更小的。我们不断地打开,直到最里面那个实心的、不能再打开的娃娃。在递归算法里,这个“最里面的娃娃”非常重要,我们称之为“终止条件”。
‹#›
要素一:递归终止条件
什么是终止条件?
递归函数的“停止信号”。它明确告诉程序,什么时候应该结束自我调用,就像赛跑时的终点线,到达目标就立刻停下。
简单说:给递归设定一个“底线”,一旦满足这个条件,就不再自己调用自己了。
必须要有!划重点
这是递归的“生命线”。如果缺少它,函数就会像失控的机器人一样,无限循环调用自己,直到把电脑内存耗尽。
后果很严重:程序直接崩溃(死循环)。这可是初学者最容易踩的“大坑”哦!
栗子:计算阶乘
阶乘规则是 n! = n × (n-1)!。我们一直拆解计算,直到遇到一个不需要再算的数。
当 n = 1 时,直接返回 1。这就是终止条件,告诉程序:“到1为止,不用再拆啦!”
💡核心口诀:先定终点,再找规律!没有终点的递归就像没有刹车的车,迟早要“翻车”。写递归代码时,第一步一定要先想好:什么时候停下来?
1.7.2013
这就是递归的第一个核心要素:递归终止条件。它的作用就是告诉程序,什么时候该停下来了。这个条件是必须的!如果没有它,函数就会像一个停不下来的机器人,不停地自己调用自己,直到把电脑的内存耗尽,程序崩溃。比如计算阶乘,当n等于1的时候,我们就知道1的阶乘就是1,计算可以停止了。
‹#›
要素二:递归递推公式
核心定义
如何将原问题拆解成更小的子问题?这是递归思维的第一步,把复杂的大任务“化整为零”,让庞大的问题规模逐步缩小,变成我们更容易下手处理的小单元。
关键核心
找到问题的重复性规律。这是递归的灵魂所在,意味着每次拆解后的子问题,在逻辑结构上和原问题是高度相似的,只是规模不同,从而可以复用同一套解决思路。
经典示例:阶乘计算 n!
公式:n! = n × (n-1)!
求 5! 时,问题转化为 5 × 4!;求 4! 又转化为 4 × 3!……直到遇到终止条件。这种层层递推的方式,让复杂的计算过程变成了简单的重复步骤,计算机就能高效地自动执行啦。
💡 思维小妙招
递归就像拼拼图游戏!
把一整块复杂的大拼图(原问题),拆成一个简单的小拼图块(当前步骤 n)和剩下的一堆拼图(子问题 n-1)。
只要找到每一步的“拆分规则”,再庞大的拼图,也能像搭积木一样,一步一步轻松拼完~
1.7.2013
递归的第二个核心要素,是递推公式。它描述了如何把一个大问题分解成小问题。这需要我们找到问题中的重复性规律。比如阶乘的递推公式就是n! = n × (n-1)!。这个公式告诉我们,要求n的阶乘,可以先去求n-1的阶乘,然后再乘以n。这样,问题的规模就减小了。
‹#›
案例分析:n的阶乘
我们要计算 n 的阶乘 (n!),即从 1 开始连续乘到 n 的积(如 5! = 5×4×3×2×1)。这是一个经典的递归入门问题,我们将通过递归的核心思维——“拆解-终止-回溯”,来探索如何优雅地解决它。
问题拆解
把复杂的大问题拆解为同类的小问题。n! = n × (n-1)!,要求解 n 的阶乘,只需要先求出 n-1 的阶乘,再乘以 n 即可。
核心公式:n! = n × (n-1)!
终止条件
递归不能无限进行,必须有停止的终点。当问题小到不能再拆时,直接给出已知答案,这是递归的“出口”。
当 n = 1 时,1! = 1
回溯求解
从最小的已知解开始,像链条一样逐步回推。利用已经算出的小问题答案,反过来计算出大问题的最终结果。
由 1! 推 2!,直到 n!
💡 趣味理解:递归就像“拆俄罗斯套娃”。先一层层拆开找最里面的小娃娃(递推),这是问题的拆解过程;然后从最里面的娃娃开始,一层层还原回去(回归),直到得到最外面的答案。
1.7.2013
我们再用阶乘的例子来完整地看一下递归的思路。第一步,问题拆解,n!等于n乘以(n-1)!。第二步,确定终止条件,当n等于1时,结果就是1。整个过程就像一个链条,从n!一直追溯到1!,然后再从1!开始,一步步计算回来,最终得到结果。
‹#›
计算 5! 的递归之旅
🔍 递归深入:问题层层拆解
从 factorial(5) 开始,函数不断调用自身,将大问题拆分为更小的子问题:
5 × factorial(4) → 5 × (4 × factorial(3)) → 5 × (4 × (3 × factorial(2)))
触底时刻:遇到终止条件 n=1
拆解到最深处:5 × (4 × (3 × (2 × factorial(1))))
此时 factorial(1) = 1,不再继续调用,开始触发“回溯”!
✨ 结果回溯:数值步步归并
拿到基础结果后,从内向外层层计算返回值:
5 × (4 × (3 × 2)) → 5 × (4 × 6) → 5 × 24
最终答案:得出结果
所有子问题解决完毕,最终合并计算得到:
5! = 120
1.7.2013
我们来看计算5的阶乘的具体过程。首先,调用factorial(5),它会去调用factorial(4)。这个过程不断深入,直到调用factorial(1),触发了终止条件,返回1。然后,结果开始一层层回溯,计算出2的阶乘是2,3的阶乘是6,4的阶乘是24,最后得到5的阶乘是120。这个先深入再回溯的过程,就是递归的精髓。
‹#›
危险!无限递归!
想象一下,如果在写阶乘函数时,不小心漏掉了关键的终止条件`if n == 1: return 1`,程序的执行逻辑就会像脱缰的野马一样彻底失控!这时候,代码的运行过程会变成什么样子呢?
第一步:正常起步
factorial(5)
想要计算 5 的阶乘,得先算 4!
第二步:没有尽头
... → 0 → -1
突破 1 的边界,负数也继续算
第三步:无限坠落
根本停不下来!
函数自己调用自己,形成死循环
严重后果:程序崩溃!
就像小人在无限延伸的楼梯上一直往下跑,永远找不到终点。系统内存和CPU资源会被迅速耗尽,最终程序会抛出错误并强制退出。所以,终止条件就是递归函数的“安全刹车”,千万不能忘!
1.7.2013
我们再强调一遍终止条件的重要性。如果我们不小心忘记写它,会发生什么呢?程序会进入一个无限递归的状态。计算5的阶乘会调用4的阶乘,然后是3的,2的,1的,0的,-1的……函数会一直不停地调用自己,就像一个人在无限延伸的楼梯上不停奔跑,直到电脑资源耗尽,程序就会崩溃报错。
‹#›
拓展案例:汉诺塔游戏
游戏初始设定
有三根柱子(A、B、C)和N个大小不一的彩色盘子。初始时,所有盘子像彩虹一样,严格按照“小盘子在上,大盘子在下”的顺序,整齐叠放在A柱子上。
移动铁律
这是游戏的关键限制!每次操作只能移动一个盘子,并且在任何时刻,都绝对不允许把大盘子放在小盘子的上面,否则游戏就会失败,需要重新开始。
最终挑战目标
我们的终极任务是:在遵守所有规则的前提下,把A柱子上的这一整叠盘子,完整无损地全部移动到C柱子上。你能算出最少需要移动多少步吗?
为什么它是递归算法的经典例题?
这个看似简单的益智游戏,随着盘子数量N的增加,移动步数会以 2ⁿ - 1 的规律呈指数级爆炸增长。如果用常规的循环去穷举每一步,逻辑会极其复杂;但如果用递归思想将问题拆解——把“移动N个盘子”转化为“先移动N-1个盘子到中转柱,再移动最大盘,最后移动N-1个盘子到目标柱”,整个解题过程就会变得简洁、优雅且易于理解。
1.7.2013
递归非常适合解决像汉诺塔这样的问题。汉诺塔游戏规则很简单:有三根柱子和一堆盘子,盘子从小到大叠在A柱上。我们需要把所有盘子移到C柱,每次只能移动一个,并且任何时候大盘子都不能放在小盘子上面。这个问题用递归思想来解决会非常优雅。
‹#›
如何用递归解决汉诺塔?
第一步:移走上方 N-1 个
先把柱子 A 上的 N-1 个盘子整体“搬家”到柱子 B。这本身就是一个规模更小的汉诺塔问题,我们需要先递归地解决这个子任务,为移动最大的盘子腾出空间。
第二步:移动最底盘子
此时柱子 A 只剩下最大的第 N 个盘子,直接把它从 A 移到目标柱子 C。这是整个过程中最直观、最基础的一步,也是递归链条中的一个实际操作节点。
第三步:归位 N-1 个盘子
最后,把暂存在柱子 B 上的 N-1 个盘子再次“搬家”到柱子 C。这同样是一个递归子问题,完成这一步后,所有盘子就都按规则从 A 移到了 C。
关键终止条件:最简单的情况
当 N=1 时,递归停止!此时只有一个盘子,无需复杂操作,直接把它从起点 A 移到终点 C 即可。这是整个递归算法的“锚点”,没有它程序就会无限循环下去。
1.7.2013
用递归的思路来想,要把N个盘子从A移到C,可以分三步。第一步,先把上面N-1个盘子从A移到B,这本身就是一个小一号的汉诺塔问题。第二步,把最下面那个最大的盘子从A直接移到C。第三步,再把B柱上的N-1个盘子移到C,这又是一个小一号的汉诺塔问题。而终止条件就是当只有一个盘子时,直接移动就行。
‹#›
递归算法的优缺点
核心优势 · 化繁为简
代码极致简洁
摒弃复杂的循环嵌套,仅需几行核心逻辑即可描述复杂问题。极大提升了代码的可读性,让人一眼看懂程序意图。
思维高度贴合
完美契合人类“大事化小、层层拆解”的直觉思维。将一个庞大的原问题,自然地分解为结构相同的小问题去解决。
💡 就像玩俄罗斯套娃,通过函数自我调用,递归让程序结构变得极具数学美感,是处理分治问题时最优雅的解决方案之一。
潜在局限 · 性能挑战
栈内存压力大
每次递归调用都会在内存栈中压入新的栈帧。一旦递归深度过大,极易引发“栈溢出”错误,导致程序意外崩溃。
重复计算损耗
朴素递归未做优化时,会反复计算大量重叠的子问题(如斐波那契数列),导致时间复杂度指数级上升,效率低下。
⚠️ 虽然写法优雅,但在工程实践中,面对海量数据时往往需要结合“记忆化搜索”或“尾递归优化”来规避性能陷阱,或直接改用迭代方案。
1.7.2013
递归算法的优点是代码非常简洁,比如汉诺塔问题,用递归写出来可能只有几行代码。而且它的思路很符合我们人类“大事化小”的思维习惯。但缺点也很明显,因为每次函数调用都要占用内存,递归层数太深的话,容易导致内存不够用。而且有时候会重复计算一些子问题,影响效率。
‹#›
什么时候用递归?
层层拆解子问题
当复杂问题可以被不断拆解成结构完全相同的小问题时。就像剥洋葱一样,每一层的处理逻辑都一模一样,直到遇到最基础的简单情况。
天然嵌套结构
面对具有层级关系的数据结构时,比如树形结构、嵌套的文件夹或者复杂的图形结构。递归能非常直观地模拟“深入”和“回溯”的过程,代码更易读。
定义即递归
如果问题的数学公式或逻辑定义本身就是递归的,比如阶乘计算(n! = n × (n-1)!)或斐波那契数列。这时候使用递归是最自然、最直接的实现方式。
递归核心心法:大事化小,小事化了
递归就像一个聪明的“分身术”。只要我们能找到问题的递归关系(如何拆分子问题)和终止条件(最小的可解问题),就能把一个看起来很难的复杂任务,拆解成无数个可以重复执行的简单步骤。这不仅让代码结构变得优雅简洁,更让逻辑一目了然!
1.7.2013
那么,什么时候适合用递归呢?当一个问题可以被层层分解成结构相同的子问题时,比如汉诺塔。或者当问题本身就具有层次嵌套的结构,比如我们后面会学到的树和图。还有一些问题,它们的数学定义本身就是递归的,比如阶乘和斐波那契数列。
‹#›
核心思想大比拼
枚举算法
就像一个拿着放大镜的勤奋侦探,面对复杂的案情,把所有“嫌疑人”都耐心地排查一遍。不遗漏任何一种可能性,通过逐一验证,最终从海量线索中找出那个唯一的真凶。
核心策略:逐一排查
地毯式搜索,虽然看似笨拙,却能保证结果的绝对准确性。
递归算法
像一位运筹帷幄的将军,面对庞大的战役,把一个复杂的大任务分解给几个小队长。小队长再将任务继续拆解给士兵,直到任务小到士兵可以直接执行,最终通过层层协作完成目标。
核心策略:问题拆解
化繁为简,利用自身解决相似的子问题,高效且优雅。
1.7.2013
学完了两种算法,我们来做个对比。枚举算法就像一个勤奋的侦探,把所有可能性都排查一遍,总能找到答案。而递归算法更像一个聪明的将军,善于把大任务分解成小任务,层层下达,直到任务完成。一个是“逐一排查”,一个是“问题拆解”。
‹#›
实现方式的不同
枚举算法
核心机制:循环结构
主要依靠 for、while 等循环语句来驱动程序执行。让计算机像“数数”一样,按照设定的规则重复遍历所有可能的情况,直到找到目标结果或完成全部检查。
递归算法
核心机制:自我调用
核心在于函数自己调用自己。把一个复杂的大问题,层层拆解成规模更小的同类子问题,直到子问题简单到可以直接求解,再通过回溯将结果组合起来得到最终答案。
1.7.2013
从实现方式上看,它们也完全不同。枚举算法主要是通过循环来实现的,比如for循环或者while循环,让计算机重复执行一段代码。而递归算法则是通过函数自己调用自己来实现的,这是一种完全不同的编程思路。
‹#›
各有所长
枚举算法
适用于范围有限、答案比较零散的问题。就像在散落的积木堆里,一块一块翻找目标积木一样,虽然直接但很有效,适合处理可能性不太多的场景。
核心思路:范围小 · 可能性少 · 逐个排查
递归算法
适用于嵌套重复、可以被层层拆解的问题。就像剥洋葱一样,每次都做同样的动作——剥掉最外层,直到碰到核心,把大问题变成无数个相似的小问题。
核心思路:可分解 · 重复性 · 自我调用
💡 小智慧:它们没有绝对的优劣之分,只是解题思路不同。面对简单直接、数量可控的问题时,枚举法是最朴实的好帮手;而面对像俄罗斯套娃一样层层嵌套的复杂结构时,递归法则能以优雅的方式化繁为简。灵活选择,就是最好的策略!
1.7.2013
它们的适用场景也各有侧重。枚举法适合解决那些答案范围有限、比较零散的问题。而递归法则更擅长处理那些具有嵌套重复结构、可以被层层拆解的问题。它们没有绝对的好坏之分,只是各有所长。
‹#›
优缺点对比总结
枚举算法
核心思想
像在玩具箱里挨个翻找!逐一排查所有可能性,筛选出符合条件的有效解,过程直白不绕弯。
核心结构
依靠循环结构(for/while)作为骨架,通过重复执行一段代码,机械地遍历每一个候选答案。
适用场景
适合数据范围有限、结构零散的小问题。比如在固定长度的列表里找特定数字,或者简单的密码破译。
算法特点
逻辑非常简单,像数数一样容易上手。但面对海量数据时效率较低,虽然“笨”但是绝对可靠,不会遗漏。
递归算法
核心思想
像俄罗斯套娃!把一个复杂的大问题,层层拆解成一模一样的小问题,直到问题小到能直接解决。
核心结构
函数自我调用的魔法!在满足“终止条件”前,函数不断调用自己来解决缩小版的子问题。
适用场景
处理天然具有嵌套或重复性的问题。例如计算斐波那契数列、走迷宫路径,或者处理树形结构的数据。
算法特点
代码写起来超级简洁优雅!但每一次调用都需要占用内存,就像叠盘子,叠太多了(深度过大)容易“倒”掉。
1.7.2013
这里有一个表格,总结了枚举和递归在核心思想、核心结构、适用场景和算法特点上的对比。大家可以清晰地看到它们的区别。枚举逻辑简单但效率可能不高,递归代码简洁但对内存有要求。
‹#›
算法选择小向导
第一问:可能的解多吗?
先看看问题的解空间有多大,这决定了我们是否能一个个去尝试。
不多(范围小)
直接穷举!试试枚举法,简单直接效率高。
很多(范围大)
枚举太慢啦,得换个更聪明的思路。
第二问:能拆解问题吗?
看看复杂问题能不能变成几个一模一样的简单小问题来解决。
能(同类子问题)
大事化小!试试递归法,让代码更优雅。
不能(独立问题)
递归不适用,考虑其他线性或迭代方法。
💡 核心心法:算法没有绝对的好坏,只有场景的适配。先看规模定枚举,再看结构定递归,灵活运用才是解题的关键哦!
1.7.2013
那么,在实际问题中我们该如何选择呢?这里有一个简单的决策向导。首先问问自己,问题的可能答案是不是很多?如果不多,范围很小,那就可以考虑用枚举。然后再问问自己,这个问题能不能被分解成更小的同类问题?如果能,那递归可能是更好的选择。
‹#›
实操任务一:百钱买百鸡
经典数学问题挑战
现有 100 元钱,需要恰好买 100 只鸡。已知市场价格:公鸡每只 5 元,母鸡每只 3 元,小鸡 1 元可以买 3 只。
请你算一算,在钱数和鸡的总数都刚好为 100 的情况下,公鸡、母鸡、小鸡分别应该购买多少只呢?
编程实现目标
请使用枚举算法的核心思想编写一段 Python 程序来解决这个问题。
程序需要遍历所有可能的购买组合,通过设定的条件(总金额=100,总数量=100)进行判断,最终输出所有符合条件的解。
思路小锦囊
枚举法的关键是“穷举”与“筛选”。你可以尝试使用双层循环分别遍历公鸡和母鸡的数量范围,小鸡的数量可由总数减去公鸡母鸡数得到;再通过价格公式判断是否符合100元的条件。记得合理设置循环的边界值,能让程序运行得更高效哦!
1.7.2013
理论学习完了,我们来动手实践一下。第一个任务是“百钱买百鸡”问题。用100元买100只鸡,公鸡5元一只,母鸡3元一只,小鸡1元三只。请大家思考一下,如何用我们刚刚学的枚举算法来解决这个问题,并尝试编写一段Python代码。
‹#›
实操任务二:计算10的阶乘
开动小脑筋思考一下~
如何让程序像我们一样
一步步拆解这个问题呢?
核心挑战:求 10! 的结果
阶乘是数学中的经典运算,符号n!表示从 1 到 n 的所有正整数的乘积。本次任务的目标非常明确,就是编写程序计算出 10 的阶乘,也就是 10 × 9 × 8 × ... × 1 的最终数值。
关键要求:必须使用递归算法
请使用Python 语言完成本次编程。重点在于应用递归思想,把大问题拆解成规模更小的同类型问题。你需要先定义好递推公式和递归的终止条件,让程序通过自我调用的方式,优雅地解决这个计算问题。
1.7.2013
第二个任务,我们来挑战一下递归。请大家用递归算法编写一个程序,来计算10的阶乘。想一想我们之前分析的阶乘递归过程,如何写出递推公式和终止条件。
‹#›
本节课收获满满!
枚举 · 简单可靠的“笨办法”
就像在一堆糖果里找牛奶糖,把所有可能性一个一个翻查。虽然听起来很“笨拙”,但它逻辑直白、不容易出错,是我们解决未知问题时最基础也最值得信赖的策略,能稳稳当当地找到答案。
递归 · 化繁为简的“巧办法”
这是一种“大事化小”的智慧!把复杂的大问题拆解成一模一样的小问题,让程序自己调用自己去解决。虽然理解它的逻辑需要转个弯,但一旦掌握,就能用超简洁的代码解决超级复杂的任务,效率直接拉满!
💡 解锁新技能:让计算机成为你的得力小助手!
从基础的枚举到巧妙的递归,我们不仅学会了两种解题思路,更掌握了指挥计算机高效工作的密码。无论是按部就班的探索,还是聪明的问题拆解,都能让我们在编程的世界里游刃有余,用代码去解决生活中那些有趣的实际挑战!
1.7.2013
好了,同学们,我们今天的课程就要结束了。回顾一下,我们学习了枚举和递归这两种经典的算法。枚举虽然看起来是“笨办法”,但它简单可靠。而递归是“巧办法”,能让代码变得非常简洁,但需要我们真正理解它的核心逻辑。希望大家通过这节课,能够掌握让计算机更高效为我们解决问题的能力!
‹#›
课后挑战
挑战一:汉诺塔的步数谜题
请尝试使用递归算法来解决经典的汉诺塔问题。如果初始有 3 个大小不同的盘子,要从起点柱子移动到终点柱子,并且始终保持大盘在下、小盘在上,最少需要移动多少步才能完成呢?
小提示:递归的核心是“大事化小”,把 N 个盘子的问题拆解成 N-1 个盘子的问题去解决哦!
挑战二:寻找生活中的算法
跳出编程的世界,在我们的日常生活中,还有哪些实际问题可以用今天学到的“枚举法”或者“递归法”来分析和解决呢?试着举一个例子,并简单描述你的思路。
开动脑筋:无论是规划路线还是整理书架,也许都藏着算法的影子!
期待你的精彩解答!请将你的思考和答案整理好,我们下节课一起来揭晓答案,看看谁的思路最巧妙!
1.7.2013
最后,给大家留两个课后挑战。第一,请尝试用递归算法解决汉诺塔问题,看看移动3个盘子最少需要多少步。第二,希望大家能打开思路,想一想我们生活中还有哪些问题,可以用今天学到的枚举或递归来解决。期待大家的答案!
‹#›
感谢聆听!
1.7.2013
今天的课程到此结束,感谢同学们的聆听!记住,算法的世界就像一条永无止境的道路,充满了探索和乐趣。希望大家能保持好奇心,继续在算法之路上前行。下课!
‹#›
$
相关资源
示范课
由于学科网是一个信息分享及获取的平台,不确保部分用户上传资料的 来源及知识产权归属。如您发现相关资料侵犯您的合法权益,请联系学科网,我们核实后将及时进行处理。