|
| 1 | +/** |
| 2 | + * Created by Liam Huang (Liam0205) on 2018/10/17. |
| 3 | + */ |
| 4 | + |
| 5 | +#ifndef SORTS_QUICK_SORT_HPP_ |
| 6 | +#define SORTS_QUICK_SORT_HPP_ |
| 7 | + |
| 8 | +#include <functional> |
| 9 | +#include <iterator> |
| 10 | +#include <algorithm> |
| 11 | +#include <utility> |
| 12 | + |
| 13 | +namespace detail { |
| 14 | +template <typename T, typename Compare = std::less<T>> |
| 15 | +const T& median(const T& a, const T& b, const T& c, Compare comp = Compare()) { |
| 16 | + if (comp(a, b) and comp(b, c) or comp(c, b) and comp(b, a)) { |
| 17 | + return b; |
| 18 | + } else if (comp(b, c) and comp(c, a) or comp(a, c) and comp(c, b)) { |
| 19 | + return c; |
| 20 | + } else { |
| 21 | + return a; |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +template <typename Iter, |
| 26 | + typename T = typename std::iterator_traits<Iter>::value_type, |
| 27 | + typename Compare = std::less<T>> |
| 28 | +const T& iter_median(Iter a, Iter b, Iter c, Compare comp = Compare()) { |
| 29 | + return median(*a, *b, *c, comp); |
| 30 | +} |
| 31 | + |
| 32 | +template <typename BidirIt, |
| 33 | + typename T = typename std::iterator_traits<BidirIt>::value_type, |
| 34 | + typename Compare = std::less<T>> |
| 35 | +std::pair<BidirIt, BidirIt> inplace_partition(BidirIt first, |
| 36 | + BidirIt last, |
| 37 | + const T& pivot, |
| 38 | + Compare comp = Compare()) { |
| 39 | + BidirIt last_less, last_greater, first_equal, last_equal; |
| 40 | + for (last_less = first, last_greater = first, first_equal = last; |
| 41 | + last_greater != first_equal; ) { |
| 42 | + if (comp(*last_greater, pivot)) { |
| 43 | + std::iter_swap(last_greater++, last_less++); |
| 44 | + } else if (comp(pivot, *last_greater)) { |
| 45 | + ++last_greater; |
| 46 | + } else { // pivot == *last_greater |
| 47 | + std::iter_swap(last_greater, --first_equal); |
| 48 | + } |
| 49 | + } |
| 50 | + const auto cnt = std::distance(first_equal, last); |
| 51 | + std::swap_ranges(first_equal, last, last_less); |
| 52 | + first_equal = last_less; |
| 53 | + last_equal = first_equal + cnt; |
| 54 | + return {first_equal, last_equal}; |
| 55 | +} |
| 56 | +} // namespace detail |
| 57 | + |
| 58 | +template <typename BidirIt, |
| 59 | + typename T = typename std::iterator_traits<BidirIt>::value_type, |
| 60 | + typename Compare = std::less<T>> |
| 61 | +void quick_sort(BidirIt first, BidirIt last, Compare comp = Compare()) { |
| 62 | + for (auto size = std::distance(first, last); size > 1; size = std::distance(first, last)) { |
| 63 | + const T pivot = detail::iter_median(first, last - 1, first + size / 2, comp); |
| 64 | + const auto eq = detail::inplace_partition(first, last, pivot, comp); |
| 65 | + quick_sort(first, eq.first, comp); |
| 66 | + first = eq.second; // Liam Huang: economize half of recursive calling. |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +#endif // SORTS_QUICK_SORT_HPP_ |
| 71 | + |
0 commit comments