我的 Hanoi 算法Java实现。
通过三个函数,分别对Hanoi进行递归、非递归和非递归规律实现。
程序如下:
View Code
1 /* 2 * Hanoi塔游戏 问题描述: 3 * 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。 4 * 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照 5 * 大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小 6 * 顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在 7 * 三根柱子之间一次只能移动一个圆盘。 8 * 9 * fuction:实现 hanoi塔 10 * 1.递归实现 11 * 2.非递归实现 12 * author:iGeneral 13 * date:2013.04.26 14 * 15 * expe: 16 * 1.注意:塔的状态:当status=1时,表示可以直接将该Disk移动到目标塔 17 * 而不是用Disk的id来判断输出 18 * 2.System.out.println(); 19 System.out.println((int)3.3%3); 20 没有(int)时,输出:0.299999 21 加上(int)后,输出:0 22 */ 23 package part03.chapter10; 24 25 import java.util.Scanner; 26 27 public class _2exercise { 28 29 public static void main(String[] args) { 30 31 Scanner scanner = new Scanner(System.in); 32 System.out.println("请输入Hanoi碟子的数量:"); 33 int diskNum = scanner.nextInt(); 34 Hanoi hanoi = new Hanoi(); 35 System.out.println("递归实现:"); 36 hanoi.play_recursive(diskNum, 'A', 'B', 'C'); 37 System.out.println("非递归实现(模仿递归思想):"); 38 hanoi.play_non_recursive(diskNum); 39 System.out.println("非递归实现(根据Hanoi规律):"); 40 hanoi.play_regular(diskNum); 41 42 } 43 44 } 45 46 class Hanoi { 47 48 // 递归实现 49 public void play_recursive(int num, char A, char B, char C) { 50 if (num == 1) { 51 System.out.println(A + " -> " + C); 52 return; 53 } else { 54 play_recursive(num - 1, A, C, B); 55 System.out.println(A + " -> " + C); 56 play_recursive(num - 1, B, A, C); 57 } 58 59 } 60 61 // 非递归实现:模仿递归思想 62 public void play_non_recursive(int diskNum) { 63 Stack stack = new Stack(); 64 stack.push(new Disk(diskNum, 'A', 'B', 'C')); 65 Disk popDisk = null; 66 while ((popDisk = stack.pop()) != null) { 67 if (popDisk.status == 1) { 68 System.out.println(popDisk.A + " -> " + popDisk.C); 69 } else { 70 // 反顺序添加 71 // 将执行移动 popDisk 的下一步的Disk添加到Stack 72 stack.push(new Disk(popDisk.status - 1, popDisk.B, popDisk.A, 73 popDisk.C)); 74 // 将一个status为 "1" 且移动顺序与 popDisk 相同的Disk 添加到Stack中 75 stack.push(new Disk(1, popDisk.A, popDisk.B, popDisk.C)); 76 // 将执行移动 popDisk 的前一步的Disk添加到Stack中 77 stack.push(new Disk(popDisk.status - 1, popDisk.A, popDisk.C, 78 popDisk.B)); 79 } 80 } 81 } 82 83 // 非递归实现:根据Hanoi规律 84 public void play_regular(int diskNum) { 85 86 // 根据规律,需要根据 Disk 的个数,多塔的位置进行调整 87 // 塔的个数为偶数时,将三个塔按“A->B->C”的顺序排列成三角形 88 // 塔的个数为奇数时,将三个塔按"A->C->B"的顺序排列成三角形 89 // 将diskNum个Disk按”上小下大“的顺序放在A塔中(堆栈实现),同时将B塔和C塔置空 90 Stack_play_regular A = new Stack_play_regular('A'); 91 Stack_play_regular B = new Stack_play_regular('B'); 92 Stack_play_regular C = new Stack_play_regular('C'); 93 for (int i = diskNum; i > 0; i--) { 94 A.push(i); 95 } 96 // 将三个塔模拟成三角形形状排列 97 Stack_play_regular[] towers = new Stack_play_regular[3]; 98 towers[0] = A; 99 if (diskNum % 2 == 0) { 100 towers[1] = B; 101 towers[2] = C; 102 } else { 103 towers[1] = C; 104 towers[2] = B; 105 } 106 // 最小Dish所在的塔,通过该塔在towers中的 107 int towerOfMinimunDisk = 0; 108 // 根据证明:n个Disk移动完成至少需要2^n-1次 109 // 不断交替进行以下两步 110 // 将最小的Disk按以上塔的顺序下移到下一个塔 111 // 对除了最小Disk所在的塔的另外两个塔进行操作,可能出现两种情况 112 // 情况一:一个塔中没有Disk,此时将存在Disk的塔最上面的Disk移动到没Disk的塔上 113 // 情况二:两个塔都有Disk,此时对他们最上面的塔进行比较,将较小的Disk移动到较大的Disk上 114 // 不会存在两个塔都没有Disk的情况,除非移动已经完成或未开始或只有一个盘子时的移动 115 int ii = 0; 116 for (int i = 0; i < (Math.pow(2, diskNum) - 1);) {// --------------注意在此处不进行i++ 117 // 取出三个塔,使代码更清晰 118 Stack_play_regular tower = towers[towerOfMinimunDisk]; 119 Stack_play_regular tower_1 = towers[(int) ((towerOfMinimunDisk + 1) % 3)]; 120 Stack_play_regular tower_2 = towers[(int) ((towerOfMinimunDisk + 2) % 3)]; 121 // 移动最小的盘子 122 System.out.println(tower.name + " -> " + tower_1.name); 123 tower_1.push(tower.pop()); 124 i++;// --------------注意在此处进行i++ 125 towerOfMinimunDisk = (int) ((towerOfMinimunDisk + 1) % 3); 126 // ------------注意此时对三个tower进行重新赋值 127 tower = towers[towerOfMinimunDisk]; 128 tower_1 = towers[(int) ((towerOfMinimunDisk + 1) % 3)]; 129 tower_2 = towers[(int) ((towerOfMinimunDisk + 2) % 3)]; 130 // 对另外两个塔进行处理 131 if ((tower_2.getTop() != -1 && (tower_1.showTopDisk() > tower_2 132 .showTopDisk())) 133 // --------------注意要再加上 tower_2.getTop() != -1 134 // 进行判断,否则可能数组访问越界 135 || (tower_1.getTop() == -1 && tower_2.getTop() != -1)) { 136 System.out.println(tower_2.name + " -> " + tower_1.name); 137 tower_1.push(tower_2.pop()); 138 i++;// --------------注意在此处进行i++ 139 } else if (((tower_1.getTop() != -1 && tower_1.showTopDisk() < tower_2 140 .showTopDisk())) 141 // --------------注意要再加上 tower_1.getTop() != -1 142 // 进行判断,否则可能数组访问越界 143 || (tower_1.getTop() != -1 && tower_2.getTop() == -1)) { 144 System.out.println(tower_1.name + " -> " + tower_2.name); 145 tower_2.push(tower_1.pop()); 146 i++;// --------------注意在此处进行i++ 147 } 148 ii = i; 149 } 150 System.out.println(ii); 151 } 152 153 } 154 155 // 存放信息的结构体 156 class Disk { 157 // 从A塔通过B塔移动到C塔 158 char A; 159 char B; 160 char C; 161 // 塔的状态:当status=1时,表示可以直接将该Disk移动到目标塔 162 int status; 163 164 // 重写构造函数 165 public Disk(int status, char A, char B, char C) { 166 this.status = status; 167 this.A = A; 168 this.B = B; 169 this.C = C; 170 } 171 } 172 173 // 存放Disk的栈 174 class Stack { 175 // 用来存储盘子的数组 176 Disk[] disks = new Disk[10000]; 177 // 塔顶 178 private int top = 0; 179 180 // 查看栈顶 181 public Disk stackTop() { 182 return disks[top]; 183 } 184 185 // 出栈 186 public Disk pop() { 187 if (top != 0) { 188 top--; 189 return disks[top + 1]; 190 } else { 191 return null; 192 } 193 } 194 195 // 入栈 196 public void push(Disk disk) { 197 top++; 198 disks[top] = disk; 199 } 200 } 201 202 // 为 play_regular(int diskNum) 创建的 Stack 类 203 // 以 diskId 来表示 Disk 对象 204 class Stack_play_regular { 205 // 塔名 206 char name; 207 // 塔顶 208 private int top = -1; 209 210 public int getTop() { 211 return top; 212 } 213 214 // 通过数组实现Stack,最多64个Disk 215 int[] stack = new int[64]; 216 217 // 重写构造函数,初始化塔的名字name 218 public Stack_play_regular(char name) { 219 this.name = name; 220 } 221 222 // 查看栈顶 223 public int showTopDisk() { 224 if (top == -1) { 225 return -1; 226 } 227 return stack[top]; 228 } 229 230 // 入栈 231 public void push(int diskId) { 232 stack[++top] = diskId; 233 } 234 235 // 出栈 236 public int pop() { 237 return stack[top--]; 238 } 239 }