[LLVMbugs] [Bug 20837] New: libc++ std::sort has O(n^2) worst case, standard mandates O(N log(N))

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Tue Sep 2 11:40:12 PDT 2014


            Bug ID: 20837
           Summary: libc++ std::sort has O(n^2) worst case, standard
                    mandates O(N log(N))
           Product: libc++
           Version: unspecified
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: All Bugs
          Assignee: unassignedclangbugs at nondot.org
          Reporter: orsonpeters at gmail.com
                CC: llvmbugs at cs.uiuc.edu, mclow.lists at gmail.com
    Classification: Unclassified

Created attachment 12978
  --> http://llvm.org/bugs/attachment.cgi?id=12978&action=edit
Evidence for quadratic worst case.

The C++ standard mandates that `std::sort` has complexity O(N log(N)), but
libc++'s implementation takes O(N^2) in the worst case.

As proof I've attached a program that constructs a worst case input for several
sizes. It also instruments the number of comparisons used to sort these worst
cases and prints the results. The technique used is described in the 1999 paper
"A Killer Adversary for Quicksort" by M. D. McIlroy.

Compiling and running:

$ clang++ -O2 -m64 -march=native -std=c++11 -stdlib=libc++ main.cpp
-nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc && ./a.out
N: comparisons
100: 2479
200: 10229
400: 40729
800: 161729
1600: 448698
3200: 1413898
6400: 5264298

This is clearly quadratic. To illustrate this defect more, these are the
comparison counts given by compiling using libstdc++:

$ clang++ -O2 -m64 -march=native -std=c++11 main.cpp && ./a.out
N: comparisons
100: 1742
200: 4260
400: 10035
800: 22784
1600: 51049
3200: 112386
6400: 244850

Inspecting the source of <algorithm> shows the cause of the issue: there is no
introsort implemented, only quicksort (albeit with non-trivial optimizations,
but nothing preventing the worst case). I've written a patch that augments the
current implementation to make it work as an introspective sort, switching to
heapsort if the recursion depth exceeds 2*floor(log(N)). This post can only
have one attachment, so I'll post it as an attachment to a comment.

Having not contributed to libc++ before I'm not 100% familiar with all coding
styles/(un)written rules. My changes are rather minimal though, so I've just
followed what style could be found in context. And of course I knowingly submit
my code under the libc++ licenses, the MIT license and the UIUC License.

You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20140902/cb4c5141/attachment.html>

More information about the llvm-bugs mailing list