我正在编写Conway的生命游戏的实现,并决定使用Hashlife algorithm的变体,使用四叉树和散列表来存储单元格并处理碰撞,有点类似于描述here和here。细节基本上是整个空间由四叉树组成,它们以生命或死亡状态下降到叶子。四边形本身是不可变的,并且在整个树中共享引用以处理非常稀疏的区域或常见的重复模式。
我遇到的一个问题是甚至生成一个字段来保存彼此相距很远的单元格。似乎即使递归地定义高度为24的空四叉树也需要非常长的时间。
解决这个问题的最佳方法是什么?
我看到的两个解决方案可能是将空的四边形保留为未初始化直到需要它们,但是四边形的不变性可能会使这有点棘手 - 如果我保持每个四元组不可变我不能只是实例化一个子节点,我将不得不更新整个结构从头开始。
我想到的另一个解决方案是拥有多个quadTree - 所以如果我有一个远离其他单元的几万亿个单元的点,它们将由不同的树控制。显然这里的问题是处理相邻或重叠的树的合并 - 看起来沿着这条路走下去需要四棵树的四叉树,我怀疑这对我来说不会很好。
我缺少哪些其他解决方案?有没有什么我忽略的上述两种解决方案会让它们变得不那么毛茸茸呢?
谢谢!
答案 0 :(得分:1)
我已经处理了这个并且开创性的实施Golly通过使用NULL
(或一些合适的替代值)代表“空”来处理这个问题。在树的任何层面。这是有效的,因为我们知道空的进展为空。
因此,如果您想象一个8x8跨度在西北象限中持有滑翔机,那么您的结构是
NorthWest =滑翔机(保存在4x4子树中) 东北地区=西南=东南亚= nullptr
使用这种方法,只要它们稀疏,你就可以制作大量的模式。
在程序的某个地方,您将访问哈希表,您可能需要添加表单的代码:
Node* getNode(Node* NW,Node* NE,Node* SW,Node* SE) {
if(NW==nullptr&&NW==nullptr&&NW==nullptr&&NW==nullptr){
return nullptr;
}
//Actually go into the hash-table....
}
一个推进功能:
Node* AdvanceQuarterSpan(Node* node, unsigned span_index){
if(node==nullptr){
return nullptr;
}
//Actually divide the node up advance the sub-quadrants and advance the resulting centre quadrant.
}
我松散地假设你有一些结构如下:
class Node {
Node* NW; //North West Quadrant. nullptr if empty.
Node* NE; //North East Quadrant. nullptr if empty.
Node* SW; //South West Quadrant. nullptr if empty.
Node* SE; //South East Quadrant. nullptr if empty.
//Other fields...
};
我看到了拥有单独树木的想法,但处理树木中有大量空洞的树木非常有效,这种方式完全毫无意义。