应该使用插入排序还是构造堆来提高性能?

Ala*_*lan 2 c++ sorting algorithm boost stl

我们有大型(100,000+元素)结构的有序向量(运算符<重载以提供排序):

std::vector < MyType > vectorMyTypes;
std::sort(vectorMyType.begin(), vectorMyType.end());
Run Code Online (Sandbox Code Playgroud)

我的问题是,在保留排序顺序的同时向这些向量添加新元素时,我们会看到性能问题.目前我们正在做类似的事情:

for ( a very large set )
{
    vectorMyTypes.push_back(newType);
    std::sort(vectorMyType.begin(), vectorMyType.end());

    ...

    ValidateStuff(vectorMyType); // this method expects the vector to be ordered
}
Run Code Online (Sandbox Code Playgroud)

这不完全是我们的代码看起来的样子,因为我知道这个例子可以用不同的方式进行优化,但是它可以让你了解性能如何成为一个问题,因为我在每一个之后进行排序push_back.

我认为我基本上有两种选择来提高性能:

  1. 使用(手工制作?)插入排序而不是std::sort提高排序性能(部分排序的矢量上的插入排序非常快)

  2. 通过使用std::make_heapstd::push_heap维护排序顺序来创建堆

我的问题是:

  • 我应该实现插入排序吗?Boost中有什么东西可以帮助我吗?

  • 我应该考虑使用堆吗?我该怎么做?


编辑:

感谢您的所有回复.我理解我给出的示例远非最佳,并且它不能完全代表我现在在代码中的内容.它只是在那里说明我遇到的性能瓶颈 - 也许这就是为什么这个问题没有看到许多上升票:)

非常感谢史蒂夫,这通常是最简单的答案,也许是我对问题的过度分析使我对最明显的解决方案视而不见.我喜欢你概述的简洁方法直接插入预先排序的矢量.

正如我评论的那样,我现在限制使用向量,因此std :: set,std :: map等不是一个选项.

Ste*_*sop 10

有序插入不需要提升:

vectorMyTypes.insert(
    std::upper_bound(vectorMyTypes.begin(), vectorMyTypes.end(), newType),
    newType);
Run Code Online (Sandbox Code Playgroud)

upper_bound提供一个有效的插入点,前提是向量按开始排序,所以只要你只在正确的位置插入元素,就完成了.我原先说过lower_bound,但是如果向量包含多个相等的元素,那么upper_bound选择需要较少工作的插入点.

这必须复制O(n)元素,但是你说插入排序"非常快",而且速度更快.如果它不够快,你必须找到一种方法来批量添加项目并在最后验证,或者放弃连续存储并切换到维护订单的容器,例如setmultiset.

堆不会在底层容器中维护顺序,但对于优先级队列或类似物是有利的,因为它可以快速删除最大元素.你说你想按顺序维护向量,但如果你从来没有按顺序迭代整个集合,那么你可能不需要它完全排序,那就是堆有用的时候.

  • upper_bound执行二进制搜索,标准保证它是随机访问迭代器的O(log N).区别在于它返回一个迭代器,而`binary_search`返回`bool`. (2认同)

Gab*_*yer 6

根据Meyers的Effective STL项目23,如果您的应用程序在3个阶段中使用其数据结构,则应使用排序向量.从这本书中,他们是:

  1. 设置.通过在其中插入大量元素来创建新的数据结构.在此阶段,几乎所有操作都是插入和擦除.查找很少见,不存在
  2. 查找.查阅数据结构以查找特定信息.在此阶段,几乎所有操作都是查找.插入和删除很少或不存在.有这么多的查找,这个阶段的性能使其他阶段的性能偶然.
  3. 改组.修改数据结构的内容.也许通过删除所有当前数据并在其位置插入新数据.在行为上,这个阶段相当于第1阶段.一旦完成此阶段,应用程序将返回阶段2

如果您对数据结构的使用类似于此,则应使用已排序的向量,然后使用提及的binary_search.如果没有,典型的关联容器应该这样做,这意味着一个集合,多集,地图或多图,因为这些结构是默认排序的