java算法系列,第五篇:汉诺塔问题

文章讲述了印度传说中的汉诺塔问题,它是递归算法的典型示例。通过Java代码实现汉诺塔移动圆盘的过程,分析了解题策略和时间复杂度为O(2^n)。最后计算了移动64片圆盘所需的时间,显示了其在实际中的巨大挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片,一次只移动一片,不管在哪根针上,小片必在大片上面。当所有的金片都从梵天穿好的那根针上移到另外一概针上时,世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽。

汉诺塔问题是一个经典的数学问题,也是计算机科学中常用于演示递归算法的示例之一。现在问题归纳如下:

问题:

有三根柱子(通常称为 A、B 和 C),初始时,在柱子 A 上有 n 个从上到下依次递减大小的圆盘。要求将这些圆盘从柱子 A 移动到柱子 C,每次只能移动一个圆盘,并且不能将较大的圆盘放在较小的圆盘上面。

目标:

将所有圆盘从柱子 A 移动到柱子 C,保持规则。

解题思路:

递归逻辑:
1.先把a的除最下面那个盘子意外的其他盘子移到b。为了实现这一步就得先把第一个移到c,第二个移到b,然后把c那个移到b。这时c就空了。
2.把a的最后一个移到空出来的c,这时a就空了
3.把b移到c,为了实现这一步就必须先把b上面那个移到空出来的a。再把下面那块移到c上面,最后把现在a上面那个,也就是最小那个放到c
这个是小学生都会玩的游戏😂
他的递归思想就是先把问题分成大三步,再在每个问题依次这么去分解,最后把所有大问题都解决掉,问题就ok了。跟怎么把大象赛冰箱里去的思路一样,第一步开门,第二步塞进去,第三步关门。最难的就是第二步赛进去,那就把第二步分解成小问题,依次解决掉,最后“塞进去”这个大问题就OK了,然后门一关就完事了。

上代码:

  1. package main.java.honphie;
  2. import java.util.LinkedList;
  3. public class Hannoi {
  4. static LinkedList<Integer> A = new LinkedList<>();
  5. static LinkedList<Integer> B = new LinkedList<>();
  6. static LinkedList<Integer> C = new LinkedList<>();
  7. static void init(int n) {//创建1-n范围的数据
  8. for (int i = n; i > 0; i--) {
  9. A.addFirst(i);
  10. }
  11. }
  12. /**
  13. * @param n 盘子的数量
  14. * @param a 源柱子
  15. * @param b 中间柱子(借)
  16. * @param c 目标柱子
  17. */
  18. static void move(int n, LinkedList<Integer> a, LinkedList<Integer> b, LinkedList<Integer> c) {
  19. if (n == 0) {
  20. return;
  21. }
  22. move(n - 1, a, c, b);//把A柱子上的n-1个盘子移动到B柱子上(a借b移到c)
  23. c.addFirst(a.removeFirst());//把A柱子上的最后一个盘子移动到C柱子上
  24. System.out.println("n="+n);
  25. print();
  26. move(n - 1, b, a, c);//把B柱子上的n-1个盘子移动到C柱子上(b借a移到c)
  27. //所需执行时间:T(n) = 2T(n-1)+c
  28. //推导为:T(n) = c(2^n - 1)
  29. //时间复杂度:Θ(2^n)
  30. }
  31. public Hannoi(int n) {
  32. init(n);
  33. print();
  34. long start = System.nanoTime();
  35. hannoi(n, A, B, C);
  36. if(n==1){//通过单次挪动时间和时间复杂度求挪完64块所需的时间
  37. long end = System.nanoTime();
  38. double time = (end - start) / Math.pow(10,6);
  39. System.out.println("单次移到耗时: " + time + "ms");
  40. long ms=(long) (time*Math.pow(2,64));
  41. long year= ms/(1000*60*60*24*365);
  42. System.out.println("挪完64片预计需要: " + ms + "ms, 约为" + year + "年");
  43. }
  44. }
  45. private static void print() {
  46. System.out.println("A: " + A);
  47. System.out.println("B: " + B);
  48. System.out.println("C: " + C);
  49. System.out.println("-------------");
  50. }
  51. }

n=3,执行结果:

 顺便计算一下,不考虑栈内存的情况下,这个程序要执行多久:

输入n=1;

啊,要 62亿多年,假如僧人以流水线工人的手速挪动,就一秒钟一块的话,日夜不停,也需要大约10*10^3年,即一万亿年多。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他
点击体验
DeepSeekR1满血版
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回顶部

登录后您可以享受以下权益:

×