如何在最多进行3N比较时实现std :: make_heap?

时间:2011-06-09 22:03:29

标签: c++ algorithm stl big-o binary-heap

我查看了C ++ 0x标准,发现要求make_heap不应超过3 * N比较。

即。 heapify一个无序集合可以在O(N)

中完成
   /*  @brief  Construct a heap over a range using comparison functor.

这是为什么?

来源没有给我任何线索(g ++ 4.4.3)

while(true)+ __parent == 0不是线索,而是对O(N)行为的猜测

template<typename _RandomAccessIterator, typename _Compare>
void
make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Compare __comp)
{

  const _DistanceType __len = __last - __first;
  _DistanceType __parent = (__len - 2) / 2;
  while (true)
    {
      _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
      std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
                 __comp);
      if (__parent == 0)
        return;
      __parent--;
    }
}

__ adjust_heap看起来像一个log N方法:

while ( __secondChild < (__len - 1) / 2)
{
    __secondChild = 2 * (__secondChild + 1);

沼泽标准记录N给我。

  template<typename _RandomAccessIterator, typename _Distance,
       typename _Tp, typename _Compare>
    void
    __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), __comp);      
      }

为什么这是O <= 3N的任何线索将不胜感激 编辑:

实验结果:

此实际实施使用

  • &lt;堆积堆的2N比较
  • &lt; 1.5N用于以相反的顺序堆积堆。

2 个答案:

答案 0 :(得分:52)

答案 1 :(得分:17)

@templatetypedef已经为build_heap提供了build_heap的渐近运行时间 O(n)的原因。 a good answer第2版第6章也有证据。

至于为什么C ++标准要求最多使用 3n 比较:

从我的实验(见下面的代码)看来,实际上需要的是 2n 比较。实际上,CLRS包含def parent(i): return i/2 def left(i): return 2*i def right(i): return 2*i+1 def heapify_cost(n, i): most = 0 if left(i) <= n: most = 1 + heapify_cost(n, left(i)) if right(i) <= n: most = 1 + max(most, heapify_cost(n, right(i))) return most def build_heap_cost(n): return sum(heapify_cost(n, i) for i in xrange(n/2, 1, -1)) 仅使用 2(n-⌈logn⌉)比较的证明。

标准的界限似乎比要求的更加慷慨。


n                     10  20  50  100  1000  10000
build_heap_cost(n)     9  26  83  180  1967  19960

一些结果:

{{1}}