最近我在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.
答案 0 :(得分:4)
... push_heap有两个参数,默认情况下它将最小值推到last-1。只有当第一个参数小于第二个参数时才会这样做,否则它会保持不变。
不。如果您的存储是向量v
,并且当前是一个堆(使用make_heap
创建),则应调用
v.push_back(new_item);
push_heap(v.begin(), v.end());
考虑push_heap
确实取范围[begin, end-1)
(已经满足堆不变量所需)和end-1
附加的元素(可能不是),然后向上移动最后一个元素,直到为所有[begin, end)
恢复堆不变量。该算法解释为here。
发现push_heap并没有真正保持我的矢量排序......
堆未排序。他们有一个排序约束(the heap property),专门且故意弱于而不是完全排序。
如果要执行二进制搜索,则需要一个完全排序的容器,并且每次使用sort_heap
将堆转换为一个缓慢且具有破坏性的容器:您的容器不再是堆你打电话给这个,你不能把它当成一个。
现在,关于你的编辑:堆不必须按降序排列。最大堆按降序排列(前面有最大元素),最小堆按升序排列(前面有最小元素)。
标准库中的默认是使用operator<
进行比较来构建最小堆。要构建一个max-heap,只需传递std::greater<int>
或其他(可选的)final参数。