数据结构和算法

DSA 主页 DSA 概述 DSA 环境设置 DSA 算法基础 DSA 渐近分析

数据结构

DSA 数据结构基础 DSA 数据结构和类型 DSA 数组数据结构

链接列表

DSA 链接列表数据结构 DSA 双向链接列表数据结构 DSA 循环链表数据结构

堆栈 &队列

DSA 堆栈数据结构 DSA 表达式解析 DSA 队列数据结构

搜索算法

DSA 搜索算法 DSA 线性搜索算法 DSA 二分搜索算法 DSA 插值搜索 DSA 跳跃搜索算法 DSA 指数搜索 DSA 斐波那契搜索 DSA 子列表搜索 DSA 哈希表

排序算法

DSA 排序算法 DSA 冒泡排序算法 DSA 插入排序算法 DSA 选择排序算法 DSA 归并排序算法 DSA 希尔排序算法 DSA 堆排序 DSA 桶排序算法 DSA 计数排序算法 DSA 基数排序算法 DSA 快速排序算法

图形数据结构

DSA 图形数据结构 DSA 深度优先遍历 DSA 广度优先遍历 DSA 生成树

树数据结构

DSA 树数据结构 DSA 树遍历 DSA 二叉搜索树 DSA AVL 树 DSA 红黑树 DSA B树 DSA B+ 树 DSA 伸展树 DSA 尝试 DSA 堆数据结构

递归

DSA 递归算法 DSA 使用递归的汉诺塔 DSA 使用递归的斐波那契数列

分而治之

DSA 分而治之 DSA 最大最小问题 DSA 施特拉森矩阵乘法 DSA Karatsuba 算法

贪婪算法

DSA 贪婪算法 DSA 旅行商问题(贪婪方法) DSA Prim 最小生成树 DSA Kruskal 最小生成树 DSA Dijkstra 最短路径算法 DSA 地图着色算法 DSA 分数背包问题 DSA 作业排序截止日期 DSA 最佳合并模式算法

动态规划

DSA 动态规划 DSA 矩阵链乘法 DSA Floyd Warshall 算法 DSA 0-1 背包问题 DSA 最长公共子序列算法 DSA 旅行商问题(动态方法)

近似算法

DSA 近似算法 DSA 顶点覆盖算法 DSA 集合覆盖问题 DSA 旅行商问题(近似方法)

随机算法

DSA 随机算法 DSA 随机快速排序算法 DSA Karger 最小割算法 DSA Fisher-Yates 洗牌算法

DSA 有用资源

DSA 问答 DSA 快速指南


使用递归的汉诺塔


汉诺塔

汉诺塔是一个数学谜题,由三座塔(桩)和多个如图所示的圆环组成。

汉诺塔

这些圆环大小不一,按升序堆叠,即较小的圆环位于较大的圆环之上。该谜题还有其他变体,其中圆盘数量增加,但塔的数量保持不变。

规则

任务是将所有圆盘移动到另一个塔中,且不违反排列顺序。汉诺塔需要遵循以下几条规则:−

  • 每次只能在塔之间移动一个圆盘。
  • 只能移除"顶部"的圆盘。
  • 大圆盘不能放在小圆盘上方。

以下是使用三个圆盘解决汉诺塔谜题的动画演示。

汉诺塔

使用 n 个圆盘的汉诺塔谜题最少可以用 2n−1 步解决。本演示显示,解决包含 3 个圆盘的难题需要 23 - 1 = 7 步。

算法

要编写汉诺塔算法,首先我们需要学习如何使用较少的圆盘数量(例如 1 或 2 个)来解决这个问题。我们为三个塔分别标记了名称、源、目标 和 辅助(仅用于帮助移动圆盘)。如果我们只有一个圆盘,那么它可以轻松地从源柱移动到目标柱。

如果我们有两个圆盘 −

  • 首先,我们将较小的(顶部)圆盘移动到辅助柱。
  • 然后,我们将较大的(底部)圆盘移动到目标柱。
  • 最后,我们将较小的圆盘从辅助柱移动到目标柱。
双圆盘汉诺塔

现在,我们可以设计一个包含两个以上圆盘的汉诺塔算法了。我们将圆盘堆分成两部分。最大的盘子(第 n 个盘子)位于一个部分,所有其他 (n-1) 个盘子位于另一个部分。

我们的最终目标是将盘子 n 从源移动到目标,然后将所有其他 (n1) 个盘子放到上面。我们可以想象以递归的方式对所有给定的盘子集合应用相同的操作。

步骤如下:−

步骤 1 − 将 n-1 个盘子从 源 移动到 辅助
步骤 2 − 将第 n 个盘子从 源 移动到 目标
步骤 3 −将 n-1 个盘子从 aux 移动到 dest

汉诺塔的递归算法可以如下实现 −

START
Procedure Hanoi(disk, source, dest, aux)

   IF disk == 1, THEN
      move disk from source to dest             
   ELSE
      Hanoi(disk - 1, source, aux, dest)     // Step 1
      move disk from source to dest          // Step 2
      Hanoi(disk - 1, aux, dest, source)     // Step 3
   END IF
   
END Procedure
STOP

示例

以下是该方法在各种编程语言中的实现 −

#include <stdio.h>
void hanoi(int n, char from, char to, char via) {
   if(n == 1){
      printf("Move disk 1 from %c to %c
", from, to);
   }
   else{
      hanoi(n-1, from, via, to);
      printf("Move disk %d from %c to %c
", n, from, to);
      hanoi(n-1, via, to, from);
   }
}
int main() {
   int n = 3;
   char from = 'A';
   char to = 'B';
   char via = 'C';
   //calling hanoi() method
   hanoi(n, from, via, to);
}
#include <iostream>
using namespace std;
void hanoi(int n, char from, char to, char via) {
   if(n == 1){
      cout<<"Move disk 1 from "<<from<<" to "<<to<<endl;
   }
   else{
      hanoi(n-1, from, via, to);
      cout<<"Move disk "<<n<<" from "<<from<<" to "<<to<<endl;
      hanoi(n-1, via, to, from);
   }
}
int main() {
   int n = 3;
   char from = 'A';
   char to = 'B';
   char via = 'C';
   //calling hanoi() method
   hanoi(n, from , via, to);
}
import java.util.*;
public class Demo {
   public static void hanoi(int n, String from, String to, String via) {
      if(n == 1){
         System.out.println("Move disk 1 from " + from + " to " + to);
      }
      else{
         hanoi(n-1, from, via, to);
         System.out.println("Move disk " + n + " from " + from + " to " + to);
         hanoi(n-1, via, to, from);
      }
   }
   public static void main(String[] args) {
      int n = 3;
      String from = "A";
      String to = "B";
      String via = "C";
      //calling hanoi() metod
      hanoi(n, from, via, to);
   }
}
def hanoi(n, f, to, via):
    if n == 1:
        print("Move disk 1 from",f,"to",to);
    else:
        hanoi(n-1, f, via, to)
        print("Move disk",n,"from",f,"to",to);
        hanoi(n-1, via, to, f)
n = 3
f = 'A'
to = 'B'
via = 'C'
hanoi(n, f, via, to)

输出

Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C