更有效的填充unordered_set方式?
More efficient way to populate unordered_set?
我有一个整数数组连续存储在内存中,我想将它们全部添加到unordered_set
集合中。
现在,我一次添加一个。
for (int i = 0; i < count; i++)
collection.insert(pi[i]);
有没有办法更有效地做到这一点?
我意识到这些项目不是连续存储在集合中,因此它不会像将数组移交给集合那么简单。但这能以某种方式优化吗?
unordered_set
有一个构造函数,该构造函数采用一系列元素来最初添加它们:
template< class InputIt >
unordered_set( InputIt first, InputIt last,
size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),
const Allocator& alloc = Allocator() );
因此,您只需执行collection = std::unordered_set{ p, p + count };
,然后由实施决定。
正如其他用户在评论中指出的那样,insert
还有一个重载,它需要一个范围:
template< class InputIt >
void insert( InputIt first, InputIt last );
所以,就像调用构造函数一样,你可以做,collection.insert(p, p + count);
不能保证这种重载会更有效,因为平均重载的复杂性都是线性的,以及只是逐个插入元素。
事实上,如果我们研究一下如何在 MSVC 中实现insert
,它非常简单。
template<class _Iter>
void insert(_Iter _First, _Iter _Last)
{ // insert [_First, _Last) at front, then put in place
_DEBUG_RANGE(_First, _Last);
for (; _First != _Last; ++_First)
emplace(*_First);
}
所以这种情况没有优化。
我认为,最好的方法是调用reserve
,如果您知道要添加的许多元素,并且如果有很多冲突(整数不会有),也许可以修改bucket_count
。
使用基于范围的构造函数或插入方法将简洁而优雅,但可能与您的方法一样高效。 原因是传递给这些函数的迭代器是输入迭代器,而不是随机迭代器。 因此,无法计算范围的长度,并且当集合的负载系数达到高时,必须通过定期重新哈希逐个插入元素。
请考虑调用 std::unordered_set 的保留方法。
collection.reserve(pi.size());
collection.insert(pi.begin(), pi.end());
编辑: 如评论中所述,人们还可以担心逐个散列插入元素的效率。 然后,能够执行某种批量插入将是有效的。 但是,在OP的情况下,元素是整数,碰巧在std::hash的大多数(如果不是全部)实现中使用标识函数进行哈希处理,这不会花费那么多;)。事实上,它是随机整数可以获得的最佳哈希函数。其他哈希函数可能更适合"有组织"的集合。
编辑2: 注释部分现在推测插入方法的更好实现。 我坚持认为基于范围的插入重载要求输入迭代器,所以是的,您实际上可以传递任何非输出迭代器。 还可以查看范围插入的最坏情况复杂性:您将看到它被指定为允许逐个插入元素。 最后,看一下 insert 方法的一些实现,您会发现随机访问迭代器没有特定的重载。 这是有道理的,因为没有理由在插入方法中强制进行额外的检查,而保留方法在这里,用于我们希望将容器设置为至少给定容量的情况。 基于此,上面的答案很可能是基于 stdlib 实际实现的最佳技术。
- 如何在c++中为模板函数实例创建快捷方式
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 以螺旋方式打印矩阵的程序.(工作不好)
- 为什么我无法更改"set<set>"循环中的值<int>
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 对于set上的循环-获取next元素迭代器
- 创建引用向量的优雅方式
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 不同/较旧的处理器运行c++代码的方式是否不同
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 在声明中合并两个常量"std::set"(不是在运行时)
- 如果条件为TRUE(最佳方式?),则在do while循环中后置增量
- 有没有办法对std::unordered_set、std::unrdered_map、std::set、std::map
- 重载方法的方式会在使用临时调用时生成编译器错误
- 在reactor中存储eventHandlers的最佳方式是什么
- 如何以优化的方式同时迭代两个间距不相等的数组
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 为什么我不能用谓词的实例化来构造 std::set,但我可以分配一个以这种方式构造的 std::set?