汉诺塔的计算实现是算法课程中递归部分的经典案例。算法不难,但是要实现,还是要动点脑筋的。大致描述如下:
就是要把n个盘移动到目标柱,首先得把n-1个盘移动到临时柱。
然后把把剩下的最大的盘移动到目标柱。
然后把临时柱作为起始柱,原先的起始柱作为临时柱,重复上述步骤。
如果只移动起始柱的一个盘,就直接放到目标柱即可。
————————————————————————————
大致描述就是如此,大多算法书的输出无非是几个箭头移来移去,不直观。因此此处采用C#重新写了一遍,看注释即可明白。
其中Move_1和Move是一样的,仅仅是采用Last()方法还是用临时tmp的区别,个人认为用last更好理解点。本质都一样。
tolist.Add(fromlist.Last()); fromlist.Remove(fromlist.Last()); PrintStatus();
tolist.Add(tmp); fromlist.Remove(tmp); PrintStatus();
附代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Dynamic; namespace ConsoleApplication1 { class Program { //static List<int> l = new List<int>() { 1, 2, 3 }; static List<int> A = new List<int>() {10,9,8,7,6,5, 4, 3, 2, 1 }; static List<int> B = new List<int>() { }; static List<int> C = new List<int>() { }; static int count = 0; static void Main(string[] args) { PrintStatus(); Move_1(A.Count, ref A, ref B, ref C); Console.WriteLine("移动次数:" + count); } //Move,表示把n个盘子从fromlist,经过tmplist作为临时柱,移动到目标柱tolist static public void Move_1(int n, ref List<int> fromlist, ref List<int> tmplist, ref List<int> tolist) { if (n == 1) { tolist.Add(fromlist.Last()); fromlist.Remove(fromlist.Last()); PrintStatus(); } else { //由于下面要把fromlist中的n-1个盘子移动走,tmp则为移动走以后,剩下的那个盘子中最小的那个盘子。 int tmp = fromlist[fromlist.Count - n]; //先把fromlist上的n-1个盘子,经过tolist作为临时柱,移动到tmplist。 Move_1(n - 1, ref fromlist, ref tolist, ref tmplist); //把fromlist上剩下的那个盘子,移动到目标盘tolist tolist.Add(tmp); fromlist.Remove(tmp); PrintStatus(); //把临时柱作为起始柱(此时临时柱上只剩下n-1个盘片),原先的起始柱作为临时柱,重复上述的移动,移动到目标盘tolist Move_1(n - 1, ref tmplist, ref fromlist, ref tolist); } } //Move,表示把n个盘子从fromlist,经过tmplist作为临时柱,移动到目标柱tolist static public void Move(int n, ref List<int> fromlist, ref List<int> tmplist, ref List<int> tolist) { if (n == 1) { count++; tolist.Add(fromlist.Last()); fromlist.Remove(fromlist.Last()); PrintStatus(); } else { //Console.WriteLine("//先把fromlist上的" + (n - 1).ToString() + "个盘子,经过tolist作为临时柱,移动到tmplist。"); //先把fromlist上的n-1个盘子,经过tolist作为临时柱,移动到tmplist。 Move(n - 1, ref fromlist, ref tolist, ref tmplist); //Console.WriteLine("//把fromlist上剩下最小的那个盘子,移动到目标盘tolist"); //把fromlist上剩下最小的那个盘子,移动到目标盘tolist tolist.Add(fromlist.Last()); fromlist.Remove(fromlist.Last()); PrintStatus(); count++; //Console.WriteLine("//把临时柱作为起始柱(此时临时柱上只剩下" + (n - 1).ToString() + "个盘片),原先的起始柱作为临时柱,重复上述的移动,移动到目标盘tolist"); //把临时柱作为起始柱(此时临时柱上只剩下n-1个盘片),原先的起始柱作为临时柱,重复上述的移动,移动到目标盘tolist Move(n - 1, ref tmplist, ref fromlist, ref tolist); } } static public void PrintStatus() { Console.Write("A:"); A.ForEach((m) => Console.Write(m)); Console.WriteLine(); Console.Write("B:"); B.ForEach((m) => Console.Write(m)); Console.WriteLine(); Console.Write("C:"); C.ForEach((m) => Console.Write(m)); Console.WriteLine(); Console.WriteLine("-------------------"); } } }
-----------------5个盘的实现过程-----------
A:54321
B:
C:
-------------------
A:5432
B:
C:1
-------------------
A:543
B:2
C:1
-------------------
A:543
B:21
C:
-------------------
A:54
B:21
C:3
-------------------
A:541
B:2
C:3
-------------------
A:541
B:
C:32
-------------------
A:54
B:
C:321
-------------------
A:5
B:4
C:321
-------------------
A:5
B:41
C:32
-------------------
A:52
B:41
C:3
-------------------
A:521
B:4
C:3
-------------------
A:521
B:43
C:
-------------------
A:52
B:43
C:1
-------------------
A:5
B:432
C:1
-------------------
A:5
B:4321
C:
-------------------
A:
B:4321
C:5
-------------------
A:1
B:432
C:5
-------------------
A:1
B:43
C:52
-------------------
A:
B:43
C:521
-------------------
A:3
B:4
C:521
-------------------
A:3
B:41
C:52
-------------------
A:32
B:41
C:5
-------------------
A:321
B:4
C:5
-------------------
A:321
B:
C:54
-------------------
A:32
B:
C:541
-------------------
A:3
B:2
C:541
-------------------
A:3
B:21
C:54
-------------------
A:
B:21
C:543
-------------------
A:1
B:2
C:543
-------------------
A:1
B:
C:5432
-------------------
A:
B:
C:54321
-------------------
移动次数:31