麻烦麻烦

时间:2013-03-25 17:36:36

标签: c++ vector heap time-complexity stl-algorithm

最近我在stackoverflow上发布了一个问题Time complexity issues with multimap 我得到了一些很好的答案,这些答案让我使用了堆,奇怪的是我之前根本没用过。我创建了一个使用minheap和maxheap重写的新程序。它的效果很好,因为它比我为此问题实现的任何其他程序快得多。唯一的问题是它偶尔会抛出一些错误的答案。 我回去做了很多调试。我意识到问题出在我的堆组织中。它没有按照我认为使用push_heap和pop_heap与比较操作的方式进行排序和分发。此外,当我尝试在Visual Studio上运行该程序时,我最终会看到很多断言错误被抛出。我尝试在cplusplus.com和cppreference.com上阅读更多关于堆及其方法的内容。我想我可能没有正确理解,因此遇到了进一步的问题。

令我困惑的第一件事是push_heap。我理解它的方式是:push_heap有两个参数,而默认它将 最少 值推到last-1。它只在第一个参数小于第二个参数时执行此操作,否则它保持不变。它基本上维护了正常堆的顺序。第三个可选参数是比较运算符,可以用作更大(),然后将更大元素推送到最后1位置。

没有意义的是,如果我在向量中动态插入或删除数字,我在保持此顺序时遇到问题。如果我希望向量按升序排列,我会使用更大的操作来继续推送堆,以便值可以升序。但是当你第一次看到push_heap方法时会让人感到困惑,因为它看起来很像其他一些算法函数,它们在数字的 范围 中执行,例如: / p>

 std::unique (myvector.begin(), myvector.end(), myfunction); 

push_heap不行。它不会对所有向量的范围中的数字执行此比较操作,我最初并不理解。

在发现push_heap并没有真正保持我的矢量排序后,我不得不保持我的矢量排序以便使用二进制搜索。我使用了sort_heap,但是这使程序变慢到不够快的程度。

另外,我发现有时push_heap会在奇怪的情况下抛出无效的堆错误。

例如:

   push_heap(v.begin(), v.end(), greater<int>());  

向量 755,98,55,22

你会在push_heap之后看到:

     22, 98, 55, 755

但是让我们说你有          22,98,55,755

通常它会继续前进而不执行任何推动,因为比较时的错误回报。这是可以预期的。

但有时我会尝试使用push_heap:

887,52,42,22

它会说

      'invalid heap' 

或者如果我尝试:       22,52,44,887 ,而不仅仅是返回false并继续前进将会打破

'invalid heap'

有时也会出现pop_heap。

为什么我的堆无效?是因为所有堆都必须按降序排列?

编辑:我在cplusplus.com上找到了这个,我想回答一个问题:

The element with the highest value is always pointed by first. The order of the other elements depends on the particular implementation, but it is consistent throughout all heap-related functions of this header.

1 个答案:

答案 0 :(得分:4)

  

... push_heap有两个参数,默认情况下它将最小值推到last-1。只有当第一个参数小于第二个参数时才会这样做,否则它会保持不变。

不。如果您的存储是向量v,并且当前是一个堆(使用make_heap创建),则应调用

v.push_back(new_item);
push_heap(v.begin(), v.end());

添加新项目。例如,请参阅herehere

考虑push_heap确实取范围[begin, end-1)(已经满足堆不变量所需)和end-1附加的元素(可能不是),然后向上移动最后一个元素,直到为所有[begin, end)恢复堆不变量。该算法解释为here


  

发现push_heap并没有真正保持我的矢量排序......

未排序。他们有一个排序约束(the heap property),专门且故意弱于而不是完全排序。

如果要执行二进制搜索,则需要一个完全排序的容器,并且每次使用sort_heap将堆转换为一个缓慢且具有破坏性的容器:您的容器不再是堆你打电话给这个,你不能把它当成一个。


现在,关于你的编辑:堆必须按降序排列。最大堆按降序排列(前面有最大元素),最小堆按升序排列(前面有最小元素)。

标准库中的默认是使用operator<进行比较来构建最小堆。要构建一个max-heap,只需传递std::greater<int>或其他(可选的)final参数。