The concept is very, very simple: let's do merging run by run (a run is a range without decrement).
template <class RandomIt>
void RunAwareMergeSort(RandomIt first, RandomIt last) {
RandomIt m_first(first); // the begin of first run of merge
RandomIt i(first); // the locater
while (true) {
while (++i < last && !(*i < *(i-1))); // locate the first run
if (!(i < last)) { // i has located the end of the last run
if (m_first == first) return; // the range has only one run; sorting completed
else { // the range has odd number of runs
m_first = i = first; // start over
continue;
}
}
RandomIt m_middle(i); // the end of first run of merge; the begin of second run of merge
while (++i < last && !(*i < *(i-1))); // locate the second run
std::inplace_merge(m_first, m_middle, i); // merge
if (i < last) m_first = i; // next
else m_first = i = first; // start over
}
}
- Best-case time complexity: \$O(n)\$ (which is better than typical merge sort)
- Average-case time complexity: \$O(n \log n)\$
- Worst-case time complexity: \$O(n \log n)\$
- Worst-case space complexity: \$O(n)\$
- Stability: true
This is slower than Timsort, right?