学习程序设计,必练河内塔问题。好的分析、实现,对于初学者有些帮助。
说明:
- 采用Java源代码风格;
- 采用doxygen风格的注释(也是Javadoc风格的注释);
- 为了输出美观,加了tabs,pLineNumber两个参数,让代码有点复杂了。但鉴于输出的美观也很重要,保留了这个复杂性。
/**
* $Id$
* wanzijin, 2014-05-09
*/
#include
#include
/**
* 河内塔问题求解(递归:中序遍历二叉树)
*
* @param pLineNumber 输出行号;
* @param tabs 缩进级别:用于控制输出的“缩进”量,纯美观设计,初学者可忽略它;
* 递归树的根缩进量为0,每下一层,则缩进量加8,在标准输出上可以得到比较美观的效果;
* @param n 要移动的盘子个数,定义域为非负整数,请尽量在[0,20]之间取值;
* n大于20的话,系统会表示负担很重,这与国际象棋盘上放谷粒的故事一个道理;-)
* @param a 源柱子,定义域为{'a','b','c'}
* @param b 中间柱子,定义域为{'a','b','c'}
* @param c 目标柱子,定义域为{'a','b','c'}
*
* @inv 缩进级别与递归层级的和(tabs+n);
* @inv {a,b,c}=={'a','b','c'}
*/
void hanoi_move(int *pLineNumber, int tabs, int n, char a, char b, char c)
{
if (n<2)
{
if(n==1)
{
// 只有一个盘子:直接搬到目标柱子上
printf("%4d,%*d:%c->%c\n",++pLineNumber[0],tabs*8,n,a,c);
}
return;
}
// 先把源柱子上的n-1个盘子搬到中间柱子上
hanoi_move(pLineNumber,tabs+1,n-1,a,c,b);
// 再把源柱子上的第n个盘子搬到目标柱子上
printf("%4d,%*d:%c->%c\n",++pLineNumber[0],tabs*8,n,a,c);
// 最后把中间柱子上的n-1个盘子搬到目标柱子上
hanoi_move(pLineNumber,tabs+1,n-1,b,a,c);
}
int main(int argc, const char *argv[])
{
int n,lineNumber=0;
if (argc<2)
{
// 教科书上很喜欢用scanf(),UNIX风格的“管道”、“重定向”等机制,也主张多用标准输入
printf("Input:");
scanf("%d",&n);
}
else
{
// 从单个“工具”角度,用“命令行参数”真心方便
// 取第二个命令行参数(命令名本身是第一个)
n = atol(argv[1]);
}
hanoi_move(&lineNumber,0,n,'A','B','C');
return 0;
}
输出实例:
e:\home\wzj\hanoyi\Debug>hanoyi 5
argv[0]=hanoyi
argv[1]=5
1, 1:A->C
2, 2:A->B
3, 1:C->B
4, 3:A->C
5, 1:B->A
6, 2:B->C
7, 1:A->C
8, 4:A->B
9, 1:C->B
10, 2:C->A
11, 1:B->A
12, 3:C->B
13, 1:A->C
14, 2:A->B
15, 1:C->B
16,5:A->C
17, 1:B->A
18, 2:B->C
19, 1:A->C
20, 3:B->A
21, 1:C->B
22, 2:C->A
23, 1:B->A
24, 4:B->C
25, 1:A->C
26, 2:A->B
27, 1:C->B
28, 3:A->C
29, 1:B->A
30, 2:B->C
31, 1:A->C