编辑:这不是询问如何以{(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)吗?我是对的,这是一个错误吗?
答案 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
实现。 (谢谢!)