使用标准库提供的函数模板std::pop_heap()和std::push_heap(),无法在对数时间内修改堆的任意元素而不违反堆属性。
但是,您可以定义自己类似于STL的函数模板set_heap_element()
来实现此目的:
template<typename RandomIt, typename T, typename Cmp>
void set_heap_element(RandomIt first, RandomIt last, RandomIt pos, T value, Cmp cmp)
{
const auto n = last - first;
*pos = std::move(value); // replace previous value
auto i = pos - first;
using std::swap;
// percolate up
while (i > 0) { // non-root node
auto parent_it = first + (i-1)/2;
if (cmp
接下来,你可以为最大堆提供以下简化的set_heap_element()
重载:
#include <functional> // std::less
template<typename RandomIt, typename T>
void set_heap_element(RandomIt first, RandomIt last, RandomIt pos, T value) {
return set_heap_element(first, last, pos, value, std::less<T>{});
}
这个重载使用一个
std::less<T>
对象作为原始函数模板的比较函数对象。
示例
在您的最大堆示例中,set_heap_element()
可按以下方式使用:
std::vector<int> v{1,2,3,5,9,20,3};
std::make_heap(v.begin(), v.end());
// set 4th element to 35 in O(log n)
set_heap_element(v.begin(), v.end(), v.begin() + 3, 35);
您可以使用
std::is_heap()
来检查在使用上述
set_heap_element()
函数模板设置元素后,
v
是否仍满足
最大堆属性。该函数具有线性时间复杂度。
assert(std::is_heap(v.begin(), v.end()));
最小堆是怎么样的?
对于最小堆,你可以通过将std::greater<int>
对象作为函数调用std::make_heap()
、set_heap_element()
和std::is_heap()
的最后一个参数来实现:
std::vector<int> v{1,2,3,5,9,20,3};
std::make_heap(v.begin(), v.end(), std::greater<int>{});
set_heap_element(v.begin(), v.end(), v.begin() + 3, 35, std::greater<int>{});
assert(std::is_heap(v.begin(), v.end(), std::greater<int>{}));
std::priority_queue
。 - eripmake_heap
的复杂度仅为线性,因此只需再次调用它。 - 463035818_is_not_a_number