如何使用 std::unordered_map 和 'external' 键
How to use std::unordered_map with 'external' keys
我的目标是编写一个像 unordered_map 一样工作的 class,但保持元素的插入顺序,同时仍然允许 O(1) 键查找。
我的做法如下:
// like unordered_map but keeps the order of the elements for iteration
// implemented as a vector with a unordered_map for constant time lookups
// consider if element removal is needed, since it is O(N) because of the use of a vector of elements
template <typename KEY, typename VAL>
struct ordered_map {
struct KeyValue {
KEY key;
VAL value;
};
std::vector<KeyValue> elements; // KeyValue pairs in order of insertion to allow iteration
std::unordered_map<KEY, int> indexmap; // key -> index map to allow O(1) lookup, is there a way to avoid the redundant key?
//...
}
但我遇到的问题是,在我的方法中,我想使用存储在索引图中的键 'externally' 来查找索引图(在基于地图中索引值的元素向量中)。
std::sort
例如允许传入一个比较器,
但是 unordered_sap 似乎没有任何相似之处。
我真的无法在网上找到有关如何完成此操作的任何信息,但我可能使用了错误的术语进行搜索。
我这个方法stl支持吗?
或者我需要求助于存储密钥两次,
我想避免这种情况,因为键可以是堆对象,例如 std::strings。
编辑:unordered_map 而不是 unordered_set 这不起作用
My goal is to write a class that works like a unordered_map but keeps the insertion order of the elements while still allowing O(1) lookup by key
...和没有复制密钥,以防它很大and/or昂贵。
所以,你想要两件事:
- 与
std::unordered_map
具有相同语义的恒定时间关联查找(没有重复键,或者您would/should已经要求std::unordered_multimap
)
- 顺序索引跟踪插入顺序
您已选择使用顺序容器实现关联查找,并使用关联容器实现顺序索引。我不知道为什么,但让我们尝试更自然的选择:
- 关联查找应该只是
std::unordered_map<Key, SomeValueType>
- 顺序索引可以是
std::vector<SomeValueType*>
剩下的空白是SomeValueType
:它可能只是VAL
,但是我们需要做额外的工作来修复顺序索引擦除一些东西。我们可以改为 std::pair<VAL, size_t>
,这样它就可以存储我们需要在擦除时删除的迭代器的索引 i
。不利的一面是,除了将所有 i+1..N
个向量元素向下移动一个,我们 还 需要更新每个地图元素的索引值。
如果要保留恒定时间擦除,您可能需要顺序索引为 std::list<SomeValueType*>
,并在地图元素中保留 std::list::iterator
。链表上的实际线性迭代比向量慢,但在擦除元素时会得到相同的复杂性。
注意。顺序索引确实需要存储指针而不是迭代器——我最初忘记了无序映射的失效行为。但是,如果您想访问密钥,它们显然可以是 std::unordered_map<key, SomeValueType>::value_type
指针……我只是写出了更短的替代方案。
我的目标是编写一个像 unordered_map 一样工作的 class,但保持元素的插入顺序,同时仍然允许 O(1) 键查找。
我的做法如下:
// like unordered_map but keeps the order of the elements for iteration
// implemented as a vector with a unordered_map for constant time lookups
// consider if element removal is needed, since it is O(N) because of the use of a vector of elements
template <typename KEY, typename VAL>
struct ordered_map {
struct KeyValue {
KEY key;
VAL value;
};
std::vector<KeyValue> elements; // KeyValue pairs in order of insertion to allow iteration
std::unordered_map<KEY, int> indexmap; // key -> index map to allow O(1) lookup, is there a way to avoid the redundant key?
//...
}
但我遇到的问题是,在我的方法中,我想使用存储在索引图中的键 'externally' 来查找索引图(在基于地图中索引值的元素向量中)。
std::sort
例如允许传入一个比较器,
但是 unordered_sap 似乎没有任何相似之处。
我真的无法在网上找到有关如何完成此操作的任何信息,但我可能使用了错误的术语进行搜索。
我这个方法stl支持吗?
或者我需要求助于存储密钥两次, 我想避免这种情况,因为键可以是堆对象,例如 std::strings。
编辑:unordered_map 而不是 unordered_set 这不起作用
My goal is to write a class that works like a unordered_map but keeps the insertion order of the elements while still allowing O(1) lookup by key
...和没有复制密钥,以防它很大and/or昂贵。
所以,你想要两件事:
- 与
std::unordered_map
具有相同语义的恒定时间关联查找(没有重复键,或者您would/should已经要求std::unordered_multimap
) - 顺序索引跟踪插入顺序
您已选择使用顺序容器实现关联查找,并使用关联容器实现顺序索引。我不知道为什么,但让我们尝试更自然的选择:
- 关联查找应该只是
std::unordered_map<Key, SomeValueType>
- 顺序索引可以是
std::vector<SomeValueType*>
剩下的空白是SomeValueType
:它可能只是VAL
,但是我们需要做额外的工作来修复顺序索引擦除一些东西。我们可以改为 std::pair<VAL, size_t>
,这样它就可以存储我们需要在擦除时删除的迭代器的索引 i
。不利的一面是,除了将所有 i+1..N
个向量元素向下移动一个,我们 还 需要更新每个地图元素的索引值。
如果要保留恒定时间擦除,您可能需要顺序索引为 std::list<SomeValueType*>
,并在地图元素中保留 std::list::iterator
。链表上的实际线性迭代比向量慢,但在擦除元素时会得到相同的复杂性。
注意。顺序索引确实需要存储指针而不是迭代器——我最初忘记了无序映射的失效行为。但是,如果您想访问密钥,它们显然可以是 std::unordered_map<key, SomeValueType>::value_type
指针……我只是写出了更短的替代方案。