inplace_merge:是什么导致N * log(N)与N-1的复杂性?

时间:2012-07-06 18:24:01

标签: c++ merge complexity-theory

从inplace_merge的C ++文档中,算法的复杂性是“如果使用内部缓冲区则比较线性(N-1),否则为NlogN(其中N是范围[first,last)中的数字元素”) 。内部缓冲区是什么意思,导致O(N-1)与O(NlogN)复杂化的原因是什么?

2 个答案:

答案 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