libc ++的`std :: make_heap`的实现是不一致的

时间:2014-06-29 10:09:57

标签: c++ stl clang llvm libc++

编辑:这不是询问如何以{(1)} O(n)的方式,而是这个特定的实现是否确实是O(n)

在O(n)时间内构建堆的教科书方法是从下到上依次构建堆。但是在我的Mac机器上在libc ++中实现std::make_heap

std::make_heap

其中template <class _RandomAccessIterator, class _Compare> inline _LIBCPP_INLINE_VISIBILITY void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { #ifdef _LIBCPP_DEBUG typedef typename add_lvalue_reference<__debug_less<_Compare> >::type _Comp_ref; __debug_less<_Compare> __c(__comp); __make_heap<_Comp_ref>(__first, __last, __c); #else // _LIBCPP_DEBUG typedef typename add_lvalue_reference<_Compare>::type _Comp_ref; __make_heap<_Comp_ref>(__first, __last, __comp); #endif // _LIBCPP_DEBUG } 定义为

__make_heap

这不是简单地迭代插入堆中,因此时间复杂度为O(n log n)吗?我是对的,这是一个错误吗?

2 个答案:

答案 0 :(得分:8)

这确实是一个不符合规范的O(n log n)实现。

将它与&#34;筛选&#34;进行比较来自Wikipedia article on heapsort的heapify版本表明它基本上是相同的算法。在增加的整数序列上测试它(最坏的情况)给出了非常适合n log n曲线的运行时间,并且所需的比较数量超过了标准规定的3n数字,即使对于小n也是如此。

虽然平均算法在3n限制内表现良好,但标准要求最坏情况下的表现,而不是平均表现。

答案 1 :(得分:0)

我相信这里的讨论似乎已经解决了问题。

问题的答案是:否; libc ++的std::make_heap实现满足了C ++标准对该例程的要求。

引用C ++ 11标准(即将推出的C ++ 14标准似乎没有改变)

template<class RandomAccessIterator>
  void make_heap(RandomAccessIterator first, RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
  void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

* Effects: Constructs a heap out of the range [first,last).
* Requires: The type of *first shall satisfy the MoveConstructible requirements (Table 20) and the MoveAssignable requirements (Table 22).
* Complexity: At most 3 * (last - first) comparisons.

唯一的复杂性要求是对比较运算符的调用次数。 我已经运行了几个测试,并得出结论,libc ++的实现满足了这个要求。我得到了2.3*N比较的操作。我在https://llvm.org/svn/llvm-project/libcxx/trunk/test/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp使用了测试。 @ n.m,你另有要求;我很期待看到你的测试用例。我的测试是使用std::random_shuffle进行洗牌的各种大小的整数数组完成的。

@WhozCraig链接的问题表明,该算法可以使用明显少于3N的比较来实现。我已经将这篇文章添加到我的(遗憾的是,很长的)阅读列表中,以便进一步研究并可能改进libc ++的make_heap实现。 (谢谢!)