C ++ std :: map或std :: set - 高效插入重复项

时间:2012-10-10 18:54:31

标签: c++ performance stdmap stdset

我有一堆完整的重复数据,我想消除重复。你知道,例如[1,1,3,5,5,5,7]变为[1,3,5,7]。

看起来我可以使用std :: map或std :: set来处理这个问题。但是我不确定(a)是否只是将所有值插入容器中,或者(b)检查它们是否已经存在于容器中并且仅在它们不存在时插入 - 是否插入非常有效?即使有更好的方法......你能建议一个快速的方法吗?

另一个问题 - 如果我存储在其中的数据不像整数那么简单,而是一个自定义类,std :: map如何管理以正确存储(哈希?)数据以便快速访问通过运营商[]?

5 个答案:

答案 0 :(得分:10)

std::map不使用散列。 std::unordered_map确实如此,但那是C ++ 11。 std::mapstd::set都使用您提供的比较器。类模板具有此比较器的默认值,可归结为operator<比较,但您可以提供自己的比较器。

如果您不需要存储密钥和值(看起来不是这样),您应该使用std::set,因为这更合适。

标准没有说明mapset在引擎盖下使用的数据结构,只有certian行为具有一定的时间复杂性。实际上,我所知道的大多数实现都使用树。

如果您使用operator[]insert,则时间复杂度没有区别,但我会在insert之前使用operator[]search insert如果找不到该项,则后跟{{1}}。后者意味着两个单独的搜索将项目插入到集合中。

答案 1 :(得分:7)

任何关联容器上的insert()执行find()以查看对象是否存在,然后插入对象。只需将元素插入std::set<T>即可合理有效地删除重复项。

根据您的设置的大小以及重复项与唯一值的比率,将对象放入std::vector<T>std::sort()然后再使用std::unique()可能会更快用std::vector<T>::erase()来摆脱重复。

答案 2 :(得分:2)

你应该做多少次?

如果通常是插入:

//*/
std::set<int> store;
/*/
// for hash:
std::unordered_set<int> store;
//*/
int number;

if ( store.insert(number).second )
{
  // was not in store
}

如果你填一次:

std::vector<int> store;
int number;

store.push_back(number);
std::sort(store.begin(),store.end());
store.erase(std::unique(store.begin(),store.end()),store.end() );

// elements are unique

答案 3 :(得分:0)

假设std::mapstd::set的通用实现策略,即平衡二叉搜索树,插入和查找都必须进行树遍历才能找到密钥所在的位置。因此,插入失败后插入的速度大约是插入速度的两倍。

  

std :: map如何管理正确存储(哈希?)数据以便通过operator []进行快速访问?

通过您指定的比较功能(或std::less,如果您在自定义类型上重载operator<,则该功能可用。在任何情况下,std::mapstd::set都是不是哈希表。

答案 4 :(得分:0)

据我所知,

std::setstd::map都是红黑树。并且可能仅使用插入会更快(然后两者都是因为您将查找时间加倍)。

mapset使用operator <。只要您的班级定义了operator <,就可以将它们用作关键字。

相关问题