首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >heap __adjust_heap函数是如何工作的?

heap __adjust_heap函数是如何工作的?
EN

Stack Overflow用户
提问于 2017-09-18 22:26:28
回答 3查看 848关注 0票数 3

我正在使用std::priority_queue,我正在尝试了解pop函数是如何工作的,以了解每次pop调用中发生了多少次比较。我已经看到优先级队列是基于std::heap的。具体地说,pop函数使用__adjust_heap函数。我试图理解这个函数,但在逻辑部分遇到了困难。

我知道在标准的pop_heap函数中,第一个对象被删除,然后最后一个对象被放到顶部,并与它的两个子对象进行比较。但在这段代码中似乎并非如此。

有人能帮我理解一下它是怎么工作的吗?

代码语言:javascript
复制
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
      _Distance __len, _Tp __value, _Compare __comp)
{
  const _Distance __topIndex = __holeIndex;
  _Distance __secondChild = __holeIndex;
  while (__secondChild < (__len - 1) / 2)
{
  __secondChild = 2 * (__secondChild + 1);
  if (__comp(__first + __secondChild,
         __first + (__secondChild - 1)))
    __secondChild--;
  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
  __holeIndex = __secondChild;
}
  if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
{
  __secondChild = 2 * (__secondChild + 1);
  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
                         + (__secondChild - 1)));
  __holeIndex = __secondChild - 1;
}
  std::__push_heap(__first, __holeIndex, __topIndex, 
           _GLIBCXX_MOVE(__value),
           __gnu_cxx::__ops::__iter_comp_val(__comp));
}

格式化以提高可读性:

代码语言:javascript
复制
adjust_heap(RandomAccessIterator first, Distance holeIndex, Distance len, Tp value, Compare comp) {
    const Distance topIndex = holeIndex;

    Distance secondChild = holeIndex;

    while (secondChild < (len - 1) / 2) {
        secondChild = 2 * (secondChild + 1);
        if (comp(first + secondChild, first + (secondChild - 1)))
            secondChild--;
        *(first + holeIndex) = std::move(*(first + secondChild));
        holeIndex = secondChild;
    }

    if ((len & 1) == 0 && secondChild == (len - 2) / 2) {
        secondChild = 2 * (secondChild + 1);
        *(first + holeIndex) = std::move(*(first + (secondChild - 1)));
        holeIndex = secondChild - 1;
    }

    std::push_heap(first, holeIndex, topIndex, std::move(value), gnu_cxx::ops::iter_comp_val(comp));
}
EN

回答 3

Stack Overflow用户

发布于 2017-09-18 23:33:09

该标准规定比较的次数最多为log(N),其中N是堆的大小。

例如,参见http://en.cppreference.com/w/cpp/algorithm/push_heap

您列出的帮助器函数只是一个实现细节(从__前导名称中可以看到)

票数 3
EN

Stack Overflow用户

发布于 2020-06-24 17:44:54

我还没有详细分析这个函数,但我在this book的第201页找到了它的简短描述:

“模板函数Adjust_heap在堆中向下渗透一个洞,直到它没有子代。然后它调用Push_heap将该洞沿堆向上渗透到存储指定值的适当位置。从模板函数Partial_sort_copy和堆模板函数中的几个位置调用Adjust_heap。”

票数 0
EN

Stack Overflow用户

发布于 2022-01-07 12:23:31

您没有提到代码是从哪里截取的,但我假设它来自于C++标准库的某个实现(例如,可以在here中找到的gcc libc++ )。

该函数将二进制堆中的一个元素向下移动到最底部,然后调用push_heap将其再次向上移动,直到恢复了max-heap属性(每个元素的子元素的值小于元素本身的值)。

为什么元素被推到最底部,然后又被抬起来呢?为什么我们不在元素到达它的最终目的地后停止呢?这个问题的答案可能在于adjust_heap函数的典型用法。它用在pop_heap函数中,该函数将根节点(我们想要提取或“弹出”的那个)与最右边的叶子交换,然后使用adjust_heap向下接收新的根节点,直到恢复堆属性。如果我们想要在元素到达其最终位置时立即停止,我们需要每个下降步骤进行2次比较(比较两个孩子,以确定我们必须下降的方向,并与元素进行比较,以确定我们是否需要停止)。这些比较中的第二个可以通过首先向下一直下降,然后再次向上移动元素来保存。如果元素的最终位置接近底部(很可能是这样,因为新的根最初来自最右边的叶子),则操作速度可以比传统的“下降到到达最终位置”更快。

例如,堆排序的Bottom-up变体中也使用了这种先向下移动,然后再向上移动的方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46281798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档