ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

谢尔宾斯基地毯递归解法:信息素养大赛图形化编程真题解析

谢尔宾斯基地毯递归解法:信息素养大赛图形化编程真题解析 1. 从一道真题说起谢尔宾斯基地毯到底在考什么刚考完的2025年全国青少年信息素养大赛图形化编程挑战赛复赛小高组里谢尔宾斯基地毯这道题在选手群里讨论度很高。我拿到题目之后第一反应是这不是单纯考画图而是在考递归思维在图形化编程环境里的落地能力。很多孩子平时用图形化编程做小游戏、做动画很顺手但一碰到分形结构就卡壳原因不在于不会拖积木而在于脑子里没有建立起自己调用自己的模型。谢尔宾斯基地毯Sierpinski Carpet是一个经典的分形图形。它的构造规则说起来很简单把一个正方形分成3×3的九宫格挖掉正中间那一块剩下8个小正方形然后对这8个小正方形分别重复同样的操作挖掉各自的正中间如此反复。迭代次数越多图形越精细最终形成一个处处有洞、自相似的结构。这道题放在小高组的复赛里考察的核心能力有三个层次。第一层是几何拆解能力能不能把一个大正方形正确地切成九宫格并定位到中心块第二层是递归抽象能力能不能把挖中心这个动作抽象成一个可以自我调用的自制积木第三层是边界控制能力递归什么时候停、停的条件怎么写、层数怎么控制这些都需要清晰的逻辑。我见过不少孩子拿到题之后直接上手画九宫格画完一层就不知道怎么办了。其实这道题如果理解了递归的本质代码量非常少核心逻辑可能就十几块积木。但如果没理解写一百块积木也画不出正确的图形。下面我就按实际解题的思路把这道题从头到尾拆一遍。2. 解题前的整体设计与思路拆解2.1 为什么选递归而不是循环嵌套面对谢尔宾斯基地毯有两种思路。一种是暴力循环嵌套比如用三层循环分别控制行、列、层级手动计算每个小方块的位置。另一种是递归写一个自制积木让它自己调用自己。暴力循环的问题在于每增加一层迭代你就得多写一层循环代码量呈指数增长。三层迭代还好四层五层就完全没法维护了。而且循环嵌套的写法很难体现分形自相似的本质代码和图形之间的对应关系不直观。递归的优势恰恰在这里。谢尔宾斯基地毯的定义本身就是递归的一个地毯由8个更小的地毯组成每个小地毯又由8个更小的地毯组成……用递归写代码结构和数学定义几乎一一对应逻辑清晰扩展性好。想画几层就改一个参数不用动主体逻辑。在图形化编程环境里自制积木也叫自定义积木、函数积木就是实现递归的载体。你需要定义一个积木比如叫画地毯它接收参数比如边长、层数、起始位置然后在它的定义内部调用自己只不过参数变小了。2.2 坐标系与定位方案的选择图形化编程的舞台坐标系通常是中心原点x向右为正y向上为正范围大概是x从-240到240y从-180到180。画谢尔宾斯基地毯我们需要确定每一层每个小正方形的位置。最直观的方案是给定一个正方形的左下角坐标和边长就能确定它的位置和大小。每次递归时把大正方形分成9个格子跳过中心格对剩下8个格子分别计算左下角坐标和新的边长原来的三分之一然后递归调用。这里有个关键点画笔的落点和移动方式。图形化编程里画正方形一般用落笔-移动-转向的循环或者直接用画矩形的扩展积木。如果角色本身有造型还要考虑是否隐藏角色、是否使用图章。这道题通常要求用画笔绘制所以角色要隐藏画笔粗细和颜色要设置好。另一个容易忽略的点是绘制顺序。如果先画大正方形再递归画小正方形小正方形会覆盖在大正方形上面视觉上没问题。但如果先递归再画大框可能会把已经画好的细节盖住。所以一般建议先画当前层的正方形边框再递归处理子层。2.3 递归终止条件的设定递归必须有终止条件否则会无限调用下去程序直接卡死。谢尔宾斯基地毯的终止条件通常是层数减到0或者边长小于某个阈值。用层数控制更直观。比如设定总层数为3每次递归层数减1当层数等于0时就不再递归直接返回。这样层数参数就变成了一个计数器控制递归深度。用边长控制也有道理因为边长每次变成原来的三分之一很快就会小于1个像素再画也没意义了。但边长控制需要处理浮点数精度问题而且不同层数对应的边长不好预设。所以实际比赛中用层数控制是更稳妥的选择。注意递归层数不要设太大。图形化编程环境的递归深度有限而且每层递归会产生8个子调用层数稍微大一点调用次数就爆炸。3层是8的3次方减一些大概几百次调用还能接受4层就是几千次可能会卡。小高组的题目一般要求2到3层就够了。3. 核心细节解析与实操要点3.1 九宫格坐标的推导过程假设当前正方形的左下角坐标是(x, y)边长是s。我们要把它分成3×3的九宫格每个小格子的边长是s/3。九个格子的左下角坐标分别是格子位置左下角x坐标左下角y坐标是否保留左下xy保留下中x s/3y保留右下x 2s/3y保留左中xy s/3保留中心x s/3y s/3挖掉右中x 2s/3y s/3保留左上xy 2s/3保留上中x s/3y 2s/3保留右上x 2s/3y 2s/3保留这个表格是整道题的核心。你需要在自制积木里用循环或者直接展开的方式遍历这8个保留的格子对每个格子计算新的左下角坐标和新的边长然后递归调用自己。用循环的话可以设两个变量dx和dy分别取0、1、2然后跳过dx1且dy1的情况。这样代码更简洁也更容易扩展到其他分形图形。3.2 自制积木的参数设计自制积木需要接收哪些参数至少需要三个左下角x坐标、左下角y坐标、当前边长。如果层数也作为参数传递那就是四个。层数也可以做成全局变量每次递归前减1递归后加回来但这样容易出错不如直接作为参数传递。在图形化编程里自制积木的参数可以是数字或字符串。建议把x、y、边长、层数都设为数字参数。定义积木时给它起一个有意义的名字比如画地毯 x y 边长 层数这样调用的时候一目了然。实操心得参数名不要太短也不要用a、b、c这种。用左下x、左下y、边长、剩余层数这样的名字调试的时候能省很多时间。我见过孩子用a、b、c做参数结果递归调用时传参顺序搞反了找了半小时才发现问题。3.3 画笔设置与绘制效率画笔的设置直接影响最终效果和运行速度。几个关键点画笔粗细如果画3层最内层的小正方形边长可能只有几个像素画笔太粗会糊成一团。建议根据层数动态调整或者统一用1到2的粗细。画笔颜色可以用单色也可以用不同层数不同颜色增强层次感。但颜色切换会增加绘制时间比赛时如果时间紧张单色最稳。绘制速度把绘制速度设为最快或者使用全部擦除后一次性绘制。图形化编程的画笔操作如果速度慢几百次调用会等很久。角色隐藏一定要把角色隐藏否则角色会挡在图形中间影响观感。另外每次开始绘制前要全部擦除否则上一次的图形会残留。这个细节很多孩子会忘导致运行两次后图形重叠看起来乱七八糟。3.4 递归调用的顺序与性能递归调用的顺序会影响绘制结果吗对于谢尔宾斯基地毯来说因为每个子正方形是独立的调用顺序不影响最终图形。但从性能角度先画小的还是先画大的可能会有细微差别。一般建议按从左到右、从下到上的顺序遍历8个格子这样绘制过程比较有规律也方便调试时观察。如果发现程序运行太慢可以考虑减少层数或者优化画笔操作比如用图章代替画笔绘制。还有一个性能技巧如果图形化编程环境支持运行时不刷新屏幕一定要打开。这样绘制过程中不会频繁刷新舞台速度会快很多。等全部画完再刷新一次用户体验也好。4. 完整实操流程与核心环节实现4.1 初始化与主程序结构整个程序的结构分为三部分初始化、主程序调用、自制积木定义。初始化部分要做几件事全部擦除、隐藏角色、设置画笔粗细和颜色、把角色移到起始位置。起始位置通常是舞台中心偏左下比如(-150, -150)这样边长为300的正方形能完整显示在舞台上。主程序部分很简单就是调用一次自制积木传入初始参数。比如当绿旗被点击 全部擦除 隐藏 将画笔粗细设为 2 将画笔颜色设为 黑色 画地毯 左下x-150 左下y-150 边长300 剩余层数3这里边长300、层数3是一个合理的配置。舞台宽度480高度360边长300的正方形放得下3层递归的调用次数也在可接受范围内。4.2 自制积木的递归实现自制积木画地毯的定义是整道题的核心。逻辑如下定义 画地毯 (左下x, 左下y, 边长, 剩余层数) 如果 剩余层数 0 那么 停止这个脚本 结束 // 画当前正方形的边框 抬笔 移到 x左下x y左下y 落笔 重复执行 4 次 移动 边长 步 右转 90 度 结束 // 递归处理8个子正方形 将 小边长 设为 边长 / 3 将 dx 设为 0 重复执行直到 dx 2 将 dy 设为 0 重复执行直到 dy 2 如果 dx 1 且 dy 1 那么 // 跳过中心格 否则 画地毯 左下x左下x dx * 小边长 左下y左下y dy * 小边长 边长小边长 剩余层数剩余层数 - 1 结束 将 dy 增加 1 结束 将 dx 增加 1 结束这段伪代码对应到图形化编程里就是用自制积木的递归调用。注意几个细节画边框之前要抬笔移到起点否则会从当前位置画一条线过去。递归调用时左下角坐标要加上dx和dy的偏移量偏移量是dx乘以小边长、dy乘以小边长。剩余层数减1后传入这样每递归一层就少一层。跳过中心格的条件是dx1且dy1这个条件不能写错。注意图形化编程里没有停止这个脚本这种积木的话可以用如果剩余层数 0 那么把整个逻辑包起来效果一样。不同平台的积木名称可能不同但逻辑是通用的。4.3 参数计算与边界处理参数计算里最容易出错的是坐标偏移。假设左下x-150边长300小边长100。那么dx0, dy0左下角(-150, -150)这是左下格dx1, dy0左下角(-50, -150)这是下中格dx2, dy0左下角(50, -150)这是右下格dx0, dy1左下角(-150, -50)这是左中格dx1, dy1左下角(-50, -50)这是中心格跳过dx2, dy1左下角(50, -50)这是右中格dx0, dy2左下角(-150, 50)这是左上格dx1, dy2左下角(-50, 50)这是上中格dx2, dy2左下角(50, 50)这是右上格这些坐标验证一遍确保没有算错。如果发现图形不对称或者缺了某一块大概率是坐标计算出了问题。边界处理方面要注意递归终止时不要画多余的边框。剩余层数为0时直接返回不画任何东西。另外如果边长太小比如小于2也可以提前终止避免画出一堆看不见的像素点。4.4 调试与验证方法调试递归程序最有效的方法是减少层数。先把层数设为1看看能不能画出一个正确的九宫格挖中心。如果1层对了再设2层检查每个小格子里是否又出现了九宫格挖中心。2层对了3层基本就没问题了。另一个方法是加日志。在递归调用前后打印当前参数看看调用次数和参数是否符合预期。图形化编程里可以用说积木输出调试信息但要注意输出太多会拖慢程序。还可以用不同颜色标记不同层数。比如第1层用黑色第2层用红色第3层用蓝色。这样一眼就能看出每一层画在哪里哪一层出了问题。我实际带学生做这道题时发现最常见的错误有三个一是中心格没跳过画出来是个完整的九宫格二是坐标偏移算错图形歪了或者重叠三是递归终止条件写错要么无限递归卡死要么只画了一层就停了。这三个问题用上面的调试方法都能快速定位。5. 常见问题与排查技巧实录5.1 程序卡死或运行极慢这是递归程序最常见的问题。原因通常是递归没有正确终止或者层数设得太大。排查步骤检查终止条件。剩余层数是否真的在每次递归时减1减1的操作是否在递归调用之前检查递归调用的参数。剩余层数传的是剩余层数 - 1还是剩余层数如果传的是原值永远不会终止。检查层数初始值。如果初始层数设成了10调用次数是8的10次方肯定卡死。小高组题目一般2到3层足够。如果确认逻辑没问题但还是慢可以尝试减少画笔操作比如用图章代替画边框或者关闭屏幕刷新。5.2 图形缺块或错位图形缺块通常是坐标计算错误或跳过条件写错。排查方法把层数设为1检查九宫格是否完整8个格子都在中心挖掉。如果1层正确把层数设为2检查每个小格子里的九宫格是否正确。用不同颜色标记不同层观察哪一层开始出错。错位问题一般是坐标偏移量算错了。检查dx和dy的乘数是不是小边长检查左下角坐标的基准点是不是当前正方形的左下角。5.3 画笔痕迹异常画笔痕迹异常包括多余的线、图形重叠、颜色不对等。多余的线通常是抬笔落笔的时机不对。画边框前要抬笔移到起点画完要抬笔。图形重叠可能是没有全部擦除或者递归时重复画了同一个格子。颜色不对检查画笔颜色的设置位置确保在绘制前设置好。5.4 常见问题速查表问题现象可能原因解决方法程序卡死递归未终止或层数过大检查终止条件减少层数只画了一层终止条件过早触发检查剩余层数参数传递中心格没挖掉跳过条件写错确认dx1且dy1时跳过图形歪斜坐标偏移计算错误重新推导九宫格坐标图形重叠未全部擦除或重复绘制开始时全部擦除检查循环范围画笔痕迹乱抬笔落笔时机不对画边框前抬笔移到起点运行速度慢画笔操作太多或屏幕刷新减少画笔操作关闭屏幕刷新实操心得比赛时如果时间紧张先把层数设为2确保能画出正确图形拿到基础分再尝试3层。不要一上来就追求3层结果卡死或者画错反而丢分。另外代码写完后一定要多运行几次确认每次结果一致避免偶然性错误。6. 从这道题延伸出去递归思维的训练价值谢尔宾斯基地毯这道题表面上是考图形化编程实际上是在考递归思维。递归是计算机科学里非常重要的概念但也是初学者最难理解的概念之一。图形化编程的好处是它把递归的调用过程可视化了孩子能直观地看到自己调用自己的效果。我带孩子练这道题的时候会先让他们用纸笔画。画一个正方形挖掉中心然后在剩下的8个格子里继续画。画到第三层纸上的图形已经很小了但孩子能理解每一层都在重复同样的操作。这个过程建立起来之后再回到图形化编程里写递归就水到渠成了。除了谢尔宾斯基地毯同样的递归思路还可以画谢尔宾斯基三角形、科赫雪花、分形树等。这些图形在信息素养大赛里都出现过核心逻辑是一样的定义基本操作然后让操作自己调用自己每次调用时参数缩小。如果孩子对这道题掌握得不错可以尝试几个扩展挑战。一是把正方形换成三角形画谢尔宾斯基三角形二是改变挖掉的位置比如挖掉四个角而不是中心三是用不同颜色标记不同层数做出彩色分形。这些扩展能帮助孩子真正理解递归的灵活性和威力。最后分享一个我在实际教学中发现的小技巧让孩子在递归调用前后各放一个说积木输出当前层数和坐标。运行程序时观察输出的顺序就能理解递归的深入和返回过程。这个技巧对理解递归的执行流程特别有效比单纯看代码直观得多。
返回列表