我需要一个索引关联容器,其操作如下:
最初为空,尺寸= 0。
当我向它添加一个新元素时,它将它放在index [size],非常类似于vector的push_back。它递增大小并返回新添加元素的索引。
如果元素已经存在,则返回它出现的索引。
Set似乎是理想的数据结构,但我没有看到任何像get的东西 来自查找操作的索引。在集合上查找返回元素的迭代器。
在这种情况下,采取与set.begin()的区别是正确的吗?
答案 0 :(得分:3)
STL中没有立即适当的数据结构,但实现这一点的一种简单而有效的方法是使用映射和指针向量。 map
将对象映射到数组中的索引(这样检查对象是否存在是有效的,如果对象确实存在,则索引就在眼前),vector
映射索引到地图中的对象(以便通过索引检索对象是有效的)。
std::map<T,size_t> objects;
std::vector<const T *> indexed;
添加元素:
size_t add_element(const T &v) {
std::map<T,size_t>::iterator it=objects.find(v);
if(it==objects.end()) {
it=objects.insert(std::map<T,size_t>::value_type(v,objects.size())).first;
indexed.push_back(&it->first);
}
return it->second;
}
(根据个人风格的明显改变可能是存储地图迭代器的向量,每次使用map :: insert并检查结果的bool部分以查看indexed
是否需要更新等。)< / p>
获得元素:
const T &get_element(size_t index) {
return *indexed[index];
}
就是这样。一个问题当然是一旦对象在集合中,就无法修改它。这是从它在这里实现的方式的一种泄漏,因为地图键是常量,显而易见的原因 - 但实际上它是我想的,无论如何,无论实现如何。如果你坚持不重复,那么一旦一个对象在列表中,它就不能被修改,以防任何修改使它成为另一个对象的副本。
(另请注意,我在这里使用size_t
作了一些欺骗 - 我认为std::vector<const T *>::size_type
可能更准确 - 这主要是为了简洁!)