【发布时间】:2014-08-19 22:26:33
【问题描述】:
编辑:这不是问std::make_heap O(n) 的方式,而是问这个特定的实现是否确实是 O(n)
教科书式的O(n)时间建堆方法是从下往上依次建堆。但是std::make_heap在我的Mac机器上在libc++中的实现是
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 定义为
template <class _Compare, class _RandomAccessIterator>
void
__make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
difference_type __n = __last - __first;
if (__n > 1)
{
__last = __first;
++__last;
for (difference_type __i = 1; __i < __n;)
__push_heap_back<_Compare>(__first, ++__last, __comp, ++__i);
}
}
template <class _Compare, class _RandomAccessIterator>
void
__push_heap_back(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len)
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
if (__len > 1)
{
__len = (__len - 2) / 2;
_RandomAccessIterator __ptr = __first + __len;
if (__comp(*__ptr, *--__last))
{
value_type __t(_VSTD::move(*__last));
do
{
*__last = _VSTD::move(*__ptr);
__last = __ptr;
if (__len == 0)
break;
__len = (__len - 1) / 2;
__ptr = __first + __len;
} while (__comp(*__ptr, __t));
*__last = _VSTD::move(__t);
}
}
}
这不是简单地迭代插入到堆中,因此时间复杂度为 O(n log n)?这是一个错误,我说得对吗?
【问题讨论】:
-
See this answer。简而言之,该算法并不像最初看起来那么简单。
-
@WhozCraig:我知道 O(n) 算法。我在问这个特定的实现(libc++)是否无法使用正确的实现。
-
@WhozCraig:这绝不是一个重复的问题。我不是在问如何以 O(n) 的方式进行操作。相反,我问的是这个实现是否确实是 O(n)。
-
@Matthieu M.:请参阅我的新编辑,说明这不是重复的。
-
我没有将其标记为重复。我仅为算法分析链接了该答案(这是准确的)。您的问题是关于该算法的具体实现,虽然相关,但 不是 重复(恕我直言)并且不应该被标记为这样(这就是为什么我 没有 这样做)。投票重新开放。