news 2026/8/30 6:49:45

C语言经典算法:青蛙跳台阶与汉诺塔

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言经典算法:青蛙跳台阶与汉诺塔

本文用最通俗的语言讲解两个经典的递归问题,所有代码均为 C 语言实现,不涉及指针,适合正在学习函数与递归的读者。


一、青蛙跳台阶

1.1 这个问题从哪来?

小时候上楼梯,你有没有想过:如果每次可以跨 1 级或 2 级,那么上第 5 级楼梯有多少种走法?

这个问题和“青蛙跳台阶”一模一样。它其实是著名的斐波那契数列的一个实际应用场景——每一项都等于前两项之和。

1.2 问题描述

一只青蛙每次可以跳1 级2 级台阶。问:跳上第n级台阶,总共有多少种不同的跳法?

我们先看几个小例子找找感觉:

台阶数所有跳法种数
1(1)1
2(1,1)、(2)2
3(1,1,1)、(1,2)、(2,1)3
4(1,1,1,1)、(1,1,2)、(1,2,1)、(2,1,1)、(2,2)5

规律出来了:从第 3 项开始,f(n) = f(n-1) + f(n-2)

为什么?因为青蛙最后一步只有两种可能:
- 从n-1级跳 1 级上来 → 前面有f(n-1)种走法
- 从n-2级跳 2 级上来 → 前面有f(n-2)种走法

把这两种情况加起来,就是总数。

1.3 非递归解法(循环版)

不用递归,我们也能做。就像你爬楼梯时一步一步数上去,循环从 1 算到 n 就行。

为了代码简单,我们只保留最近的两项,用三个变量“接力”前进:

#include <stdio.h> /* 青蛙跳台阶 - 非递归(循环版) 思路:从第 1 级、第 2 级开始,一步步算到第 n 级 只用三个变量,像接力赛跑一样往前传递 / int frog_jump(int n) { / 处理特殊情况 */ if (n <= 0) return 0; if (n == 1) return 1; if (n == 2) return 2; int prev2 = 1; /* 代表 f(n-2),即前两项中的前一项 / int prev1 = 2; / 代表 f(n-1),即前两项中的后一项 / int current = 0; / 当前正在计算的这一级 */ int i; /* 从第 3 级开始,一直算到第 n 级 / for (i = 3; i <= n; i++) { current = prev1 + prev2; / 当前级 = 前两级之和 / prev2 = prev1; / 大家往前挪一步 */ prev1 = current; } return current; } int main() { int n; printf("请输入台阶数:"); scanf("%d", &n); printf("跳上 %d 级台阶共有 %d 种跳法\n", n, frog_jump(n)); return 0; }

核心思想:就像你爬楼梯时只记得“上两级有多少种走法”和“上一级有多少种走法”,就能算出这一级有多少种走法,更早的数据不需要记了。

1.4 递归解法

递归的写法非常自然,几乎就是把我们刚才的分析翻译成代码:

#include <stdio.h> /* 青蛙跳台阶 - 递归版 思路:f(n) = f(n-1) + f(n-2) 边界条件:1 级台阶有 1 种,2 级台阶有 2 种 / int frog_jump_recur(int n) { / 边界条件:递归到这里就不再往下拆了 */ if (n == 1) return 1; if (n == 2) return 2; /* 把大问题拆成两个子问题,结果相加 */ return frog_jump_recur(n - 1) + frog_jump_recur(n - 2); } int main() { int n; printf("请输入台阶数:"); scanf("%d", &n); printf("跳上 %d 级台阶共有 %d 种跳法\n", n, frog_jump_recur(n)); return 0; }

为什么能这样写?

想象青蛙站在第n级台阶上回头看,它最后一步只有两种来路:
- 从n-1级跳上来的 → 有多少种来路?问f(n-1)
- 从n-2级跳上来的 → 有多少种来路?问f(n-2)

一直问到n=1n=2,这就是“边界”,边界知道了,一层层返回来就能算出答案。

小提示:递归代码虽然好看,但当n比较大时(比如超过 40),会因为重复计算太多而变得很慢。平时写代码推荐用上面的循环版。


二、汉诺塔

2.1 这个问题从哪来?

汉诺塔(Hanoi)是一个古老的印度传说:

神庙里有三根金刚石柱子,第一根上套着 64 个大小不等的金盘,大的在下,小的在上。僧侣们要把这 64 个金盘从第一根柱子移到第三根柱子,规则是每次只能移动一个盘,且大盘不能压在小盘上。据说当所有盘子都移完时,世界就会毁灭。

当然,这只是个传说。但这个游戏确实是一个非常经典的递归思维训练题。

2.2 问题描述

有三根柱子:A(起始)、B(辅助)、C(目标)。A柱上有n个盘子,从上到下从小到大排列。要求把所有盘子从A移到C,每次只能移一个,大盘不能压小盘。

2.3 递归解法

这是汉诺塔最经典、最优雅的解法。核心思路就一句话:

把上面的n-1个盘子先挪走,把最底下那个大盘子直接移到目标柱,再把那n-1个盘子移过来。

就像搬家:先把家具都搬到临时房间,把大床搬进主卧,再把家具从临时房间搬进来。

#include <stdio.h> /* 汉诺塔 - 递归版 参数说明: n :要移动的盘子数量 from :从哪根柱子移出 to :移到哪根柱子 via :借助哪根柱子(中转站) 思路: 把上面 n-1 个盘子从 from 移到 via(借助 to) 把第 n 个盘子从 from 直接移到 to 把 via 上的 n-1 个盘子移到 to(借助 from) / void hanoi(int n, char from, char to, char via) { / 边界条件:只有一个盘子,直接搬 */ if (n == 1) { printf("将盘子 1 从 %c 移动到 %c\n", from, to); return; } /* 第 1 步:把上面 n-1 个盘子搬到中转柱 */ hanoi(n - 1, from, via, to); /* 第 2 步:把最底下的大盘子搬到目标柱 */ printf("将盘子 %d 从 %c 移动到 %c\n", n, from, to); /* 第 3 步:把中转柱上的 n-1 个盘子搬到目标柱 / hanoi(n - 1, via, to, from); } int main() { int n; printf("请输入盘子个数:"); scanf("%d", &n); / 从 A 柱移到 C 柱,B 柱作为中转 */ hanoi(n, 'A', 'C', 'B'); return 0; }

运行结果(3 个盘子时):

将盘子 1 从 A 移动到 C 将盘子 2 从 A 移动到 B 将盘子 1 从 C 移动到 B 将盘子 3 从 A 移动到 C 将盘子 1 从 B 移动到 A 将盘子 2 从 B 移动到 C 将盘子 1 从 A 移动到 C

你可以拿三个大小不一的硬币在桌上摆一摆,完全吻合!

2.4 非递归解法(思路简述)

汉诺塔的非递归写法需要自己用数组模拟系统栈,手动记录每一步该做什么、做到哪了。代码量很大,逻辑也比较绕,对初学者不太友好。

其核心思想是:递归其实是系统在帮我们管理一个“任务清单”。非递归版本就是自己写代码维护这个清单——每遇到一个子问题就记下来,做完一个划掉一个。

如果你感兴趣,可以记住这个结论:汉诺塔的非递归 = 用循环 + 数组栈 手动模拟递归的过程。理解了递归的本质后,再回头挑战非递归会轻松很多。

对于汉诺塔问题,递归解法不仅代码最简洁,而且本身就是最优的(数学上已证明最少需要移动 2ⁿ-1 次),所以实际学习和面试中,掌握递归版本就足够了


三、一句话总结

问题非递归核心递归核心
青蛙跳台阶从第 1 级开始,一步步“接力”算到第 n 级f(n) = f(n-1) + f(n-2),问到边界就回头
汉诺塔自己用数组模拟栈,手动管理任务(较复杂)先把上面的盘子挪走,移最底下的,再把上面的挪回来

递归的精髓就三步:
1.找规律—— 大问题怎么拆成小问题?
2.写边界—— 小到什么程度可以直接给出答案?
3.相信递归—— 假设子问题已经解决,只管把它们拼起来。

希望这篇文章能帮你跨过递归这道坎!如果有疑问,欢迎在评论区交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 6:44:18

英伟达6730亿美元销售目标:AI算力全栈技术与瓶颈

这则新闻不只是一条财经快讯&#xff0c;它的信息量比表面看起来大得多。6730 亿美元的销售预期&#xff0c;放在当前英伟达的营收基数和全球 AI 基础设施投资节奏里&#xff0c;意味着未来几个财年要保持远高于行业平均的增速。对于做模型部署、算力规划、云架构选型&#xff…

作者头像 李华
网站建设 2026/8/30 6:43:00

B2B企业怎么做好AI生态获客?拓氪科技AIGEO引擎有哪些核心优势?

过去十年&#xff0c;搜索引擎长期占据企业线上获客核心主场&#xff0c;行业营销打法趋于标准化、成熟化。多数企业依托竞价投放、SEO关键词优化、全域内容铺量等常规模式&#xff0c;稳定获取公域流量、承接商业客户。但随着通用人工智能全面落地普及&#xff0c;用户信息检索…

作者头像 李华
网站建设 2026/8/30 6:40:17

MOSS-VL Technical Report——MOSS-VL 技术报告

一、研究定位与核心目标 核心定位&#xff1a; MOSS-VL是一个开源的视觉-语言模型家族&#xff0c;首创性地将“实时交互”作为一等公民能力——即模型能够在生成文本的同时持续感知新到达的视觉帧&#xff0c;并在证据变化时动态修正或打断自己的回复。 关键突破&#xff1a…

作者头像 李华
网站建设 2026/8/30 6:38:49

ISM330DHCX自检失败排查:从硬件到寄存器的完整指南

很多玩过ST六轴IMU的工程师&#xff0c;第一次在板子上读到ISM330DHCX返回“Self-test failed”时&#xff0c;第一反应基本都是“芯片是不是坏了”。我也一样&#xff0c;几年前第一次在项目里用这颗料&#xff0c;自检一失败就开始怀疑采购渠道、怀疑焊接、怀疑人生&#xff…

作者头像 李华
网站建设 2026/8/30 6:37:15

大模型后训练与RLVR:用可验证奖励实现稳定推理

大模型后训练&#xff08;post-training&#xff09;和可验证强化学习&#xff08;RLVR&#xff0c;Reinforcement Learning with Verifiable Rewards&#xff09;是当前从“模型会生成”走向“模型能稳定解决问题”的关键环节。斯坦福大模型开发课 EP16 把这条链路单独拎出来讲…

作者头像 李华