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

C++ std::map or std::set - efficiently insert duplicates

本文关键字:std 插入 有效地 set map C++      更新时间:2023-10-16

我有一堆充满重复的数据,我想消除重复项。你知道,例如 [1, 1, 3, 5, 5, 5, 7] 变成 [1, 3, 5, 7]。

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

另一个问题 - 如果我存储在其中的数据不像整数那样微不足道,而是一个自定义类,那么 std::map 如何设法正确存储(哈希?)数据以便通过 operator[] 快速访问?

std::map不使用

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

如果你不需要同时存储键和值(看起来你不需要),你应该只使用std::set,因为这更合适。

该标准没有说明mapset在引擎盖下使用哪些数据结构,只是说某些操作具有一定的时间复杂性。 实际上,我知道的大多数实现都使用树。

如果您使用 operator[]insert,则在

时间复杂度方面没有区别,但是我会在我做search之前使用 insertoperator[],如果没有找到该项目,则使用insert。 后者意味着进行两次单独的搜索以将项目插入到集合中。

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

根据集合的大小以及重复项与唯一值的比率,将对象放入 std::vector<T> 中可能会更快,然后std::sort(),然后将std::unique()std::vector<T>::erase()一起使用以删除重复项。

你应该做多少次?

如果通常插入:

//*/
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

假设std::mapstd::set的共同实现策略,即平衡的二叉搜索树,插入和查找都必须进行树遍历以找到键应该在的位置。因此,失败的查找后插入的速度大约是插入的两倍。

std::map 如何设法正确存储(哈希?)数据,以便通过 operator[] 快速访问?

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

据我所知

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

mapset使用operator <。只要您的类定义了operator <它就可以将它们用作键。