对于非重复项目,最有效的std容器是什么?

时间:2013-01-22 23:12:27

标签: c++ map vector set containers

将非重复元素添加到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)

6 个答案:

答案 0 :(得分:14)

setmap都具有O(log(N))性能,可用于查找密钥。 vectorO(N)

就您应该关注的问题而言,setmap之间的区别在于您是否需要将键与值相关联,或者只是直接存储值。如果您需要前者,请使用map,如果您需要后者,请使用set

在这两种情况下,您都应该使用insert()而不是find()

原因是insert()将值插入容器中,当且仅当容器尚未包含该值时(在map的情况下,如果容器不包含该键) 。这可能看起来像

Map.insert(std::make_pair(Element, ID));

表示地图或

Set.insert(Element);

一套。

您可以查阅返回值以确定是否实际执行了插入。


如果您使用的是C ++ 11,则还有两个选项,std::unordered_mapstd::unordered_set。对于插入和查找,这两者都具有摊销O(1)性能。但是,它们还要求密钥(或者在设置的情况下的值)是可清除的,这意味着您需要为密钥专门化std::hash<>。相反,std::mapstd::set要求您的密钥(或值,如果设置)回复operator<()

答案 1 :(得分:6)

如果您使用的是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。如果我没记错的话,标准只是强制执行运行时限,而不是实现 - 它只是证明那些是唯一适合边界的可行实现。

答案 2 :(得分:3)

你应该使用std::set;它是一个容器,用于保存对象的单个(等效)副本,并实现为二叉搜索树。因此,容器的大小为O(log N),而不是O(N)

std::setstd::map经常共享其底层实施的很大一部分;你应该查看你当地的STL实施。

说了这么多,复杂性只是性能的一个衡量标准。使用排序向量可能会有更好的性能,因为它会使数据彼此保持本地,因此更有可能触及缓存。如今,缓存一致性是数据结构设计的重要组成部分。

答案 3 :(得分:1)

听起来你想使用std::set。它的元素是唯一的,因此您在添加元素时无需关心唯一性,a.find(k)(其中astd::setk是值)是被定义为复杂性的对数。

答案 4 :(得分:1)

如果您的元素可以针对O(1)进行哈希处理,那么最好使用unordered_mapunordered_set(而不是map / set中的索引,因为他们在实现中使用RB树,这是O(logN)查找复杂度)

答案 5 :(得分:1)

您的示例显示了明确的模式:

check if the value is already in container
  if not, add the value to the container.

这两项操作都可能需要一些时间。首先,如果元素没有以任何特定方式排列(例如,只是普通的std::vector),则可以在O(N)时间(线性搜索)中查找元素,它可以在O(logN)中完成)时间(二进制搜索)如果元素被排序(例如,std::mapstd::set),并且如果元素被散列,则可以在O(1)时间内完成(例如,{{ 1}}或std::unordered_map)。

对于普通向量或无序容器(哈希容器),插入将是O(1)(摊销),尽管哈希容器会慢一点。对于像set或map这样的已排序容器,您将进行日志时间插入,因为它需要在插入之前查找插入它的位置。

因此,结论是,使用std::unordered_setstd::unordered_set(如果您需要键值功能)。并且您在插入之前不需要检查,这些是唯一密钥容器,它们不允许重复。

如果{(1}} / std::unordered_map(来自C ++ 11)或std::unordered_set / std::unordered_map(自2007年起)无法(或任何等效版本),则下一个最佳选择是std::tr1::unordered_set / std::tr1::unordered_map