你还记得我之前的问题:是什么导致了std::async
这里的数据竞争?
即使我成功地并行化了这个程序,它仍然运行得太慢而不实用。
所以我试图改进代表康威生命游戏模式的数据结构。
新结构的简要说明:
class pattern {
// NDos::Lifecell represents a cell by x and y coordinates.
// NDos::Lifecell is equality comparable, and has std::hash specialization.
private:
std::unordered_map<NDos::Lifecell, std::pair<int, bool>> cells_coor;
std::unordered_set<decltype(cells_coor)::const_iterator> cells_neigh[9];
std::unordered_set<decltype(cells_coor)::const_iterator> cells_onoff[2];
public:
void insert(int x, int y) {
// if coordinate (x,y) isn't already ON,
// turns it ON and increases the neighbor's neighbor count by 1.
}
void erase(int x, int y) {
// if coordinate (x,y) isn't already OFF,
// turns it OFF and decreases the neighbor's neighbor count by 1.
}
pattern generate(NDos::Liferule rule) {
// this advances the generation by 1, according to the rule.
// (For example here, B3/S23)
pattern result;
// inserts every ON cell with 3 neighbors to result.
// inserts every OFF cell with 2 or 3 neighbors to result.
return result;
}
// etc...
};
简而言之,pattern
包含单元格。它包含每个 ON 单元,以及每个具有 1 个或多个 ON 相邻单元的 OFF 单元。它还可以包含备用的 OFF 单元。
cells_coor
通过使用它们的坐标作为键直接存储单元格,并将它们映射到它们的 ON 相邻单元格的数量(存储为int
)以及它们是否为 ON(存储为bool
)。
cells_neigh
并cells_onoff
通过迭代器将单元格间接存储为键。
一个单元的 ON 邻居数总是 0 或更大且 8 或更少,cells_neigh
大小为 9 的数组也是如此。
cells_neigh[0]
存储相邻单元格为 0 的单元格,cells_neigh[1]
存储相邻单元格为 1 的单元格,依此类推。
同样,一个单元格总是关闭或打开,cells_onoff
大小为 2 的数组也是如此。
cells_onoff[false]
存储OFF单元,并cells_onoff[true]
存储ON单元。
单元格必须插入或删除所有cells_coor
,cells_neigh
和cells_onoff
。换句话说,如果一个单元格被插入其中一个或从其中一个中删除,那么其他的也必须如此。正因为如此,元素cells_neigh
和cells_onoff
是std::unordered_set
将迭代器存储到实际单元中,从而通过邻居计数或关闭/开启状态快速访问单元。
如果这种结构有效,则插入函数的平均时间复杂度为O(1)
,擦除也O(1)
为 ,生成O(cells_coor.size())
时间为 ,与之前的结构相比,时间复杂度有很大的提高。
但是如您所见,有一个问题:我如何散列 a std::unordered_map::const_iterator
?
std::hash
禁止对他们进行专业化,所以我必须定制一个。
获取他们的地址是行不通的,因为它们通常是作为右值或临时值获得的。
取消引用它们也不起作用,因为有多个单元格的相邻单元格为 0,或者多个单元格关闭,等等。
那我该怎么办?如果我不能做任何事情,cells_neigh
并且cells_onoff
将会std::vector
或某事,会急剧降低时间复杂度。