Помните мой предыдущий вопрос: Что вызывает гонку данных в 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
содержит ячейки. Он содержит все включенные ячейки и все выключенные ячейки, которые имеют 1 или более включенных соседних ячеек. Он также может содержать запасные ВЫКЛЮЧЕННЫЕ ячейки.cells_coor
напрямую сохраняет ячейки, используя их координаты в качестве ключей, и сопоставляет их с количеством включенных соседних ячеек (хранится как int
) и включено ли они (хранится как bool
).
cells_neigh
и cells_onoff
косвенно сохраняют ячейки с помощью итераторов к ним как к ключам.
Число включенных соседей ячейки всегда равно 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_coor
, cells_neigh
и cells_onoff
. Другими словами, если ячейка вставляется или стирается из одного из них, то это должно быть так же и для других. Из-за этого элементы cells_neigh
и cells_onoff
std::unordered_set
сохраняют итераторы к фактическим ячейкам, обеспечивая быстрый доступ к ячейкам по счетчику соседей или по состоянию OFF/ON.
Если эта структура работает, функция вставки будет иметь среднюю временную сложность O(1)
, стирание также O(1)
и генерацию O(cells_coor.size())
, что значительно улучшает временную сложность по сравнению с предыдущей структурой.
Но, как видите, есть проблема: Как я могу хешировать std::unordered_map::const_iterator
?std::hash
запрещает им специализацию, поэтому мне нужно сделать собственную.
Выиграл взятие их адреса. не работают, так как они обычно получаются как rvalue или временные значения.
Разыменование их также не сработает, так как есть несколько ячеек, для которых 0 имеет соседние ячейки, или несколько ячеек, которые выключены, и т. д.
Итак. что я могу сделать? Если я ничего не могу сделать, cells_neigh
и cells_onoff
будут std::vector
или что-то в этом роде, что резко ухудшит временную сложность.
std::hash
запрещает им специализацию? Думаю, я понимаю, почему вы этого хотите, но IMO это еще одно доказательство того, что хранение итераторов - не всегда лучшая идея. Но у меня нет для тебя альтернативы. Кстати, на вашей карте отсутствует тип значения; ты хотел сказатьunordered_set
? - person Lightness Races in Orbit   schedule 04.03.2017std::hash
делает это, но да, я хочу хранить итераторы, потому что в них должна быть связь. Если ячейка вставлена в одну, она должна быть вставлена и в остальные и т.д. - person Dannyu NDos   schedule 04.03.2017std::unordered_set
. Исправлено. - person Dannyu NDos   schedule 04.03.2017std::set
, если это всего несколько элементов - вы [вероятно] не заметите разницы. - person Lightness Races in Orbit   schedule 04.03.2017std::unordered_set
? Но это будет стоить раз. Да, элементов будет немного, но я ищу миллиарды паттернов «Игры жизни» Конвея. Небольшое улучшение временной сложности — это просто здорово. - person Dannyu NDos   schedule 04.03.2017std::unordered_map::value_type*
, полученный с помощью&*iter
. Или, по крайней мере, вы можете реализовать хэш итератора, хэшируя указатель&*iter
. - person Igor Tandetnik   schedule 04.03.2017