如何在 C++ 标准库中更改堆中的最大元素?

Posted

技术标签:

【中文标题】如何在 C++ 标准库中更改堆中的最大元素?【英文标题】:How to change max element in a heap in C++ standard library? 【发布时间】:2015-06-22 03:46:30 【问题描述】:

如果我有一个最大堆,并且如果我需要更改最大元素,则归结为单个气泡下降算法。有没有办法通过 C++ 标准库做到这一点,而无需手动编码算法?

我知道它应该等同于 pop_heap + push_heap,但这是 2 次冒泡操作,而不仅仅是一次。

那么 - 这个冒泡算法是通过库 API 公开的吗?

【问题讨论】:

【参考方案1】:

如果您愿意在自己的容器v 上调用std::pop_heap(),那么您可以在弹出堆之前先在容器上的“修改”元素上先v.push_back()。然后,收缩v

// Precondition is that v is already a heap.
void change_max_element (std::vector<int> &v, int modified_value) 
    v.push_back(modified_value);
    std::pop_heap(v.begin(), v.end());
    v.pop_back();

这“有效”是因为std::pop_heap() 被定义为交换第一个和最后一个元素并冒泡。但是,还规定了输入序列应该是有效堆。如果我们能够定义一个专门的比较操作,允许新推回的项目在它已经在最后一个位置时报告自己属于最后一个位置,那么它在技术上可以满足要求。

【讨论】:

虽然有一个警告(但我认为这不是问题)。 std::pop_heap() 的文档要求 [first, last) 是一个堆,但是当您 push_back 一个新值作为最后一个时,不能保证 [first, last) 是一个堆。我不认为这很重要,因为最后一个元素无论如何都会移到第一个并执行 heapify。 @szli:这是一个很好的观点。未来的实现可能会利用该要求并仍然产生指定的效果。然而,效果被如此具体地描述。 我查看了 STL 的 GNU/Clang/SGI 实现,唯一的假设是 [first, last-1) 是一个堆。第一步是交换 first 和 last-1,然后 heapify [first, last-1)。至少现在是安全的。【参考方案2】:

你会得到最接近的是std::make_heap,这可能比简单的弹出/推送慢。

然而,boost heap(s?) 有“Fixup Interface”,它允许您根据需要进行修改。 http://www.boost.org/doc/libs/1_51_0/doc/html/heap/concepts.html#heap.concepts.mutability

【讨论】:

我认为std::make_heap 会比pop 和push 大堆慢很多。对于小堆,它可能会更快。 @rici:我不知道make_heap 是如何实现的,但是可能对于除了一个元素之外已经是堆的东西来说它可能非常快. 可能它甚至是最适合这种情况的。虽然取决于实施。而且我完全在推测,无论初始布局如何,都可能或多或少地要求 make_heap 实现是相同的运行时。 不管它是怎么实现的,它需要检查每一个元素才能知道你给它的已经是一个堆,除了一个元素。所以这是 O(N)。 Pop 和 push 是 O(log N),具有稍大的常数乘数(不过可能不超过 2 或 3),因此对于大堆,make_heap 将无法扩展。

以上是关于如何在 C++ 标准库中更改堆中的最大元素?的主要内容,如果未能解决你的问题,请参考以下文章

c++如何直接调用自己写的类中的函数,就像调用标准库中的函数那样

如何更改静态链接库中 const 字符串数组的 Visual Studio C++ 初始化序列

堆栈/堆中的向量元素?长输入,C++

如何找到向量中的最大元素(C++)?

如何在 C++ 中做一个整数 log2()?

如何选出最适合的C++ STL容器?