2121#ifndef SORT_HPP
2222#define SORT_HPP
2323
24+ #define ENABLE_OPTIMIZATION 0
25+
2426#include < algorithm>
2527#include < chrono>
2628#include < cmath>
@@ -39,6 +41,7 @@ template <class ForwardIterator, class Compare>
3941inline void
4042bubble_sort_impl (ForwardIterator first, ForwardIterator last, Compare compare, std::forward_iterator_tag) noexcept {
4143 ForwardIterator current, next;
44+
4245 for (; first != last; last = current) {
4346 current = next = first;
4447
@@ -188,7 +191,7 @@ inline void selection_sort(BidirectionalIterator first, BidirectionalIterator la
188191template <class RandomAccessIterator , class Compare >
189192inline void
190193heapify_down (RandomAccessIterator first, RandomAccessIterator last, std::size_t i, Compare compare) noexcept {
191- auto n = last - first;
194+ std:: size_t n = last - first;
192195 while (true ) {
193196 auto left = i * 2 + 1 ;
194197 auto right = i * 2 + 2 ;
@@ -413,7 +416,11 @@ template <class RandomAccessIterator,
413416 class Compare ,
414417 class T = typename std::iterator_traits<RandomAccessIterator>::value_type>
415418inline void merge_sort_buf (RandomAccessIterator first, RandomAccessIterator last, T* buffer, Compare compare) {
419+ #if ENABLE_OPTIMIZATION
416420 detail::MergeSorter<RandomAccessIterator, Compare, 16 >::sort (first, last, buffer, compare);
421+ #else // Not ENABLE_OPTIMIZATION
422+ detail::MergeSorter<RandomAccessIterator, Compare, 0 >::sort (first, last, buffer, compare);
423+ #endif // ENABLE_OPTIMIZATION
417424}
418425
419426template <class RandomAccessIterator , class T = typename std::iterator_traits<RandomAccessIterator>::value_type>
@@ -857,4 +864,305 @@ inline void bucket_sort(RandomAccessIterator first, RandomAccessIterator last) {
857864
858865} // namespace alg
859866
867+ // namespace extra
868+ #include < utility>
869+ #include < functional>
870+ #include < iterator>
871+
872+ namespace extra {
873+
874+ struct PartitionScheme {
875+ struct Lomuto {};
876+ struct Hoare {};
877+ struct DutchFlag {};
878+ };
879+
880+ /* @reference Lomuto's Partitioning Scheme
881+
882+ @link https://github.com/raywenderlich/swift-algorithm-club/tree/master/Quicksort
883+
884+ func partitionLomuto<T: Comparable>(_ a: inout [T], low: Int, high: Int) -> Int {
885+ let pivot = a[high]
886+
887+ var i = low
888+ for j in low..<high {
889+ if a[j] <= pivot {
890+ (a[i], a[j]) = (a[j], a[i])
891+ i += 1
892+ }
893+ }
894+
895+ (a[i], a[high]) = (a[high], a[i])
896+ return i
897+ }
898+
899+ func quicksortLomuto<T: Comparable>(_ a: inout [T], low: Int, high: Int) {
900+ if low < high {
901+ let p = partitionLomuto(&a, low: low, high: high)
902+ quicksortLomuto(&a, low: low, high: p - 1)
903+ quicksortLomuto(&a, low: p + 1, high: high)
904+ }
905+ }
906+ */
907+ template <class BidirectionalIterator , class Compare >
908+ inline BidirectionalIterator
909+ partition_lomuto_scheme (BidirectionalIterator first,
910+ BidirectionalIterator last,
911+ Compare compare) noexcept {
912+ --last;
913+
914+ auto it = first;
915+ for (; first != last; ++first) {
916+ if (compare (*first, *last)) {
917+ std::iter_swap (first, it);
918+ ++it;
919+ }
920+ }
921+
922+ std::iter_swap (last, it);
923+ return it;
924+ }
925+
926+ /* @reference Hoare's Partitioning Scheme
927+
928+ @link https://github.com/raywenderlich/swift-algorithm-club/tree/master/Quicksort
929+
930+ func partitionHoare<T: Comparable>(_ a: inout [T], low: Int, high: Int) -> Int {
931+ let pivot = a[low]
932+ var i = low - 1
933+ var j = high + 1
934+
935+ while true {
936+ repeat { j -= 1 } while a[j] > pivot
937+ repeat { i += 1 } while a[i] < pivot
938+
939+ if i < j {
940+ a.swapAt(i, j)
941+ } else {
942+ return j
943+ }
944+ }
945+ }
946+
947+ func quicksortHoare<T: Comparable>(_ a: inout [T], low: Int, high: Int) {
948+ if low < high {
949+ let p = partitionHoare(&a, low: low, high: high)
950+ quicksortHoare(&a, low: low, high: p)
951+ quicksortHoare(&a, low: p + 1, high: high)
952+ }
953+ }
954+ */
955+ template <class RandomAccessIterator , class Compare >
956+ inline RandomAccessIterator
957+ partition_hoare_scheme (RandomAccessIterator first,
958+ RandomAccessIterator last,
959+ Compare compare) noexcept {
960+ auto i = --first;
961+ auto j = last;
962+ ++first;
963+
964+ while (true ) {
965+ do { --j; } while (compare (*first, *j));
966+ do { ++i; } while (compare (*i, *first));
967+
968+ if (i >= j) {
969+ return j;
970+ }
971+ std::iter_swap (i, j);
972+ }
973+ }
974+
975+ /* @reference Dutch National Flag Partitioning Scheme
976+
977+ @link https://github.com/raywenderlich/swift-algorithm-club/tree/master/Quicksort
978+
979+ func partitionDutchFlag<T: Comparable>(_ a: inout [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) {
980+ let pivot = a[pivotIndex]
981+
982+ var smaller = low
983+ var equal = low
984+ var larger = high
985+
986+ while equal <= larger {
987+ if a[equal] < pivot {
988+ swap(&a, smaller, equal)
989+ smaller += 1
990+ equal += 1
991+ } else if a[equal] == pivot {
992+ equal += 1
993+ } else {
994+ swap(&a, equal, larger)
995+ larger -= 1
996+ }
997+ }
998+ return (smaller, larger)
999+ }
1000+
1001+ func quicksortDutchFlag<T: Comparable>(_ a: inout [T], low: Int, high: Int) {
1002+ if low < high {
1003+ let pivotIndex = random(min: low, max: high)
1004+ let (p, q) = partitionDutchFlag(&a, low: low, high: high, pivotIndex: pivotIndex)
1005+ quicksortDutchFlag(&a, low: low, high: p - 1)
1006+ quicksortDutchFlag(&a, low: q + 1, high: high)
1007+ }
1008+ }
1009+ */
1010+ template <class RandomAccessIterator , class Compare >
1011+ inline std::pair<RandomAccessIterator, RandomAccessIterator>
1012+ partition_dutchflag_scheme (RandomAccessIterator first,
1013+ RandomAccessIterator last,
1014+ Compare compare) noexcept {
1015+ auto p = *(--last);
1016+ auto e = first;
1017+
1018+ while (e <= last) {
1019+ if (compare (*e, p)) { std::iter_swap (first++, e++); }
1020+ else if (compare (p, *e)) { std::iter_swap (e, last--); }
1021+ else { e++; }
1022+ }
1023+
1024+ return {first, last};
1025+ }
1026+
1027+ namespace detail {
1028+
1029+ #if ENABLE_OPTIMIZATION
1030+
1031+ template <class RandomAccessIterator , class Compare , class _PartitionScheme >
1032+ inline void
1033+ quick_sort_impl_helper (RandomAccessIterator first,
1034+ RandomAccessIterator last,
1035+ Compare compare,
1036+ int recursion_count,
1037+ _PartitionScheme scheme) noexcept {
1038+ if (last - first <= 16 ) { // small
1039+ alg::insertion_sort (first, last, compare);
1040+ return ;
1041+ }
1042+ if (recursion_count <= 0 ) { // too many divisions
1043+ alg::heap_sort (first, last, compare);
1044+ return ;
1045+ }
1046+
1047+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::Lomuto>::value) {
1048+ auto pivot = partition_lomuto_scheme (first, last, compare);
1049+ quick_sort_impl_helper (first, pivot, compare, recursion_count - 1 , scheme);
1050+ quick_sort_impl_helper (++pivot, last, compare, recursion_count - 1 , scheme);
1051+ return ;
1052+ }
1053+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::Hoare>::value) {
1054+ auto pivot = partition_hoare_scheme (first, last, compare);
1055+ quick_sort_impl_helper (first, ++pivot, compare, recursion_count - 1 , scheme);
1056+ quick_sort_impl_helper (pivot, last, compare, recursion_count - 1 , scheme);
1057+ return ;
1058+ }
1059+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::DutchFlag>::value) {
1060+ auto pivots = partition_dutchflag_scheme (first, last, compare);
1061+ quick_sort_impl_helper (first, pivots.first , compare, recursion_count - 1 , scheme);
1062+ quick_sort_impl_helper (++pivots.second , last, compare, recursion_count - 1 , scheme);
1063+ return ;
1064+ }
1065+ }
1066+
1067+ template <class RandomAccessIterator , class Compare , class PartitionScheme >
1068+ inline void quick_sort_impl (RandomAccessIterator first,
1069+ RandomAccessIterator last,
1070+ Compare compare,
1071+ std::random_access_iterator_tag,
1072+ PartitionScheme scheme) {
1073+ auto recursion_count = 2 * alg::detail::log2 (last - first);
1074+ quick_sort_impl_helper (first, last, compare, recursion_count, scheme);
1075+ }
1076+
1077+ #else // Not ENABLE_OPTIMIZATION
1078+
1079+ template <class RandomAccessIterator , class Compare , class _PartitionScheme >
1080+ inline void quick_sort_impl (RandomAccessIterator first,
1081+ RandomAccessIterator last,
1082+ Compare compare,
1083+ std::random_access_iterator_tag iter_tag,
1084+ _PartitionScheme scheme) {
1085+ if (first == last || first == --last) { return ; }
1086+ ++last;
1087+
1088+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::Lomuto>::value) {
1089+ auto pivot = partition_lomuto_scheme (first, last, compare);
1090+ quick_sort_impl (first, pivot, compare, iter_tag, scheme);
1091+ quick_sort_impl (++pivot, last, compare, iter_tag, scheme);
1092+ return ;
1093+ }
1094+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::Hoare>::value) {
1095+ auto pivot = partition_hoare_scheme (first, last, compare);
1096+ quick_sort_impl (first, ++pivot, compare, iter_tag, scheme);
1097+ quick_sort_impl (pivot, last, compare, iter_tag, scheme);
1098+ return ;
1099+ }
1100+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::DutchFlag>::value) {
1101+ auto pivots = partition_dutchflag_scheme (first, last, compare);
1102+ quick_sort_impl (first, pivots.first , compare, iter_tag, scheme);
1103+ quick_sort_impl (++pivots.second , last, compare, iter_tag, scheme);
1104+ return ;
1105+ }
1106+ }
1107+
1108+ #endif // ENABLE_OPTIMIZATION
1109+
1110+ template <class BidirectionalIterator , class Compare , class _PartitionScheme >
1111+ inline void quick_sort_impl (BidirectionalIterator first,
1112+ BidirectionalIterator last,
1113+ Compare compare,
1114+ std::bidirectional_iterator_tag iter_tag,
1115+ _PartitionScheme scheme) noexcept {
1116+ if (first == last || first == --last) { return ; }
1117+ ++last;
1118+
1119+ if constexpr (std::is_same<_PartitionScheme, PartitionScheme::Lomuto>::value) {
1120+ auto pivot = partition_lomuto_scheme (first, last, compare);
1121+ quick_sort_impl (first, pivot, compare, iter_tag, scheme);
1122+ quick_sort_impl (++pivot, last, compare, iter_tag, scheme);
1123+ return ;
1124+ }
1125+ static_assert (!std::is_same<_PartitionScheme, PartitionScheme::Hoare>::value);
1126+ static_assert (!std::is_same<_PartitionScheme, PartitionScheme::DutchFlag>::value);
1127+ }
1128+
1129+ } // namespace detail
1130+
1131+ /* *
1132+ * @brief quick sort algorithm
1133+ *
1134+ * @details Uses introsort if the iterator is a random access iterator.
1135+ * Introsort uses insertion sort once the range gets small, and if the recursion depth
1136+ * becomes more than 2*log2(n) it uses heapsort.
1137+ * A random pivot is used for the partitioning if the iterator is a random access iterator.
1138+ * The last element is used as pivot if the iterator is a bidirectional iterator.
1139+ *
1140+ * @param first a bidirectional iterator
1141+ * @param last a bidirectional iterator
1142+ * @param compare a comparison functor
1143+ * @param scheme a partition scheme identifier
1144+ */
1145+ template <class BidirectionalIterator , class Compare , class PartitionScheme >
1146+ inline void quick_sort (BidirectionalIterator first,
1147+ BidirectionalIterator last,
1148+ Compare compare,
1149+ PartitionScheme scheme) {
1150+ using iter_category = typename std::iterator_traits<BidirectionalIterator>::iterator_category;
1151+ return detail::quick_sort_impl (first, last, compare, iter_category{}, scheme);
1152+ }
1153+
1154+ template <class BidirectionalIterator , class PartitionScheme >
1155+ inline void quick_sort (BidirectionalIterator first, BidirectionalIterator last, PartitionScheme scheme) {
1156+ using value_type = typename std::iterator_traits<BidirectionalIterator>::value_type;
1157+ quick_sort (first, last, std::less<value_type>(), scheme);
1158+ }
1159+
1160+ template <class BidirectionalIterator >
1161+ inline void quick_sort (BidirectionalIterator first, BidirectionalIterator last) {
1162+ using value_type = typename std::iterator_traits<BidirectionalIterator>::value_type;
1163+ quick_sort (first, last, std::less<value_type>(), PartitionScheme::Lomuto ());
1164+ }
1165+
1166+ } // namespace extra
1167+
8601168#endif // SORT_HPP
0 commit comments