引言
前几天看了LIVE写的两篇关于骑士巡游算法的文章(我的马的遍历代码[Teaks & xgluxv] 以及马的遍历进阶版--骑士巡游(添加了评估函数)[Teaks & xgluxv & r]),感觉其中C#版本的算法实现还有可以改进的地方,所以乘周末有空的时候,做了几个版本来验证一下C#在需要速度的时候是否真的差很多。
版本一
HamiltonCS:点击下载源文件
算法上在保证遍历路线不变的情况下,做了小小的优化。更主要的改进是使用了指针访问,代替了原有的数组。减少了装箱以及拆箱的操作。
版本二
KnightTour:点击下载源文件
在版本一的基础上又做了改进。棋盘遍历标志的访问直接使用指针。同时修改版本一中骑士存储的方式,改存偏移量索引为访问地址。
版本三
KnightTourPlus:点击下载源文件
在算法上做了优化,所以说在执行时间上,与原有的版本没有什么可比性。
算法优化思路如下:
作为骑士巡游路线,只要搜索到一条,那么把该路线第2点与第64点以及之间的点的次序颠倒,则必然存在另外一条巡游路线。所以在计数时,可以每次累加2。为了去除重复计数的部分,首先先获取第2点可能点的序列(即所有的NextKnight)。在判断是否是巡游路线时,只要判断结束点是否是当前遍历路线第2点以后的点即可。此算法和LIVE使用的优化一样,只是做到了局部优化,对于获取前N条路线时可以大大提高效率。
测试结果
注:测试使用的版本均为Release版本。
总结
从测试结果不难看出,相同的算法,在使用C#的情况下,也可以得到比较理想的速度。但我不得不承认,为此我也大大增加了编码的时间,同时牺牲了大部分C#的特性作为代价。
我写这篇文章其实也只是为了证明C#并不是那么弱,当你需要执行效率的时候,它也可以做到这点。掌握好编码效率和执行效率的平衡点才是王道。
套用一下《霍元甲》主题曲中的一段作为结束语:“我以为,世上的武术确实没有高低之分,只有习武的人才有强弱之别,通过竞技我们可以认识一个真正的自己,因为我们真正的对手,可能就是我们自己。”
前几天看了LIVE写的两篇关于骑士巡游算法的文章(我的马的遍历代码[Teaks & xgluxv] 以及马的遍历进阶版--骑士巡游(添加了评估函数)[Teaks & xgluxv & r]),感觉其中C#版本的算法实现还有可以改进的地方,所以乘周末有空的时候,做了几个版本来验证一下C#在需要速度的时候是否真的差很多。
版本一
HamiltonCS:点击下载源文件
算法上在保证遍历路线不变的情况下,做了小小的优化。更主要的改进是使用了指针访问,代替了原有的数组。减少了装箱以及拆箱的操作。
版本二
KnightTour:点击下载源文件
在版本一的基础上又做了改进。棋盘遍历标志的访问直接使用指针。同时修改版本一中骑士存储的方式,改存偏移量索引为访问地址。
版本三
KnightTourPlus:点击下载源文件
在算法上做了优化,所以说在执行时间上,与原有的版本没有什么可比性。
算法优化思路如下:
作为骑士巡游路线,只要搜索到一条,那么把该路线第2点与第64点以及之间的点的次序颠倒,则必然存在另外一条巡游路线。所以在计数时,可以每次累加2。为了去除重复计数的部分,首先先获取第2点可能点的序列(即所有的NextKnight)。在判断是否是巡游路线时,只要判断结束点是否是当前遍历路线第2点以后的点即可。此算法和LIVE使用的优化一样,只是做到了局部优化,对于获取前N条路线时可以大大提高效率。
测试结果
|
|
|
|
|
CppHamilton(C#) |
100000 |
1530348 |
146391 |
1 |
Hamilton(C#) |
100000 |
1530348 |
418031 |
2.85 |
HamiltonCS(C#) |
100000 |
1530348 |
157453 |
1.08 |
KnightTour(C#) |
100000 |
1530348 |
95437 |
0.65 |
KnightTourPlus(C#) |
100000 |
737861 |
33796 |
0.23 |
注:测试使用的版本均为Release版本。
总结
从测试结果不难看出,相同的算法,在使用C#的情况下,也可以得到比较理想的速度。但我不得不承认,为此我也大大增加了编码的时间,同时牺牲了大部分C#的特性作为代价。
我写这篇文章其实也只是为了证明C#并不是那么弱,当你需要执行效率的时候,它也可以做到这点。掌握好编码效率和执行效率的平衡点才是王道。
套用一下《霍元甲》主题曲中的一段作为结束语:“我以为,世上的武术确实没有高低之分,只有习武的人才有强弱之别,通过竞技我们可以认识一个真正的自己,因为我们真正的对手,可能就是我们自己。”