tonglin0325的个人主页

Java递归算法——汉诺塔问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Tower_demo {

static int nDisks = 3;

public static void main(String[] args) {
doTower(nDisks, 'A', 'B', 'C');
}

public static void doTower(int topN,char from,char inter,char to){
if(topN == 1)
System.out.println("Disk 1 from "+from+" to "+to);
else{
doTower(topN-1, from, to, inter);
System.out.println("Disk "+topN+" from "+from+" to "+to);
doTower(topN-1, inter, from, to);
}
}

}

 

通过二叉树的中序遍历过程来分析汉诺塔问题:

考虑A、B、C三根柱子,A上从上到下有1、2、3三个数,要把A上的数移动到C上,其过程应该是

**      A  B  C**

初始  123

A->C   23     1

A->B   3  2   1

C->B   3   12  

A->C      12  3

B->A   1  2   3

B->C   1      23

A->C          123

 

可以写成下图二叉树的中序遍历

在程序中有两个输出语句,

结束条件中的数据语句输出的是二叉树中的叶子结点

递归左子树和递归右子树中间的输出语句输出是所有的非叶子结点

所有左孩子和右孩子输出语句中得到的实际参数都是其父结点传递的,根节点输出语句得到的参数是初始传递的参数

 

 <1>首先确定递归函数的形式

1
2
doTower(int topN,char from,char inter,char to)

 <2>在main中**给根节点传递的初始值为(A,B,C) **

 对于根节点的输出A->C

可以确定递归左子树和递归右子树中间的输出语句应该输出 from->to,即

1
2
System.out.println("Disk "+topN+" from "+from+" to "+to);

 <3>步骤<2>确定了递归左子树和递归右子树中间的输出语句的格式,

对于根节点(A->C)的左孩子(A->B)和右孩子(B->C),由于都是非叶子结点,所以它们使用的仍然是递归左子树和递归右子树中间的输出语句 from->to

所以对于左孩子(A->B),要输出(A->B),可以确定出给其传递的参数应该是(A,C,B)

对于右孩子(B->C),要输出(B->C),可以确定出给其传递的参数应该是(B,A,C)

又因为所有左孩子和右孩子输出语句中得到的实际参数都是其父结点传递的,由于父节点得到的实参是(frmo=A,inter=B,to=C)

左孩子要想得到(A,C,B),给其传递的顺序应该是(from,to,inter)

右孩子要想得到(B,A,C),给其传递的顺序应该是(inter,from,to)

即确定了

1
2
3
4
doTower(topN-1, from, to, inter);

doTower(topN-1, inter, from, to);

 

 

<4>最后确定结束条件中的输出语句的输出顺序

由于上一步确定了

1
2
3
4
doTower(topN-1, from, to, inter);

doTower(topN-1, inter, from, to);

 对于A->B的左孩子A->C,由于在A->B结点中,from=A,inter=C,to=B,所以执行了doTower(topN-1, from, to, inter)后,给A->C传递的参数应该是(A,B,C),想要输出A->C,可以确定结束条件中的输出语句为

1
2
System.out.println("Disk 1 from "+from+" to "+to);

 同理,对于A->B的右孩子C->B,由于在A->B结点中,from=A,inter=C,to=B,所以执行了doTower(topN-1, inter, from, to)后,给C->B传递的参数应该是(C,A,B),可以输出C->B