У консьержа есть несколько ведер (vector<float>
). Мне нужно получить доступ к этим ковшим на основе некоторых индексов. Пример:
int indexX, indexY, indexZ, indexW;
Поэтому, когда приходит новый пункт, мне нужно поставить точку в правильные ведра. Теперь я делаю что-то вроде этого:
// X Y Z W => Bucket
unordered_map<int, unordered_map<int, unordered_map<int, unordered_map<int, vector<float>>>>> indexedTable;
// New point arrives and I put it in the right bucket:
indexedTable[indexX][indexY][indexZ][indexW].push_back(myValue);
Но я нахожу это очень уродливым, и, к сожалению, это тоже очень медленно. Например, для доступа к ней за 1700 пунктов требуется 0,56 с, что слишком медленно.
Есть ли лучшие/более быстрые альтернативы, без использования Boost?
Обратите внимание, что эта структура данных в моих потребностях сопоставима с разреженной матрицей (многомерная), потому что очень мало "ведер" будут заполнены чем-то.
Вместо использования этого 4-глубинного монстра вы можете просто использовать unordered_map
со struct
содержащей 4 индекса в качестве ключа, и vector<float>
в качестве типа значения. Предоставьте функции сравнения и хеш-функции для структуры, и вы находитесь в бизнесе.
struct indices
{
int indexX, indexY, indexZ, indexW;
bool operator==(indices const& other) const
{
return std::tie(indexX, indexY, indexZ, indexW) ==
std::tie(other.indexX, other.indexY, other.indexZ, other.indexW);
}
};
struct indices_hash
{
std::size_t operator()(indices const& i) const
{
std::size_t seed = 0;
boost::hash_combine(seed, i.indexX);
boost::hash_combine(seed, i.indexY);
boost::hash_combine(seed, i.indexZ);
boost::hash_combine(seed, i.indexW);
return seed;
}
};
std::unordered_map<indices, std::vector<float>, indices_hash> m;
Поскольку вы не хотите использовать Boost, либо hash_combine
альтернативу hash_combine
либо скопируйте реализацию здесь.
Пока вам не нужно обращаться ко всем точкам измерения (т.е. Ко всем ведрам, где y == 2), тогда вам следует рассмотреть возможность использования единой структуры для представления вашей точки, а не для вложенных карт.
Что-то в этом роде:
struct Point_t
{
int x;
int y;
int z;
int w;
Point_t (int _x, int _y, int _z, int _w) : x (_x), y (_y), z (_z), w (_w) {}
};
// Make sure the points are sortable
struct CmpPoint_t
{
bool operator() (const Point_t& lhs, const Point_t& rhs)
{
return (lhs.x < rhs.x &&
lhs.y < rhs.y &&
lhs.z < rhs.z &&
lhs.w < rhs.w);
}
};
typedef std::vector<float> Bucket_t;
typedef std::map<Point_t, Bucket_t, CmpPoint_t> BucketMap_t;
Применяя пример использования:
BucketMap_t indexedTable;
indexedTable[Point_t(indexX, indexY, indexZ, indexW)].push_back (myValue);
operator<
для ваших ключей, чтобы их можно было отсортировать. Для unordered_map вы должны предоставить реализацию operator==
а также хеш-функцию. С unordered_map качество хеш-функции влияет на производительность.
indices
который принимает все 4 параметра, и я бы предоставил специализацию дляstd::hash<indices>
чтобы вам не приходилось явно называть хэш вunordered_map
.seed ^= **hash_value(v)** + 0x9e3779b9 + (seed << 6) + (seed >> 2);