递归的基础训练day01
汉诺塔问题

前言
汉诺塔问题是一个经典的递归问题,其编程思想主要体现在以下几个方面:
- 分解问题:将汉诺塔问题分解为若干个子问题,每个子问题都是将一个盘子从一个柱子移动到另一个柱子。通过将大问题分解为小问题,可以更容易地处理和解决。
- 递归思考:汉诺塔问题的解决方法是递归的。在解决一个较大规模的汉诺塔问题时,可以将它分解为几个较小规模的汉诺塔问题,并且这些较小规模的问题与原问题具有相同的解决方案。通过递归调用自身,可以逐步解决较小规模的问题,并最终解决原问题。
- 设定状态:在编程解决汉诺塔问题时,需要设定状态来跟踪每个盘子的位置以及移动的方向。通常使用三个变量来表示三个柱子的状态,以及一个变量来表示当前正在移动的盘子。
- 设计算法:根据汉诺塔问题的规则和递归思想,可以设计出一个算法来解决该问题。算法需要明确如何移动盘子、如何判断移动是否合法、如何记录移动的步骤等。
选用多个单参数的递归函数
public class Code01_Hanoi {
public static void hanoi1(int n) {
leftToRight(n);
}
public static void leftToRight(int n) {
if (n == 1) {
System.out.println("把第 " + n + " 个圆盘" + "从左边放到右边");
return;
}
leftToMid(n - 1);
System.out.println("把第 " + n + " 个圆盘" + "从左边放到右边");
midToRight(n - 1);
}
public static void leftToMid(int n) {
if (n == 1) {
System.out.println("把第 " + n + " 个圆盘" + "从左边放到中间");
return;
}
leftToRight(n - 1);
System.out.println("把第 " + n + " 个圆盘" + "从左边放到中间");
rightToMid(n - 1);
}
public static void midToRight(int n) {
if (n == 1) {
System.out.println("把第 " + n + " 个圆盘" + "从中间放到右边");
return;
}
midToLeft(n - 1);
System.out.println("把第 " + n + " 个圆盘" + "从中间放到右边");
leftToRight(n - 1);
}
public static void rightToMid(int n) {
if (n == 1) {
System.out.println("把第 " + n + " 个圆盘" + "从右边放到中间");
return;
}
rightToLeft(n - 1);
System.out.println("把第 " + n + " 个圆盘" + "从右边放到中间");
leftToMid(n - 1);
}
public static void midToLeft(int n) {
if (n == 1) {
System.out.println("把第 " + n + " 个圆盘" + "从中间放到左边");
return;
}
midToRight(n - 1);
System.out.println("把第 " + n + " 个圆盘" + "从中间放到左边");
rightToLeft(n - 1);
}
public static void rightToLeft(int n) {
if (n == 1) {
System.out.println("把第 " + n + " 个圆盘" + "从右边放到左边");
return;
}
rightToMid(n - 1);
System.out.println("把第 " + n + " 个圆盘" + "从右边放到左边");
midToLeft(n - 1);
}
}
选用多参数的递归函数
public static void hanoi2(int n){
f(n,"左边","右边","中间");
}
public static void f(int n,String from,String to,String other){
if(n == 1){
System.out.println("把第 " + n + " 个圆盘" + "从" + from + "放到" + to);
return;
}
f(n-1,from,other,to);
System.out.println("把第 " + n + " 个圆盘" + "从" + from + "放到" + to);
f(n-1,other,to,from);
}
总结
在解决汉诺塔问题时,使用多个带一个参数的递归函数和使用一个带多个参数的递归函数相比,各有优缺点。
使用多个带一个参数的递归函数,可以让每个递归函数专注于一个具体的子问题,这样代码更加清晰和易于理解。此外,这种方式可以更容易地对不同的子问题进行分别处理,例如在移动盘子时需要考虑盘子的颜色和大小等因素。然而,这种方式需要更多的函数调用和重复代码,尤其是在处理较大的汉诺塔问题时,可能会导致代码膨胀和效率降低。
使用一个带多个参数的递归函数可以将所有的子问题都集中到一个函数中处理,减少了函数调用和重复代码的数量。这种方式还可以方便地处理更复杂的问题,例如汉诺塔问题变种或其他类似问题。然而,这种方式可能会使代码更加复杂和难以理解,需要更多的参数来传递状态和信息,而且对于一些特定的问题可能需要手动设置初始条件和边界条件。
综上所述,使用多个带一个参数的递归函数和使用一个带多个参数的递归函数各有优缺点,选择哪种方式取决于具体的问题和应用场景。在编写代码时,需要根据实际情况进行权衡和选择。