是否存在连续存储的散列映射数据结构
Is there a contiguously stored hash map data structure?
考虑不同类型的集合,如Position
, Color
, Name
。这些实例可以通过在集合中使用相同的键来连接。密钥是64位长度的全局唯一标识符。目前,我使用哈希映射,但这不是理想的。
// custom types
struct Position { float x, y, z; bool static; };
enum Color { RED, BLUE, GREEN };
// collections
std::unordered_map<uint64_t, Position> positions;
std::unordered_map<uint64_t, Color> colors;
std::unordered_map<uint64_t, std::string> names;
// add some data
// ...
// only access positions collection,
// so the key is not needed here
for (auto i = positions.begin(); i != positions.end(); ++i) {
if (i->second.static) continue;
i->second.x = (rand() % 1000) / 1000.f;
i->second.y = (rand() % 1000) / 1000.f;
i->second.z = (rand() % 1000) / 1000.f;
}
// access to all three collections,
// so we need the key here
for (auto i = positions.begin(); i != positions.end(); ++i) {
uint64_t id = *i->first;
auto position = i->second;
auto color = colors.find(id);
auto name = names.find(id);
if (color == colors.end() || name == names.end()) continue;
draw(*name, *position, *color);
}
我尝试分离集合,但是正如您所看到的,同时也需要多个集合的收集实例。当然,我还需要不时地添加或删除单个元素,但这些情况对性能并不重要。
现在我想优化单个集合的迭代。因此,我尝试让集合连续存储,这是面向数据设计思想的一部分。但是,我仍然需要非常快速地访问各个实例。直接使用数组不工作,因为这会分配太多的内存,并不是一种类型的所有实例都有另一种类型的对应物。另一方面,哈希映射不是迭代的最佳选择。
我认为数据结构必须在内部使用数组。我应该在这里使用哪种数据类型?在c++标准库中实现了这样的数据结构吗?
创建unordered_map
以偏移到std::vector
。
将元素存储在std::vector
中。当您想要删除一个元素时,将它与std::vector
的最后一个元素交换,然后删除最后一个元素。检查unordered_map
s,将索引存储到std::vector
中,并修复那些指向最后一个元素的索引,使其指向最后一个元素的位置。
删除一个元素现在是O(n)。如果你一次删除一堆元素,你可以用一点创造力在一次O(n)次中完成所有元素。
添加一个元素仍然是0(1)。
遍历所有元素包括遍历std::vector
。如果在迭代时需要哈希值,可以将其冗余存储在那里,或者动态计算。
将std::vector
和std::unordered_map
封装在强制上述规则的类型后面,否则不变量将永远不会持续存在,这将在外部暴露类似map
的接口。
作为O(n)移除的替代方案,创建一个并行的std::vector
来存储std::unordered_map<
??>::iterator
年代。仔细跟踪std::unordered_map
中发生重新散列的时间(重新散列是确定的,但您必须自己计算它何时发生),以及何时重新构建它(因为所有iterator
都会因重新散列而失效)。重复哈希很少发生,所以它有一个平摊常数代价1。当您想要擦除时,现在可以在0(1)时间内更新unordered_map
中的索引(记住也要更新第二个std::vector
——将位置从最后一个交换到被删除的元素)。您可以将它存储在与原始数据相同的std::vector
中,但这会使它变得很大(这会减慢迭代速度)。
1当容器达到max_load_factor()*bucket_count()
大小时发生重列。然后bucket_count
呈指数增长,元素四处移动。就像std::vector
的增长算法一样,这保证了移动的元素总数是线性的——所以它保持了平摊常数插入。手动重建反向表并不比移动所有现有元素更昂贵,因此它还有助于平摊常数插入时间因子。
- 如何在 C# 中映射双 C 结构指针?
- 链表,反向函数,数据结构
- 无法添加多个键以映射将结构作为键
- 如何使用set实现无序数据结构?
- 我们可以将数据永久保存为数据结构吗?
- C++中的可变长度数组/数据结构
- 用于存储由空格分隔的字符串的 C++/C 数据结构
- 用于对项目进行分组并将单个项目映射到其他组成员的数据结构
- 通常用于将输入映射到显示器的数据结构是什么
- 排序值C++映射具有多个键值的数据结构
- 如何在结构数据结构中使用 map stl 并初始化映射,然后引用它
- 如何用树数据结构有效地实现无序映射
- 更好的数据结构映射函数与多个参数(键)
- 将值映射到像素对-如何实现数据结构
- STL:访问已作为第二对添加到映射的结构中的数据
- 具有堆和映射同等能力的数据结构
- 数据结构-C++映射:需要智能算法
- C++-具有结构共享/不变性的类映射数据结构
- 如何使用 'auto' 关键字遍历 C++ STL 映射数据结构?
- 是否存在连续存储的散列映射数据结构