Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a vector in which the n first elements have been already sorted?

Consider a std::vector v of N elements, and consider that the n first elements have already been sorted withn < N and where (N-n)/N is very small:

sorted/unsorted vector

Is there a clever way using the STL algorithms to sort this vector more rapidly than with a complete std::sort(std::begin(v), std::end(v)) ?

EDIT: a clarification: the (N-n) unsorted elements should be inserted at the right position within the n first elements already sorted.

EDIT2: bonus question: and how to find n ? (which corresponds to the first unsorted element)

like image 769
Vincent Avatar asked Feb 06 '14 01:02

Vincent


People also ask

Can we sort vector using sort function?

Sorting a Vector in C++ in Ascending order A vector in C++ can be easily sorted in ascending order using the sort() function defined in the algorithm header file. The sort() function sorts a given data structure and does not return anything. The sorting takes place between the two passed iterators or positions.

How do you know if a vector is sorted?

if (result == false) cout << "Vector elements are not sorted in ascending order." << endl; result = is_sorted(v.

How do you sort a number in vector?

Sorting a vector in C++ Sorting a vector in C++ can be done by using std::sort(). It is defined in<algorithm> header. To get a stable sort std::stable_sort is used. It is exactly like sort() but maintains the relative order of equal elements.


7 Answers

Sort the other range only, and then use std::merge.

like image 56
Kornel Kisielewicz Avatar answered Sep 22 '22 16:09

Kornel Kisielewicz


void foo( std::vector<int> & tab, int n ) {
     std::sort( begin(tab)+n, end(tab));
     std::inplace_merge(begin(tab), begin(tab)+n, end(tab));
}

for edit 2

auto it = std::adjacent_find(begin(tab), end(tab),  std::greater<int>() );
if (it!=end(tab)) {
    it++;
    std::sort( it, end(tab));
    std::inplace_merge(begin(tab), it, end(tab));
}
like image 23
galop1n Avatar answered Sep 20 '22 16:09

galop1n


The optimal solution would be to sort the tail portion independently and then perform in-place merge, as described here

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.22.5750

The algorithm is quite convoluted and is usually regarded as "not worth the effort".

Of course, with C++ you can use readily available std::inplace_merge. However, the name of that algorithm is highly misleading. Firstly, there's no guarantee that std::inplace_merge actually works in-place. And when it is actually in-place, there's no guarantee that it is not implemented as a full-blown sort. In practice it boils down to trying it and seeing whether it is good enough for your purposes.

But if you really want to make it in-place and formally more efficient than a full sort, then you will have to implement it manually. STL might help with a few utility algorithms, but it does not offer any solid solutions of "just a few calls to standard functions" kind.

like image 43
AnT Avatar answered Sep 21 '22 16:09

AnT


Using insertion sort on N - n last elements:

template <typename IT>
void mysort(IT begin, IT end) {
    for (IT it = std::is_sorted_until(begin, end); it != end; ++it) {
        IT insertPos = std::lower_bound(begin, it, *it);
        IT endRotate = it;
        std::rotate(insertPos, it, ++endRotate);
    }
}
like image 22
Jarod42 Avatar answered Sep 21 '22 16:09

Jarod42


The Timsort sorting algorithm is a hybrid algorithm developed by Pythonista Tim Peters. It makes optimal use of already-sorted subsegments anywhere inside the array, including in the beginning. Although you may find a faster algorithm if you know for sure that in particular the first n elements are already sorted, this algorithm should be useful for the overall class of problems involved. Wikipedia describes it as:

The algorithm finds subsets of the data that are already ordered, and uses that knowledge to sort the remainder more efficiently.

In Tim Peters' own words,

It has supernatural performance on many kinds of partially ordered arrays (less than lg(N!) comparisons needed, and as few as N-1), yet as fast as Python's previous highly tuned samplesort hybrid on random arrays.

Full details are described in this undated text document by Tim Peters. The examples are in Python, but Python should be quite readable even to people not familiar with its syntax.

like image 41
gerrit Avatar answered Sep 20 '22 16:09

gerrit


Use std::partition_point (or is_sorted_until) to find n. Then if n-m is small do an insertion sort (linear search+std::rotate).

like image 26
Nicolas Avatar answered Sep 24 '22 16:09

Nicolas


I assume that your question has two aims:

  • improve runtime (using a clever way)
  • with few effort (restricting to STL)

Considering these aims, I'd strongly recommend against this specific optimization, unless you are sure that the effort is worth the benefit. As far as I remember, std::sort() implements the quick sort algorithm, which is almost as fast on presorted input as to determine, if / how-much-of the input is sorted.

Instead of meddling with std::sort you can try changing the data structure to a sorted/prioritized queue.

like image 28
No answer Avatar answered Sep 21 '22 16:09

No answer