对于非重复项目,最有效的标准容器是什么
What is the most efficient std container for non-duplicated items?
非重复元素添加到 STL 容器中的最有效方法是什么,哪种容器最快?我有大量的数据,恐怕每次我尝试检查它是否是新元素时,都需要花费很多时间。我希望地图非常快。
// 1- Map
map<int, int> Map;
...
if(Map.find(Element)!=Map.end()) Map[Element]=ID;
// 2-Vector
vector<int> Vec;
...
if(find(Vec.begin(), Vec.end(), Element)!=Vec.end()) Vec.push_back(Element);
// 3-Set
// Edit: I made a mistake: set::find is O(LogN) not O(N)
set
和 map
在查找键时都具有O(log(N))
性能。 vector
有O(N)
.
set
和 map
之间的区别 ,就您应该关注的那样,您是需要将键与值相关联,还是直接存储值。如果需要前者,请使用map
,如果需要后者,请使用set
。
在这两种情况下,您都应该只使用insert()
而不是执行find()
。
原因是insert()
当且仅当容器尚未包含该值时(在 map
的情况下,如果容器不包含该键),才会将值插入容器中。这可能看起来像
Map.insert(std::make_pair(Element, ID));
对于地图或
Set.insert(Element);
为一组。
您可以查阅返回值以确定是否实际执行了插入。
如果您使用的是 C++11,则还有两个选择,即 std::unordered_map
和 std::unordered_set
。这两者都摊销了插入和查找的O(1)
性能。但是,它们还要求键(或值,在 set 的情况下)是可哈希的,这意味着您需要专门针对您的密钥进行std::hash<>
。相反,std::map
和 std::set
要求键(或值,在 set 的情况下)响应operator<()
。
如果您使用的是 C++11,则可以使用 std::unordered_set
.这将允许你O(1)
存在检查(技术上摊销O(1)
- O(n)
在最坏的情况下)。
std::set
可能是您O(lg n)
的第二选择。
基本上,std::unordered_set
是一个哈希表,std::set
是一个树结构(在我见过的每个实现中都是一棵红色的黑色树)1。
根据哈希分布的程度和项目数量,std::set 实际上可能更快。如果它确实对性能至关重要,那么与往常一样,您需要进行基准测试。
1)从技术上讲,我认为两者都不需要作为哈希表或平衡BST实现。如果我没记错的话,标准只是规定了运行时限制,而不是实现 - 事实证明,这些是唯一符合边界的可行实现。
你应该使用std::set
;它是一个容器,旨在保存对象的单个(等效)副本,并实现为二叉搜索树。因此,它在容器的大小上是O(log N)
的,而不是O(N)
的。
std::set
和std::map
通常共享其底层实现的很大一部分;您应该查看本地 STL 实现。
话虽如此,复杂性只是衡量性能的一种标准。使用排序向量可能会有更好的性能,因为它使数据彼此保持本地,因此更有可能命中缓存。如今,缓存一致性是数据结构设计的重要组成部分。
听起来你想使用std::set
。它的元素是唯一的,因此在添加元素时无需关心唯一性,并且a.find(k)
(其中a
是std::set
,k
是值)被定义为复杂度对数。
如果你的元素可以为O(1)进行哈希处理,那么最好在unordered_map
或unordered_set
中使用索引(而不是在map
/set
中,因为它们在实现中使用RB树,这是O(logN)发现复杂性)
您的示例显示了明确的模式:
check if the value is already in container
if not, add the value to the container.
这两个操作都可能需要一些时间。首先,如果元素没有以任何特定方式排列(例如,只是一个普通std::vector
),则可以在O(N)时间内(线性搜索)完成查找元素,如果元素被排序(例如,std::map
或std::set
),则可以在O(logN)时间内完成(二叉搜索),如果元素被散列(例如, std::unordered_map
或std::unordered_set
)。
对于普通向量或无序容器(哈希容器),插入将是 O(1)(摊销),尽管哈希容器会慢一点。对于排序的容器(如 set 或 map),您将具有日志时插入,因为它需要在插入之前查找插入它的位置。
所以,结论,使用std::unordered_set
或std::unordered_map
(如果你需要键值功能)。而且在插入之前您无需检查,这些是唯一密钥容器,它们不允许重复。
如果您(或任何同等产品)无法使用std::unordered_set
/std::unordered_map
(从 C++11 开始)或 std::tr1::unordered_set
/std::tr1::unordered_map
(自 2007 年起),那么下一个最佳选择是 std::set
/std::map
.
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 标准 N3337 5.2.10 第 7 条中的C++"类型"是什么意思?
- 如何声明一个标准::提升直方图的向量?提升直方图的类型是什么?
- 根据 c++ 标准在该宏定义中推送/弹出宏时的行为是什么
- 标准库容器最简单、性能差的哈希类是什么?
- C++ 捕获异常后进行清理的标准方法是什么?
- 读取二进制文件的惯用C++17标准方法是什么
- 在 NTL 中构造多项式的标准方法是什么?
- C++标准兼容库容器的完整接口是什么?
- 此代码中的数组初始化样式是什么?这是标准的吗?
- Eclipse CDT 项目中的缺省C++标准是什么?
- "AfxIsValidAddress"函数的等效标准函数是什么?
- 在C++中编写符合 IEEE-754 标准的双/浮子除法的最快方法是什么?
- embarcadero/borland TMemoryStream和TFileStream的标准C++等价物是什么?
- 使用C 17处理Unicode的有效,符合标准的机制是什么
- C 11中的标准方法是什么,可以访问std :: vector中元素n的指针
- 模板函数作为模板参数,标准是什么
- 选择排序算法的标准是什么
- 编译器用来决定移动操作是否安全的标准是什么
- 参数传递中常量位置的 c++ 标准是什么?