从inplace_merge的C ++文档中,算法的复杂性是“如果使用内部缓冲区则比较线性(N-1),否则为NlogN(其中N是范围[first,last)中的数字元素”) 。内部缓冲区是什么意思,导致O(N-1)与O(NlogN)复杂化的原因是什么?
答案 0 :(得分:1)
内部缓冲区只是由足够大小的库分配的缓冲区,用于在合并发生时保存合并的输出(在合并完成后将其复制回原始范围)。如果使用此额外空间,则可以在线性时间内完成合并。如果它不能或不使用单独的缓冲区来存储输出,则操作会降级为使用运行时O(n log n)
的通用排序。
答案 1 :(得分:1)
扩展其他答案:
至少在libstdc ++和libc ++中,“内部缓冲区”是通过调用std::get_temporary_buffer
来提供的,这是STL中一个不起眼的标准例程。这个例程已经在C ++ 17中被弃用了,主要是因为它让人感到困惑和愚蠢。有关详细信息,请参阅this question,或阅读Stephan T. Lavavej's original deprecation proposal。
在libstdc ++中,get_temporary_buffer
实现为对operator new
的调用。 (Source)
在libc ++中,get_temporary_buffer
实现为对operator new
的调用。 (Source)
我不知道inplace_merge
是否在MSVC的标准库中使用get_temporary_buffer
,但我敢打赌这样做。
在MSVC中,it has been reported get_temporary_buffer
被视为对operator new
的调用。
您可以通过覆盖全局命名空间中的operator new
来将程序编写到observe this call to operator new
firsthand:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
void *operator new(size_t nbytes, const std::nothrow_t&) noexcept
{
puts("hello from operator new!");
return malloc(nbytes);
}
int main()
{
int a[32] = {
1,1,1,2,3,4,4,5,5,5,5,6,6,8,9,9,
1,1,2,3,3,3,4,4,5,5,7,8,9,9,9,9,
};
std::inplace_merge(&a[0], &a[16], &a[32]); // "hello from operator new!"
(void)a;
}
TL; DR:通过调用operator new
在堆上分配“内部缓冲区”。实现不是必需来调用operator new
,但在实践中他们都这样做。如果你重视堆,请远离inplace_merge
。