该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
26 }
27
28 if (last != britop && ((britop%2 && britop>srctop) || ((britop%2==0) && britop>dsttop)))
29 {
30 sbri.pop();
31 last = britop;
32 britop % 2 ? ssrc.push(britop) : sdst.push(britop);
33
34 if (britop % 2)
35 cout<
36 else
37 cout<
38 }
39
40 if (last != dsttop && ((dsttop%2 && dsttop>britop) || ((dsttop%2==0) && dsttop>srctop)))
41 {
42 sdst.pop();
43 last = dsttop;
44 dsttop % 2 ? sbri.push(dsttop) : ssrc.push(dsttop);
45 if (dsttop % 2)
46 cout<
47 else
48 cout<
49 }
50 }
51 }
看上面的代码好象复杂了点,不过主要还是因为判别的条件太复杂了,才会导致这段代码这么难懂。在这个while循环里面有3个if语句都在判定当前的盘子是否可以被移动,如果可以移动就移动它并且打印出来。
对于一个盘子要可以移动要满足以下2个条件
1. 前一次没有被移动过也就是不能够等于last
2. 盘子的编号必须要大于目标盘最上面的盘子的编号
这两个条件都要满足才能移动,可以证明在任何时候可以移动的盘子都是唯一的。
为了便于和开始的方法比较,在输出的时候对盘子的编号做了个转换,还是把它还原成原来的编号的方法。也就是编号小的在上,编号大的在下。上面我这个写法实在是太不简洁了,希望有写得更好的替换它。
3.递归的方法
尽管书上已经有递归的方法,不过我还是要给出我的递归的方法,作为参考。然后用于性能的比较。
3 #define move(disk,src,dst) cout<
4 void hanoi_r(int size,char src,char dst,char bri)
5 {
6 if (size == 1)
7 move(size,src,dst);
8 else
9 {
10 hanoi_r(size-1,src,bri,dst);
11 move(size,src,dst);
12 hanoi_r(size-1,bri,dst,src);
13 }
14 }
4.各种方法的比较
有不同的实现方法,当然就有对比,我一直以为非递归的方法要比递归的方法要快一些,不过结果好象并不是这样。
由于打印输出需要消耗部少的时间,所以我就把它去掉了,只是改动我定义的宏就可以了。
堆栈
#define print_oprt(op)
递归
#define move(disk,src,dst)
表示这个打印操作什么都不做。
下面是我在我的计算机上虚拟的Linux环境下用3种不同的方法解决规模为1-30的汉诺塔问题所花的时间的比较结果(单位是秒),你也可以把这个程序下载到你的计算机上去测试一下。
Scale Stack Recursion Other (1-30)
1 0 0 0
2 0 0 0
3 0 0 0
4 0 0 0
5 0 0 0
6 0 0 0
7 0 0 0
8 0 0 0
9 0 0 0
10 0 0 0
11 0 0 0
12 0 0 0
13 0 0 0
14 0 0 0.01
15 0 0 0.01
16 0.02 0 0.01
17 0.03 0 0.03
18 0.05 0 0.05
19 0.12 0 0.12
20 0.23 0.01 0.23
21 0.49 0.01 0.47
22 0.95 0.04 0.89
23 1.92 0.07 1.87
24 3.8 0.15 3.55
25 7.65 0.3 7.52
26 15.2 0.6 14.24
27 30.49 1.2 29.7
28 61.11 2.41 57.24
29 111.15 4.29 97.56
30 201.09 7.72 184.32
用堆栈和其它的方法所花的时间比较接近,而用递归的速度却是最快的。相差非常的大。到底是什么原因呢,按理说应该不会有这么大的差别哦。
总结了一下,大概有以下原因:
1. STL本身的效率不是太高
STL功能强大了,效率上必然要受到一定的影响
2. 递归的方式函数调用比较少,就是调用它本身,而其它方式函数调用比较多
从代码中我们就可以看出,非递归方式调用函数的次数远远比递归方式多,每次移动操作都要调用好几次函数,pop,push等,而递归方式,每次移动操作只调用本身一次,故系统堆栈的负担要小的多。
3. 对堆栈实现,涉及到对象的多次构造和析构,并且还有就是堆栈的多次重新分配也需要消耗不少的时间(STL中stack是顺序存储结构,当空间不够用时,再向系统申请双倍的空间)
附录
上面提到的所以代码我都已经把它压缩好了,并且提供下载,
http://www.freewebs.com/zhengsh/download/hanoi.tar.gz
在readme文件中有比较详细的说明。除了hanoi_cmp.c其它的文件都可以在windows,linux下通过编译,我使用的是Linux下实现的,所以最好在Linux下重新编译它们。