inplace_merge: What causes a complexity of N*log(N) vs. N-1?

馋奶兔 提交于 2019-12-23 12:47:39

问题


From C++ documentation on inplace_merge, the complexity of the algorithm is "Linear in comparisons (N-1) if an internal buffer was used, NlogN otherwise (where N is the number elements in the range [first,last))". What do they mean by an internal buffer and what causes a complexity of O(N-1) vs. O(NlogN)?


回答1:


An internal buffer is simply a buffer allocated by the library of sufficient size to hold the output of the merge while the merge is happening (it's copied back to the original range after the merge is complete). If this extra space is used, the merge can be done in linear time. If it can't or doesn't use a separate buffer to store the output then the operation degrades to a general purpose sort with runtime O(n log n).




回答2:


To expand on the other answer(s):

  • At least in libstdc++ and libc++, the "internal buffer" is provided by calling std::get_temporary_buffer, an obscure yet standard routine in the STL. This routine has been deprecated in C++17, basically because it's confusing and kind of dumb. See this question for details, or read Stephan T. Lavavej's original deprecation proposal.

  • In libstdc++, get_temporary_buffer is implemented as a call to operator new. (Source)

  • In libc++, the get_temporary_buffer is implemented as a call to operator new. (Source)

  • I don't know whether inplace_merge uses get_temporary_buffer in MSVC's standard library, but I would bet money that it does.

  • In MSVC, it has been reported that get_temporary_buffer is implemented as a call to operator new.

You can write a program to observe this call to operator new firsthand by overriding operator new in the global namespace:

#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: The "internal buffer" is allocated on the heap by calling operator new. Implementations are not required to call operator new, but in practice they all do. Stay far, far away from inplace_merge if you value your heap.



来源:https://stackoverflow.com/questions/11367674/inplace-merge-what-causes-a-complexity-of-nlogn-vs-n-1

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!