【问题标题】:STL container that combines sequential ordering with constant access time?将顺序排序与恒定访问时间相结合的 STL 容器?
【发布时间】:2015-05-01 07:59:54
【问题描述】:

这让我印象深刻,因为我应该可以在 Stackoverflow 上找到,但也许我在这里搜索错误的术语。

我有一个类的场景

class Foo
{
  int key;
  int b;
  ...
}

我想将该类的新元素推送到列表中。项目数量事先未知。

同时,我希望能够快速检查(并检索)具有特定键的元素的存在,例如键==5。

所以,总结一下:

  • 存在/检索/删除应该有 O(1)(或大约)时间
  • 应该保持推送项的顺序

对此的一个解决方案让我印象深刻,“使用 std::list 存储项目,并使用 std::unordered_map 检索它们,并进行一些簿记”。我当然可以自己实现它,但想知道这样的东西是否已经以方便的形式存在于 STL 中。

编辑:为了抢占建议,std::map 不是解决方案,因为它基于某个键进行排序。也就是说,它不会保留我推送项目的顺序。

【问题讨论】:

  • 在 STL 或现代 C++ 标准库中没有类似的东西(我认为这就是您所说的 STL),但 Boost 有 multi-index containers
  • O(1) 是棘手的部分,std::map 至少是 O(log)。一旦你有了它,在 std::vector 或链表中存储指向元素的指针将解决第二个约束。
  • std::unordered_map“几乎”是 O(1)。因此,将它与std::list 一起使用的想法是满足 OP 复杂性要求的合理方法。当然,使用 Boost 可能会是一种更稳健的方法。当然,在渐近复杂度在实践中占主导地位之前可能需要一个巨大的 n,因此衡量性能将非常重要。
  • 这个“O”符号可能很棘手。 O(n) 并不意味着它总是比 O(1) 慢,只是对于某个 n 或更大的值,它会变得更慢。对于简单类型(例如具有基本数据类型的类),并且可能少于 1000 个(取决于许多因素,例如类型和 CPU 的大小),您可能会发现使用 std::findstd::vector 明显更快比其他更“聪明”的数据结构承诺“更好”的 O 评级。这是由于更好的缓存性能和更少的动态内存分配。 (例如std::list 动态分配每个节点。非常慢。)
  • 当然,唯一确定的方法就是测量。

标签: c++ stl


【解决方案1】:

STL 没有那种容器,您可以使用 std::unordered_map 和 std::list 编写自己的容器。将您的键映射到 std::unordered_map 中的列表迭代器,并将键值对存储在 std::list 中。

void add(const Key& key, const Value& value) 
{
    auto iterator = list.insert(list.end(), std::pair<Key, Value>(key, value));
    map[key] = iterator;
}

void remove(const Key& key)
{
    auto iterator = map[key];
    map.erase(key);
    list.erase(iterator);
}

或者使用 boost 多索引容器 http://www.boost.org/doc/libs/1_57_0/libs/multi_index/doc/tutorial/index.html

【讨论】:

  • 是的,这就是我认为它会归结为的。我真的很惊讶它在代码中如此简单。我认为列表中的迭代器不会通过删除以外的任何方法失效? (与重新散列使所有迭代器无效的地图不同)
  • 是的,你是对的,只有指向已删除对象的迭代器在 std::list 中变得无效。
  • 顺便说一句,将密钥与列表中的值成对存储的任何特殊原因?似乎也可以只将元素本身存储在列表中,从而减少内存。
  • 如果你想迭代密钥,你应该存储对。
  • 我明白了,是的。在我的特殊情况下,键是元素本身的一部分,因此检索它会给您提供与它一起的键。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-09
  • 2018-03-08
  • 2011-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多