Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to partially sort in a stable way

Tags:

c++

sorting

Is std::partial_sort stable and if not, is there a stable partial sort provided by the standard library or e.g. boost?

like image 270
ManuelSchneid3r Avatar asked Dec 02 '14 11:12

ManuelSchneid3r


People also ask

How do you stable a sort?

Stable sorting algorithms maintain the relative order of records with equal keys (i.e. values). That is, a sorting algorithm is stable if whenever there are two records R and S with the same key and with R appearing before S in the original list, R will appear before S in the sorted list.

How partial sort works?

In computer science, partial sorting is a relaxed variant of the sorting problem. Total sorting is the problem of returning a list of items such that its elements all appear in order, while partial sorting is returning a list of the k smallest (or k largest) elements in order.

What is partial_ sort in c++?

C++ Algorithm partial_sort() function is used to rearrange the elements in the range[first, last), in such a way that the elements between the first and middle will be sorted and the elements between the middle and last will be in an unspecified order.

Is Swift sort stable?

Whenever Swift's default sorting algorithm encounters an element that is equal to another element, it will preserve the original order of these elements in the output. In other words, Swift's sorting algorithm is a so-called stable sorting algorithm.


1 Answers

partial_sort is efficient and easy to provide because it is basically a quicksort where recursions that aren't necessary for the desired range are skipped. There is no equivalent efficient partial stable sort algorithm; stable_sort is usually implemented as a merge sort, and merge sort's recursion works the wrong way.

If you want a partial sort to be stable, you need to associate position information with each element. If you have a modifiable zip range you can do that by zipping together the elements and a iota vector, but modifiable zip ranges are actually impossible to build within the current iterator concepts, so it's easier to do indirect sorting via iterators and rely on the iterators' ordering. In other words, you can do this:

using MyThingV = std::vector<MyThing>;
using MyThingIt = typename MyThingV::iterator;
MyThingV things;
// Set up a vector of iterators. We'll sort that.
std::vector<MyThingIt> sorted; sorted.reserve(things.size());
for (auto it = things.begin(); it != things.end(); ++it) sorted.push_back(it);

std::partial_sort(sorted.begin(), sorted.begin() + upto_index, sorted.end(),
  [](MyThingIt lhs, MyThingIt rhs) {
    // First see if the underlying elements differ.
    if (*lhs < *rhs) return true;
    if (*rhs < *lhs) return false;
    // Underlying elements are the same, so compare iterators; these represent
    // position in original vector.
    return lhs < rhs;
  });

Now your base vector is still unsorted, but the vector of iterators is sorted the way you want.

like image 132
Sebastian Redl Avatar answered Sep 23 '22 05:09

Sebastian Redl