First we try, then we trust

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

华容道系列-开篇

华容道与数据结构 (1)

 

六、 数据结构设计

针对上面说到的解题方法,设计如下的数据结构:

1、广度优先的树型结构

由于整个棋局的可行解可以描述成一个树型结构,并且为了得到最少移动步数需要采用广度优先的搜索算法,因此考虑将链表与树型结构整合起来,便于进行广度搜索。如图,当我们试图搜索第三步可行解时,只需要顺着第二步的链表依次搜索便可以实现了。

 


2、堆栈结构输出最少步数

由于在树型结构设计上,每个子节点都保留了一个对父节点的引用。所以一旦找到最优解,我们就需要从最底层向上追溯所有移动步骤(如下图)。但这个顺序与走棋的顺序正好相反。借助一个堆栈结构实现后进先出便把这个次序逆转过来了。

 


3、引用环形链表解决求解下一步走法的问题

在分析1中,我将链表和树整合在了一起,究其原因就是为了便于广度搜索。实际上我们还面临着以下几个问题:

第一,4个字节的棋局表示虽然减小了存储空间,但不利于求解。为了实现步法移动,我们至少要分清棋子的上下左右,4字节的表示方式很难达到这一点。我们需要另外一种带方位的棋局表示方式以便进行求解,而这种表示方式的棋局数量还不能太多,在使用完后要及时释放,否则就会占用大量内存。

第二,为了降低系统模块间的耦合度,尽量让带方位的棋局表示与4字节表示剥离开,两者能够独立变化。

出于上面两点考虑,我决定引入"池"的概念。胡华旦的《"华容道"难题的计算机解》一文中记录了某一步走法的最大可能布局数(树型结构某层级的最多布局数)在200到800之间(10棋子),或1400左右(11棋子),或1800左右(12棋子)。由于我们只研究10棋子布局,所以这个池的大小设置在800比较合适(实际检验的结果是池的大小在1100左右,因为上一步走法与下一步走法存在相关性,并且10子布局中某一步最大可能布局数经检验会大于1000)。通过一个环形链表(加入必要的溢出检验)可以很容易的达到目的。设计如下:

 

环形链表中的每一个节点都是一个带方位关系的布局表述,有了这个环形链表,就可以将在分析1中的链表结构从树型结构中剥离开了。


4、AVL树(平衡树)

每当我们求解得到下一步的一个可行走法后,都要检查该走法完成后的棋盘布局是否在以前搜索过的布局中出现过,如果出现过的化则直接剔除,不再添加到树型结构和环形链表中。这就需要一个检索的过程。

我们知道,在一个未排序的队列中进行检索是一个很耗时的工作,需要遍历每个结点。如果经过排序则可以使用二分法迅速定位。我们可以把所有出现过的布局组织到一个结构中,这个结构应当满足以下两点:一是能够快速的进行查找,二是不允许该结构中出现重复值。在这里,AVL树是再合适不过了。它基于二叉树,并且不允许树中两个节点具有相同取值,同时还可以保证最高的检索效率。在下一篇文章中我将重点介绍AVL树,并说明它在华容道求解过程中的应用。


(待续)

 

posted on 2004-12-14 11:15  吕震宇  阅读(7896)  评论(9编辑  收藏  举报