如何散列std :: unordered_map :: const_iterator?

时间:2017-03-04 12:55:37

标签: c++ c++11 hash unordered-map const-iterator

你还记得我先前的问题:What is causing data race in std::async here?
即使我成功并行化了这个程序,仍然运行得太慢而不实用 所以我试图改进代表康威生命游戏模式的数据结构 新结构的简要说明:

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_neighcells_onoff通过迭代器将单元格间接存储为键。
单元的ON邻居数始终为0或更大且为​​8或更小,因此cells_neigh为9号数组。 cells_neigh[0]存储具有0个ON相邻单元的单元,cells_neigh[1]存储具有1个ON相邻单元的单元,依此类推。
同样,单元格始终为OFF或ON,因此cells_onoff是2号数组 cells_onoff[false]存储OFF单元格,cells_onoff[true]存储ON单元格 必须将单元格插入或删除所有cells_coorcells_neighcells_onoff。换句话说,如果将一个单元插入或从其中一个单元中删除,则对其他单元也必须如此。因此,cells_neighcells_onoff的元素是std::unordered_set,将迭代器存储到实际单元格中,从而可以通过邻居计数或OFF / ON状态快速访问单元格。

如果此结构有效,则插入函数的平均时间复杂度为O(1),擦除也为O(1),而生成O(cells_coor.size())则具有很大的时间复杂度。先前的结构。

但正如您所见,存在一个问题:如何散列std::unordered_map::const_iterator
std::hash禁止对他们进行专业化,所以我必须制作一个自定义的 取他们的地址是行不通的,因为他们通常被收购为rvalues或temporaries 取消引用它们也不起作用,因为有多个单元格具有0个ON相邻单元格,或多个单元格处于OFF状态等。
那我该怎么办?如果我无法执行任何操作,cells_neighcells_onoff将为std::vector或其他内容,会严重降低时间复杂度。

1 个答案:

答案 0 :(得分:2)

短篇小说:这不会奏效(非常好)(* 1)。您可能要在地图cells_coor上执行的大多数操作都会使任何迭代器(but not pointers, as I learned)无效。

如果你想保留我所说的不同的观点&#34;在某些集合中,存储实际数据的基础容器需要不被修改或者不能使其迭代器无效(例如链接列表)。

也许我错过了什么,但为什么不为邻居计数保留9组小区,为开/关保留2组小区? (* 2)换句话说:你真的需要那张地图吗?的(* 3)

(* 1):映射仅在发生重新散列时使指针和迭代器无效。你可以检查一下:

// Before inserting
(map.max_load_factor() * map.bucket_count()) > (map.size() + 1)

(* 2):9组可以减少到8:如果单元格(x,y)不在8组中,那么它将在第9组中。因此,不需要存储该信息。打开/关闭相同:它足以存储打开的单元格。所有其他人都关闭了。

(* 3):在不使用地图的情况下访问邻居的数量,但仅使用单元格集,伪代码的种类:

unsigned number_of_neighbours(Cell const & cell) {
  for (unsigned neighbours = 9; neighbours > 0; --neighbours) {
    if (set_of_cells_with_neighbours(neighbours).count() == 1) {
      return neighbours;
    }
  }
  return 0;
}

集合中的重复查找当然会破坏实际性能,您需要对其进行分析。 (渐近运行时不受影响)