(转载)
发信人: mmc (毛毛虫-吃青菜), 信区: Datastructure
标 题: 汉诺塔非递归算法(转载)
发信站: 出水芙蓉 (2002年01月02日18:56:56 星期三), 站内信件
/* 这个算法是用java做的.
读完后就知道,汉诺塔问题其实就是一颗满二叉数
1 h(n,a,b,c)= h(n-1,a,c,b) + a->c + h(n-1,b,a,c) 对应一个二叉树
(a,b,c) ---0层
/ /
(a,c,b) (b,a,c) ---- 1层
2 实际上,整个递归算法走完了一个 n-1 层的二叉树,***是满二叉树。该树中,每
个节点的
左孩子等于该节点第二、三个参数交换,右孩子等于该节点第一、二个参数交换
3 我们完全可以通过建立二叉树的方法来实现该问题(第0层节点三个参数为 a,b,c),对
该树进行中序(中根)
遍历,便得到了整个操作序列。(各节点的处理为输出 第一参数 -> 第三参数)
4 完全二叉树可以用数组来表示和实现。但是,为了方便,我们要按照 中序(中根)
来建树。各节点间关系如下:
(为了方便,我们将第一个元素序号设为1,最上层为第 0 层,n 个盘子,设立一个
n-1层的树)
第 i 层第一个元素序号 为 2^( n-1-i)
第 i 层两个相临元素序号差值 2^( n-i) (当 i!= 0时)
-----上述关系无须证明,只把各节点序号用二进制数表示,则一目了然。
********************************************************************
本算法缺点:空间复杂度为 2^ n .但在此基础上,可以引入堆栈,减少空间需求。
但这样会减弱代码的可读性。
//*********************************************************************
5 以下讨论与本算法无关,但是可以让我们更进一步认识到该问题的实质
给树的每个边附加一个数 :左向边为0 ,右向边为 1
给每个节点标记为从根节点到该节点的路径中全部边。如图
@
/ /
0 / / 1
/ /
节点标记为“0” @ 略
/ /
0 / / 1
/ /
略 @ 节点标记为 “01”
| 1 0 0 |
定义 T(0)=| 0 0 1 |
| 0 1 0 |
| 0 1 0 |
定义 T(1)=| 1 0 0 |
| 0 0 1 |
两个矩阵,则
(a,b,c) * T(0)=( a,c,b )
(a,b,c) * T(1)=( b,a,c )
因此 节点 P的左孩子参数 = p 的参数 * T(0)
节点 P的右孩子参数 = p 的参数 * T(1)
各节点的 参数等于(a ,b,c) * 标记序列对应的 矩阵序列。
如上图最下层节点三个参数
= 最上层节点三个参数 * T(0) * T(1)
这样,每个节点的意义和节点间的关系都非常清楚
*/
class H{
char [][] oper;
H(int n){
int total=pow
;
oper=new char[total][3];//用于前序存放n-1层满二叉树,oper[0]冗余不用
int first=total/2;//first 指向每层第一个元素,当前为第0层第一元素
oper[first][0] ='a';//对第0层赋值
oper[first][1] ='b';
oper[first][2] ='c';
//从第0层开始,到第n-2层,每层对下一层赋值
for(int i=0;i<n-1;i++){
int gap=2*first;//第i层同层元素的间隔(i!=0时)
int subfirst=first/2;//下一层第一个元素
int subgap=gap/2;
for(int j=first;j<total;j+=gap){//第i 层每个元素,对其下层
oper[subfirst][0] =oper[j][0] ;
oper[subfirst][1]=oper[j][2];
oper[subfirst][2]=oper[j][1];
subfirst+=subgap;
oper[subfirst][0] =oper[j][1];
oper[subfirst][1]=oper[j][0] ;
oper[subfirst][2]=oper[j][2];
subfirst+=subgap;
}
first/=2;//first
}
System.out.println( "按照二叉数的格式化输出<左边为根,
向上为左子树,向下为右子树>");
for(int k=1;k<total;k++){
int tem=k,lay=n-1;
while (tem%2==0){tem/=2;lay--;}
tem=lay;
while (lay>0){System.out.print(" ");lay--;}
System.out.print (""+oper[k][0]+">"+oper[k][1]+">>"+oper[k][2]);
while(tem<n-1){System.out.print("----------");tem++;}
System.out.println (" (the "+k+ " th step)");
}
System.out.println( "/n按照二叉数中序便利输出(注意各行的对应关系)/
n");
for(int k=1;k<total;k++)System.out.println (""+oper[k][0]+">"
+oper[k][1]+">>"+oper[k][2]);
}
int pow(int y){
int result=1;
while(y>0){
result*=2;
y--;
}
return result;
}
}
public class Class1
{
public static void main (String[] args)
{
H h=new H(3);
try{System.in.read ();}catch (Exception e){}
}
}