First we try, then we trust

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

八、    程序解题过程


在这部分内容中,我们通过一个简化的实际例子来看看在华容道求解过程中,循环链表、AVL树以及树之间是如何相互协作的。首先我们假设所有的棋子只能向下移动(这样可以大大减少树中的节点数量),我们来看系统如何搜索所有可行步骤:

首先,系统初始化各个部件。

 

环形链表中维护了三个指针:current指明当前运算到了哪个布局;last指针指向当前搜索层级的最后一个布局;allocate指针指向下一个可分配的布局,所有这些布局都是可以循环反复使用的。

TreeLinkedList初始化根节点以及Current指针。这个指针用来表示树型结构中子节点的父节点是谁。例如当前初始布局有两个可行的"下一步",那么这两个布局的父节点就是Current指针指向的节点。

AVLTree用初始布局的整数值初始化根节点。系统为华容道求解做好了准备。

第一步:当初始化完成后,系统开始进行搜索运算。首先计算当前步中所有布局(现在只有一个初始布局)的可行走法,并将可行走法追加到allocate分配的空间中。

 

每次移动CircularLinkedList中的current指针时,同步移动TreeLinkedList中的Current指针,确保父节点的正确性。另外,每计算得到一个可行的"下一步"布局,都先将其转换为整数表示,并在AVL树中判断有无重复值。如果没有重复值,便确认 CircularLinkedList中分配的空间,同时向TreeLinkedList中添加节点。

这里需要我们注意的是,TreeLinkedList中添加的节点还包括一个"走法"信息。如Move 6 Down和Move 7 Down。这两个走法分别被附加到了两个青颜色的节点上。但是,这里的走法其实是黄颜色节点的"走法"。黄颜色节点通过该"走法"得到子节点的"布局"。 所以在最终通过堆栈获取所有步骤时,我们要将走法"上移"到父节点,以标识父节点如何走得到子节点。(此处可以参考本文最后关于Stack部分的内容)

第二步:当前步求解完成后,便进入下一步求解(在CircularLinkedList中调用NextStep方法),重新设置好current、last、allocate指针。

 

从上图中我们可以看出,出现了重复布局,该重复布局被AVLTree检测出来,于是allocate分配的空间没能被正确ConfirmAllocation,因此下次需要分配一个布局空间时,仍然会将该布局分配出去。

第三步:该步操作与上一步基本相同,需要注意的是AVLTree在插入布局整数11144021时发生了"旋转"操作,因此确保树拥有最小高度,和最好的检索效率。

 

除此之外,我们还应注意"无解"判断。当某一搜索深度的可行解为0时,我们便说该棋局"无解"。如下图所示:

 

该棋局便是一个"无解"棋局。

最后,假设在我们移动完棋子A后,我们得到了最优解,我们看一看如何通过堆栈结构将解题步骤完整的罗列出来。

 

在对堆栈执行Push时,需要注意的是将移动方法"上移",这样通过Pop操作就可以得到正确的解题步骤了。

到此为止,我们便完成了一个完整的解题循环。
posted on 2005-02-04 11:24  吕震宇  阅读(3922)  评论(3编辑  收藏  举报