Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_sort_utils.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
94#ifndef TPL_SORT_UTILS_H
95#define TPL_SORT_UTILS_H
96
97#include <ahUtils.H>
98#include <ahFunctional.H>
99#include <ah-errors.H>
100#include <tpl_arrayStack.H>
101#include <tpl_array.H>
102#include <tpl_dynArray.H>
103#include <tpl_dynDlist.H>
104#include <tpl_arrayHeap.H>
105#include <htlist.H>
106#include <vector>
107#include <utility>
108
109namespace Aleph
110{
121 extern size_t Insertion_Threshold;
122
129 extern size_t Quicksort_Threshold;
130
137 extern const int Not_Found;
138
159 template <template <typename> class Container, typename T,
160 class Compare = Aleph::less<T>>
161 [[nodiscard]] bool is_sorted(const Container<T> & cont, const Compare & cmp = Compare())
162 {
163 if (cont.is_empty())
164 return true;
165
166 typename Container<T>::Iterator it(cont);
167 const T & first = it.get_curr();
168 const T *prev = &first;
169 it.next_ne();
170 for (; it.has_curr(); it.next_ne())
171 {
172 const T & curr = it.get_curr();
173 if (cmp(curr, *prev))
174 return false;
175 prev = &curr;
176 }
177 return true;
178 }
179
202 template <template <typename> class Container, typename T,
203 class Compare = Aleph::less<T>>
204 [[nodiscard]] std::pair<bool, size_t> search_inversion(const Container<T> & cont,
205 const Compare & cmp = Compare())
206 {
207 if (cont.is_empty())
208 return std::make_pair(true, 0);
209
210 typename Container<T>::Iterator it(cont);
211 const T & first = it.get_curr();
212 const T *prev = &first;
213 size_t i = 1;
214 it.next_ne();
215 for (; it.has_curr(); it.next_ne(), ++i)
216 {
217 const T & curr = it.get_curr();
218 if (cmp(curr, *prev))
219 return std::make_pair(false, i);
220 prev = &curr;
221 }
222
223 return std::make_pair(true, i);
224 }
225
245 template <template <typename> class Container, typename T,
246 class Compare = Aleph::less<T>>
247 [[nodiscard]] bool is_inversely_sorted(const Container<T> & cont, const Compare & cmp = Compare())
248 {
249 if (cont.is_empty())
250 return true;
251
252 typename Container<T>::Iterator it(cont);
253 const T & first = it.get_curr();
254 const T *prev = &first;
255 it.next_ne();
256 for (; it.has_curr(); it.next_ne())
257 {
258 const T & curr = it.get_curr();
259 if (cmp(*prev, curr))
260 return false;
261 prev = &curr;
262 }
263 return true;
264 }
265
288 template <template <typename> class Container, typename T,
289 class Compare = Aleph::less<T>>
290 [[nodiscard]] std::pair<bool, size_t>
291 test_sorted(const Container<T> & cont, const Compare & cmp = Compare())
292 {
293 if (cont.is_empty())
294 return {true, 0};
295
296 typename Container<T>::Iterator it(cont);
297 const T & first = it.get_curr();
298 const T *prev = &first;
299 size_t i = 1;
300 it.next_ne();
301 for (; it.has_curr(); it.next_ne(), ++i)
302 {
303 const T & curr = it.get_curr();
304 if (cmp(curr, *prev))
305 return {false, i};
306 prev = &curr;
307 }
308 return {true, i};
309 }
310
311
345 template <typename T, class Compare = Aleph::less<T>>
346 inline
347 void selection_sort(T *a, const size_t n, const Compare & cmp = Compare())
349 {
350 if (n < 2)
351 return;
352
353 for (size_t i = 0, min, j; i < n - 1; ++i)
354 {
355 for (min = i, j = i + 1; j < n; ++j)
356 if (cmp(a[j], a[min]))
357 min = j;
358
359 if (cmp(a[min], a[i]))
360 std::swap(a[min], a[i]);
361 }
362 }
363
386 template <class Link, class Compare>
387 inline
388 Link * search_extreme(const Link & list, const Compare & cmp)
389 {
390 typename Link::Iterator it(const_cast<Link &>(list));
391 Link *extreme = it.get_curr();
392
393 for (it.next(); it.has_curr(); it.next_ne())
394 {
395 Link *curr = it.get_curr();
396 if (cmp(curr, extreme))
397 extreme = curr;
398 }
399
400 return extreme;
401 }
402
403 template <class Compare>
404 inline
405 Dlink * search_extreme(const Dlink & list, const Compare & cmp = Compare())
406 {
408 }
409
410 template <class Compare>
411 inline
412 Slinknc * search_extreme(const Slinknc & list, const Compare & cmp = Compare())
413 {
415 }
416
434 template <class Compare>
435 inline
436 void selection_sort(Dlink & list, Compare cmp)
437 {
438 Dlink aux;
439 while (not list.is_empty())
440 {
442 extreme->del(); // remove extreme from list
443 aux.append(extreme); // insert it ordered into aux
444 }
445
446 list.swap(&aux);
447 }
448
449 template <typename Tlink,
450 template <class> class Tnode,
451 typename T, class Compare>
453 {
454 Compare cmp;
455
456 public:
458 : cmp(cmp_fct)
459 { /* empty */
460 }
461
462 bool operator ()(Tlink *l1, Tlink *l2) const
463 noexcept(noexcept(std::declval<const Compare&>()(std::declval<const T&>(), std::declval<const T&>())))
464 {
465 auto *n1 = static_cast<Tnode<T> *>(l1);
466 auto *n2 = static_cast<Tnode<T> *>(l2);
467
468 assert(n1 == l1 and n2 == l2);
469
470 return cmp(n1->get_data(), n2->get_data());
471 }
472
473 // To generalize in sequential_search
474 bool operator ()(Tlink *l, const T & x) const
475 noexcept(noexcept(std::declval<const Compare&>()(std::declval<const T&>(), std::declval<const T&>())))
476 {
477 auto *n = static_cast<Tnode<T> *>(l);
478
479 assert(n == l);
480
481 return cmp(n->get_data(), x);
482 }
483 };
484
485 template <typename T, class Compare>
486 struct Compare_Dnode : public Compare_Tnode<Dlink, Dnode, T, Compare>
487 {
488 Compare_Dnode(const Compare & cmp = Compare())
490 : Compare_Tnode<Dlink, Dnode, T, Compare>(cmp)
491 { /* empty */
492 }
493 };
494
495 template <typename T, class Compare>
497
498
518 template <typename T, class Compare = Aleph::less<T>>
519 inline void selection_sort(Dnode<T> & list, Compare cmp)
520 {
523 }
524
546 template <typename T, class Equal = Aleph::equal_to<T>>
547 [[nodiscard]] inline
548 long sequential_search(T *a, const T & x, const long l, const long r,
549 Equal eq = Equal())
550 {
551 for (long i = l; i <= r; ++i)
552 if (eq(a[i], x)) return i;
553
554 return Not_Found;
555 }
556
590 template <typename T, class Equal = Aleph::equal_to<T>>
591 inline
592 long sequential_search(const DynArray<T> & a, const T & x,
593 const long l, const long r, Equal eq = Equal())
594 {
595 for (long i = l; i <= r; ++i)
596 if (a.exist(i))
597 if (eq(a(i), x))
598 return i;
599
600 return Not_Found;
601 }
602
603 template <class Link, typename T, class Equal>
604 Link * sequential_search(const Link & list, const T & x, Equal & eq)
605 {
606 for (typename Link::Iterator it(const_cast<Link &>(list));
607 it.has_curr(); it.next_ne())
608 if (Link *curr = it.get_curr(); eq(curr, x))
609 return curr;
610
611 return nullptr;
612 }
613
614 template <typename T, class Equal = Aleph::equal_to<T>>
615 Dlink * sequential_search(const Dlink & list, const T & x,
616 Equal eq = Equal())
617 {
620 }
621
622 template <typename T, class Equal = Aleph::equal_to<T>>
623 Slinknc * sequential_search(const Slinknc & list, const T & x,
624 Equal eq = Equal())
625 {
628 }
629
649 template <typename T, class Equal = Aleph::equal_to<T>>
650 inline
651 Dnode<T> * sequential_search(const Dnode<T> & list, const T & x,
652 Equal & eq)
653 {
655 const auto & base = static_cast<const Dlink &>(list);
657
658 return ret == nullptr ? nullptr : static_cast<Dnode<T> *>(ret);
659 }
660
661 template <typename T, class Equal = Aleph::equal_to<T>>
662 inline
663 Dnode<T> * sequential_search(const Dnode<T> & list, const T & x,
664 Equal && eq = Equal())
665 {
666 return sequential_search<T, Equal>(list, x, eq);
667 }
668
688 template <typename T, class Equal = Aleph::equal_to<T>>
689 inline
690 T * sequential_search(const DynDlist<T> & list, const T & x,
691 Equal eq = Equal())
692 {
694 (const_cast<Dnode<T> &>(static_cast<const Dnode<T> &>(list)), x, eq);
695 return ret != nullptr ? &ret->get_data() : nullptr;
696 }
697
698 template <typename T, class Equal = Aleph::equal_to<T>>
699 inline
700 T * sequential_search(const DynList<T> & list, const T & x,
701 Equal & eq)
702 {
703 for (typename DynList<T>::Iterator it(list); it.has_curr(); it.next_ne())
704 {
705 T & curr = it.get_curr_ne();
706 if (eq(curr, x))
707 return &curr;
708 }
709 return nullptr;
710 }
711
712 template <typename T, class Equal = Aleph::equal_to<T>>
713 inline
714 T * sequential_search(const DynList<T> & list, const T & x,
715 Equal eq = Equal())
716 {
717 for (typename DynList<T>::Iterator it(list); it.has_curr(); it.next_ne())
718 {
719 T & curr = it.get_curr_ne();
720 if (eq(curr, x))
721 return &curr;
722 }
723 return nullptr;
724 }
725
726
741 template <typename T, class Compare = Aleph::less<T>>
742 inline
743 long search_extreme(T *a, const long l, const long r, const Compare & cmp = Compare())
744 {
745 long extreme_index = l;
746 for (long i = l + 1; i <= r; ++i)
747 if (cmp(a[i], a[extreme_index])) // is there a new minimum?
748 extreme_index = i; // yes
749
750 return extreme_index;
751 }
752
757 template <typename T, class Compare = Aleph::less<T>>
758 inline
759 long search_min(T *a, const long l, const long r, const Compare & cmp = Compare())
760 {
761 return search_extreme<T, Compare>(a, l, r, cmp);
762 }
763
768 template <typename T, class Compare = Aleph::greater<T>>
769 inline
770 long search_max(T *a, const long l, const long r, const Compare & cmp = Compare())
771 {
772 return search_extreme<T, Compare>(a, l, r, cmp);
773 }
774
778 template <typename T, class Compare = Aleph::less<T>>
779 inline
780 Dnode<T> * search_extreme(const Dnode<T> & list, const Compare & cmp = Compare())
781 {
783 Dlink *ret =
785 (const_cast<Dlink &>(static_cast<const Dlink &>(list)), cmp_dnode);
786
787 return static_cast<Dnode<T> *>(ret);
788 }
789
803 template <typename T, class Compare = Aleph::less<T>>
804 inline
805 T * search_extreme(const DynDlist<T> & list, const Compare & cmp = Compare())
806 {
807 const auto & base = static_cast<const Dnode<T> &>(list);
808 Dnode<T> *ret = search_extreme<T, Compare>(const_cast<Dnode<T> &>(base), cmp);
809
810 return ret != nullptr ? &(ret->get_data()) : nullptr;
811 }
812
813 template <typename T, class Compare = Aleph::less<T>>
814 inline
815 T * search_extreme(const DynList<T> & list, const Compare & cmp = Compare())
816 {
817 if (list.is_empty())
818 return nullptr;
819
820 typename DynList<T>::Iterator it(list);
821 T *extreme = &it.get_curr_ne();
822 it.next_ne();
823 for (; it.has_curr(); it.next_ne())
824 {
825 T & curr = it.get_curr_ne();
826 if (cmp(curr, *extreme))
827 extreme = &curr;
828 }
829
830 return extreme;
831 }
832
837 template <typename T, class Compare = Aleph::less<T>>
838 inline
839 T * search_min(const DynDlist<T> & list, const Compare & cmp = Compare())
840 {
841 return search_extreme<T, Compare>(list, cmp);
842 }
843
848 template <typename T, class Compare = Aleph::greater<T>>
849 inline
850 T * search_max(const DynDlist<T> & list, const Compare & cmp = Compare())
851 {
852 return search_extreme<T, Compare>(list, cmp);
853 }
854
890 template <typename T, class Compare = Aleph::less<T>>
891 inline
892 void insertion_sort(T *a, const long l, const long r,
893 const Compare & cmp = Compare())
895 {
896 if (l >= r)
897 return;
898 for (long i = l, j; i <= r; ++i)
899 {
900 T tmp = a[i]; // store a[i], since it will be overwritten
901 for (j = i; j > l and cmp(tmp, a[j - 1]); --j)
902 a[j] = a[j - 1]; // shift to the right
903
904 a[j] = tmp; // insert tmp into the gap
905 }
906 }
907
921 template <class Compare>
922 inline
923 void insert_sorted(Dlink & list, Dlink *p, const Compare & cmp)
924 {
925 Dlink::Iterator it(list);
926 while (it.has_curr() and cmp(it.get_curr(), p))
927 it.next_ne();
928
929 if (it.has_curr())
930 it.get_curr()->append(p); // insert before current
931 else
932 list.append(p);
933 }
934
935 template <class Compare>
936 inline
937 void insert_sorted(HTList & list, Slinknc *p, const Compare & cmp)
938 {
939 // Handle empty list case
940 if (list.is_empty())
941 {
942 list.insert(p);
943 return;
944 }
945
946 if (Slinknc *first = list.get_first(); cmp(p, first) or not cmp(first, p)) // p <= first?
947 {
948 list.insert(p);
949 return;
950 }
951
952 if (Slinknc *last = list.get_last(); cmp(last, p) or not cmp(p, last)) // p >= last?
953 {
954 list.append(p);
955 return;
956 }
957
958 Slinknc *prev = list.get_first();
959 HTList::Iterator it(list);
960 for (it.next(); it.has_curr(); it.next_ne())
961 {
962 Slinknc *curr = it.get_curr();
963 if (cmp(p, curr)) // p < curr
964 {
965 prev->insert(p);
966 return;
967 }
968 prev = curr;
969 }
971 << "insert_sorted(): reached end of list traversal without inserting";
972 }
973
985 template <class ListType, class Compare>
986 inline
987 void list_insertion_sort(ListType & list, const Compare & cmp)
988 {
989 if (list.is_empty())
990 return;
991
992 ListType aux;
993 aux.append(list.remove_first());
994 while (not list.is_empty())
995 insert_sorted<Compare>(aux, list.remove_first(), cmp);
996
997 list.swap(aux);
998 }
999
1000 template <typename T, class Compare = Aleph::less<T>>
1001 inline
1002 void insertion_sort(DynList<T> & l, const Compare & cmp = Compare())
1003 {
1004 using Cmp = Compare_Snodenc<T, Compare>;
1005 Cmp c(cmp);
1007 }
1008
1009 template <typename T, class Compare = Aleph::less<T>>
1010 inline
1011 DynList<T> insertion_sort(DynList<T> && l, const Compare & cmp = Compare())
1012 {
1013 using Cmp = Compare_Snodenc<T, Compare>;
1014 Cmp c(cmp);
1016 return std::move(l);
1017 }
1018
1030 template <typename T, class Compare = Aleph::less<T>>
1031 inline void insertion_sort(Dnode<T> & list, const Compare & cmp = Compare())
1032 {
1033 using Cmp = Compare_Dnode<T, Compare>;
1034 Cmp c(cmp);
1036 }
1037
1066 template <typename T, class Compare = Aleph::less<T>>
1067 inline
1068 void merge(T *a, const long l, const long m, const long r,
1069 std::vector<T> & buf, const Compare & cmp = Compare())
1070 {
1071 const long s = r - l + 1;
1072
1073 // Resize buffer once instead of multiple push_back calls
1074 // This avoids repeated capacity checks and potential reallocations
1075 if (buf.size() < static_cast<size_t>(s))
1076 buf.resize(static_cast<size_t>(s));
1077
1078 // Copy left partition [l..m] to buffer start
1079 long buf_idx = 0;
1080 for (long i = l; i <= m; ++i)
1081 buf[buf_idx++] = std::move(a[i]);
1082
1083 // Copy right partition [m+1..r] in reverse to buffer end
1084 buf_idx = s - 1;
1085 for (long j = m + 1; j <= r; ++j)
1086 buf[buf_idx--] = std::move(a[j]);
1087
1088 // Merge from both ends toward middle
1089 long i = 0;
1090 long j = s - 1;
1091
1092 for (long k = l; k <= r; ++k)
1093 if (cmp(buf[i], buf[j]))
1094 a[k] = std::move(buf[i++]);
1095 else
1096 a[k] = std::move(buf[j--]);
1097 }
1098
1113 template <typename T, class Compare = Aleph::less<T>>
1114 inline
1115 void merge(T *a, const long l, const long m, const long r,
1116 const Compare & cmp = Compare())
1117 {
1118 std::vector<T> buf;
1119 buf.reserve(r - l + 1);
1120 merge(a, l, m, r, buf, cmp);
1121 }
1122
1123 template <typename T, class Compare>
1124 void mergesort(T *a, const long l, const long r, std::vector<T> & buf, Compare cmp)
1125 {
1126 if (l >= r)
1127 return;
1128
1129 const long m = l + (r - l) / 2;
1130
1131 mergesort<T, Compare>(a, l, m, buf, cmp);
1132 mergesort<T, Compare>(a, m + 1, r, buf, cmp);
1133
1134 if (not cmp(a[m + 1], a[m]))
1135 return;
1136
1137 merge<T, Compare>(a, l, m, r, buf, cmp);
1138 }
1139
1174 template <typename T, class Compare = Aleph::less<T>>
1175 inline
1176 void mergesort(T *a, const long l, const long r, const Compare & cmp = Compare())
1177 {
1178 if (l >= r)
1179 return;
1180
1181 std::vector<T> buf;
1182 buf.reserve(r - l + 1);
1183 mergesort(a, l, r, buf, cmp);
1184 }
1185
1211 template <typename Tlist, class Compare>
1212 inline
1213 void merge_lists(Tlist & l1, Tlist & l2, Tlist & result,
1214 const Compare & cmp = Compare())
1215 {
1216 assert(result.is_empty());
1217
1218 while (not l1.is_empty() and not l2.is_empty())
1219 if (cmp(l1.get_first_ne(), l2.get_first_ne()))
1220 result.append(l1.remove_first_ne());
1221 else
1222 result.append(l2.remove_first_ne());
1223
1224 if (l1.is_empty())
1225 result.concat_list(l2);
1226 else
1227 result.concat_list(l1);
1228
1229 assert(l1.is_empty() and l2.is_empty());
1230 }
1231
1248 template <typename T, class Compare = Aleph::less<T>>
1249 inline
1250 void merge_lists(Dnode<T> & l1, Dnode<T> & l2, Dnode<T> & result,
1251 const Compare & cmp = Compare())
1252 {
1254 }
1255
1286 template <typename Tlist, class Compare>
1287 inline
1288 void mergesort(Tlist & list, const Compare & cmp = Compare())
1289 {
1290 if (list.is_unitarian_or_empty())
1291 return;
1292
1293 Tlist l, r;
1294 list.split_list_ne(l, r); // split into two lists
1295
1298
1299 merge_lists<Tlist, Compare>(l, r, list, cmp); // merge them
1300 }
1301
1320 template <template <typename> class Tlist, typename T,
1321 class Compare = Aleph::less<T>>
1322 inline
1323 void mergeinsertsort(Tlist<T> & list, const Compare & cmp = Compare(),
1324 const size_t lsz = Aleph::Insertion_Threshold)
1325 {
1326 if (list.is_unitarian_or_empty())
1327 return;
1328
1329 if (list.size() <= lsz)
1330 {
1332 return;
1333 }
1334
1335 Tlist<T> l, r;
1336 list.split_list(l, r); // split into two lists
1337
1340
1341 merge_lists<Tlist<T>, Compare>(l, r, list, cmp); // merge them
1342 }
1343
1344 template <template <typename> class Tlist, typename T,
1345 class Compare = Aleph::less<T>>
1346 inline
1347 void mergesort(Tlist<T> & list, const Compare & cmp = Compare())
1348 {
1349 if (list.is_unitarian_or_empty())
1350 return;
1351
1352 Tlist<T> l, r;
1353 list.split_list(l, r); // split into two lists
1354
1357
1358 merge_lists<Tlist<T>, Compare>(l, r, list, cmp); // merge them
1359 }
1360
1381 template <typename T, class Compare = Aleph::less<T>>
1382 inline
1383 void mergesort(Dnode<T> & list, const Compare & cmp = Compare())
1384 {
1386 }
1387
1408 template <typename T, class Compare = Aleph::less<T>>
1409 inline
1410 void mergesort(DynDlist<T> & list, const Compare & cmp = Compare())
1411 {
1413 }
1414
1415 template <typename T, class Compare = Aleph::less<T>>
1416 inline
1417 void mergesort(DynList<T> & list, const Compare & cmp = Compare())
1418 {
1419 mergesort<DynList<T>, Compare>(list, cmp);
1420 }
1421
1422
1423 template <typename T, class Compare = Aleph::less<T>>
1424 inline
1425 DynList<T> mergesort(DynList<T> && list, const Compare & cmp = Compare())
1426 {
1427 mergesort<DynList<T>, Compare>(list, cmp);
1428 return std::move(list);
1429 }
1430
1431 template <typename T, class Compare = Aleph::less<T>>
1432 inline
1433 long select_pivot(T *a, long l, long r, const Compare & cmp = Compare())
1434 noexcept(noexcept(cmp(a[0], a[0])) && std::is_nothrow_swappable_v<T>);
1435
1436
1437 template <typename T, class Compare = Aleph::less<T>>
1438 inline
1439 long partition(T *a, const long l, const long r, const Compare & cmp = Compare())
1440 noexcept(noexcept(cmp(a[0], a[0])) && std::is_nothrow_swappable_v<T>)
1441 {
1442 const long p = select_pivot<T, Compare>(a, l, r, cmp);
1443 std::swap(a[p], a[r]);
1444
1445 // Note: pivot stays at a[r] throughout the loop - no copy needed
1446 // This saves a potentially expensive copy for large T types
1447 long i = l - 1; // index first element to the left > pivot
1448 long j = r; // index first element to the right < pivot
1449 while (true)
1450 {
1451 // advance while a[i] < pivot (pivot is at a[r])
1452 while (cmp(a[++i], a[r])) {}
1453
1454 while (cmp(a[r], a[--j])) // advance while pivot < a[j]
1455 if (j == l) // Has the left edge been reached?
1456 break; // yes ==> the iteration must be finished
1457
1458 if (i >= j)
1459 break;
1460
1461 // At this point there is an inversion a[i] > pivot > a[j]
1462 std::swap(a[i], a[j]); // Eliminate inversion
1463 }
1464
1465 std::swap(a[i], a[r]); // Place pivot in its final position
1466
1467 return i;
1468 }
1469
1504 template <typename T, class Compare = Aleph::less<T>>
1505 inline
1506 void quicksort_rec(T *a, const long l, const long r, const Compare & cmp = Compare())
1507 {
1508 if (l >= r)
1509 return;
1510
1511 const long pivot = partition<T, Compare>(a, l, r, cmp);
1512
1515 }
1516
1517 template <typename T, class Compare = Aleph::less<T>>
1518 inline
1519 void quicksort_no_tail(T *a, long l, long r, const Compare & cmp = Compare())
1520 {
1521 while (l < r)
1522 {
1523 const long pivot = partition<T, Compare>(a, l, r, cmp);
1524 const long left_size = pivot - l;
1525 const long right_size = r - pivot;
1526
1527 // Recurse on the smaller partition to ensure O(log n) stack depth.
1528 if (left_size < right_size)
1529 {
1531 l = pivot + 1; // tail recurse on the right by looping
1532 }
1533 else
1534 {
1536 r = pivot - 1; // tail recurse on the left by looping
1537 }
1538 }
1539 }
1540
1557 template <typename T, class Compare = Aleph::less<T>>
1558 inline
1559 void quicksort_rec_min(T *a, const long l, const long r,
1560 const Compare & cmp = Compare())
1561 {
1562 if (r <= l)
1563 return;
1564
1565 if (const long pivot = partition<T, Compare>(a, l, r, cmp); pivot - l < r - pivot)
1566 // which partition is smaller?
1567 { // left partition is smaller
1570 }
1571 else
1572 { // right partition is smaller
1575 }
1576 }
1577
1578 template <typename T, class Compare>
1579 inline
1580 long select_pivot(T *a, const long l, const long r, const Compare & cmp)
1581 noexcept(noexcept(cmp(a[0], a[0])) && std::is_nothrow_swappable_v<T>)
1582 {
1583 const long m = l + (r - l) / 2;
1584
1585 if (cmp(a[r], a[l]))
1586 std::swap(a[l], a[r]);
1587 if (cmp(a[m], a[l]))
1588 std::swap(a[m], a[l]);
1589 if (cmp(a[r], a[m]))
1590 std::swap(a[r], a[m]);
1591
1592 return m;
1593 }
1594
1632 template <typename T, class Compare = Aleph::less<T>>
1633 inline
1634 void quicksort(T *a, const long l, const long r, const Compare & cmp = Compare())
1635 {
1636 if (r - l < Quicksort_Threshold)
1637 {
1638 insertion_sort(a, l, r, cmp);
1639 return;
1640 }
1641
1642 typedef std::pair<long, long> Partition;
1643 FixedStack<Partition> stack(64);
1644 stack.push(Partition(l, r));
1645
1646 while (stack.size() > 0)
1647 {
1648 const Partition p = stack.pop();
1649 const long diff = p.second - p.first;
1650
1651 if (diff <= 1)
1652 continue;
1653
1655 {
1656 insertion_sort(a, p.first, p.second, cmp);
1657 continue;
1658 }
1659
1660 if (const long pivot = partition<T, Compare>(a, p.first, p.second, cmp); pivot - p.first < p.second - pivot)
1661 // which one is smaller?
1662 { // left partition is smaller
1663 stack.push(Partition(pivot + 1, p.second));
1664 stack.push(Partition(p.first, pivot - 1));
1665 }
1666 else
1667 { // right partition is smaller
1668 stack.push(Partition(p.first, pivot - 1));
1669 stack.push(Partition(pivot + 1, p.second));
1670 }
1671 }
1672 }
1673
1682 inline size_t introsort_depth_limit(size_t n) noexcept
1683 {
1684 size_t depth = 0;
1685 while (n > 1)
1686 {
1687 n >>= 1;
1688 ++depth;
1689 }
1690 return depth * 2;
1691 }
1692
1697 template <typename T, class Compare>
1698 void introsort_loop(T *a, long l, long r, size_t depth_limit,
1699 const Compare & cmp)
1700 {
1701 while (r - l >= static_cast<long>(Quicksort_Threshold))
1702 {
1703 if (depth_limit == 0) [[unlikely]]
1704 {
1705 // Depth limit reached: switch to heapsort for guaranteed O(n log n)
1706 faster_heapsort(a + l, static_cast<size_t>(r - l + 1), cmp);
1707 return;
1708 }
1709
1710 --depth_limit;
1711
1712 // Median-of-three pivot selection
1713 // Recurse on smaller partition, iterate on larger (tail call elimination)
1714 if (const long pivot = partition<T, Compare>(a, l, r, cmp); pivot - l < r - pivot)
1715 {
1717 l = pivot + 1;
1718 }
1719 else
1720 {
1722 r = pivot - 1;
1723 }
1724 }
1725 }
1726
1774 template <typename T, class Compare = Aleph::less<T>>
1775 inline
1776 void introsort(T *a, const long l, const long r, const Compare & cmp = Compare())
1777 {
1778 if (r <= l)
1779 return;
1780
1781 const auto n = static_cast<size_t>(r - l + 1);
1782
1783 if (n < Quicksort_Threshold)
1784 {
1785 insertion_sort(a, l, r, cmp);
1786 return;
1787 }
1788
1789 // Main introsort loop with depth limit
1791
1792 // Final insertion sort pass for small unsorted subarrays
1793 insertion_sort(a, l, r, cmp);
1794 }
1795
1807 template <typename T, class Compare = Aleph::less<T>>
1808 inline
1809 void introsort(T *a, const size_t n, const Compare & cmp = Compare())
1810 {
1811 if (n <= 1)
1812 return;
1813 introsort(a, 0L, static_cast<long>(n - 1), cmp);
1814 }
1815
1843 template <typename T, class Compare = Aleph::less<T>>
1844 inline
1845 void introsort(T *begin, T *end, const Compare & cmp = Compare())
1846 {
1847 if (begin >= end)
1848 return;
1849 const auto n = static_cast<size_t>(end - begin);
1850 introsort(begin, n, cmp);
1851 }
1852
1877 template <typename T, class Compare = Aleph::less<T>>
1878 inline
1879 void introsort(Array<T> & arr, const Compare & cmp = Compare())
1880 {
1881 const size_t n = arr.size();
1882 if (n <= 1)
1883 return;
1884 // Array uses contiguous memory via MemArray, so we can use pointer arithmetic
1885 introsort(&arr(0), n, cmp);
1886 }
1887
1901 template <class Compare>
1902 void quicksort(Dlink & list, const Compare & cmp = Compare())
1903 {
1904 if (list.is_unitarian_or_empty())
1905 return;
1906
1907 Dlink *pivot = list.remove_next();
1908 Dlink smaller, bigger; // lists of smaller and larger than pivot
1909
1910 while (not list.is_empty())
1911 {
1912 if (Dlink *p = list.remove_next(); cmp(p, pivot))
1913 smaller.append(p);
1914 else
1915 bigger.append(p);
1916 }
1917
1919 quicksort<Compare>(smaller, cmp);
1920
1921 list.concat_list(&smaller); // restore sorted lists into list
1922 list.append(pivot);
1923 list.concat_list(&bigger);
1924 }
1925
1947 template <typename T, class Compare = Aleph::less<T>>
1948 void quicksort(Dnode<T> & list, const Compare & cmp = Compare())
1949 {
1951 }
1952
1953 template <typename T, class Compare>
1954 void quicksort(HTList & list, const Compare & cmp = Compare())
1955 {
1956 if (list.is_unitarian_or_empty())
1957 return;
1958
1959 auto *pivot = static_cast<Snodenc<T> *>(list.remove_first_ne());
1960 HTList smaller, bigger; // lists of smaller and larger than pivot
1961
1962 while (not list.is_empty())
1963 if (auto *p = static_cast<Snodenc<T> *>(list.remove_first_ne()); cmp(p->get_data(), pivot->get_data()))
1964 smaller.append(p);
1965 else
1966 bigger.append(p);
1967
1969 quicksort<T, Compare>(smaller, cmp);
1970
1971 list.concat_list(smaller); // restore sorted lists into list
1972 list.append(pivot);
1973 list.concat_list(bigger);
1974 }
1975
1976 template <typename T, class Compare = Aleph::less<T>>
1977 void quicksort(DynList<T> & list, const Compare & cmp = Compare())
1978 {
1979 quicksort<T, Compare>(static_cast<HTList &>(list), cmp);
1980 }
1981
2020 template <typename T, class Compare = Aleph::less<T>>
2021 inline
2022 void quicksort_insertion(T *a, const long l, const long r,
2023 const Compare & cmp = Compare())
2024 {
2025 if (r <= l)
2026 return;
2027
2028 const long pivot = partition<T, Compare>(a, l, r, cmp);
2029
2030 const long l_size = pivot - l; // left partition size
2031 const long r_size = r - pivot; // right partition size
2032 bool left_done = false; // true if left partition is sorted
2033 bool right_done = false; // true if der partition is sorted
2034
2036 { // sort left partition by insertion
2038 left_done = true;
2039 }
2040
2042 { // sort der partition by insertion
2044 right_done = true;
2045 }
2046
2048 return; //both partitions sorted by insertion
2049
2050 if (left_done) // left partition sorted by insertion?
2051 { // Yeah; It only remains to recursively sort the right partition
2053 return;
2054 }
2055
2056 if (right_done) // der partition sorted by insertion?
2057 { // Yeah; It only remains to recursively sort the left partition
2059 return;
2060 }
2061
2062 // here, both partitions were not insertion sorted
2063 if (l_size < r_size) // sort smallest partition first
2064 { //smaller left partition
2067 }
2068 else
2069 { // smaller right partition
2072 }
2073 }
2074
2108 template <typename T, class Compare = Aleph::less<T>>
2109 inline
2110 long random_search(T *a, const T & x, const long l, const long r,
2111 const Compare & cmp = Compare())
2112 {
2113 if (l > r)
2114 return Not_Found;
2115
2116 const long pivot = partition<T, Compare>(a, l, r, cmp);
2117
2118 if (cmp(x, a[pivot]))
2119 return random_search<T, Compare>(a, x, l, pivot - 1, cmp);
2120 if (cmp(a[pivot], x))
2121 return random_search<T, Compare>(a, x, pivot + 1, r, cmp);
2122
2123 return pivot; // element found at index x
2124 }
2125
2126 template <typename T, class Compare = Aleph::less<T>>
2127 inline
2128 long random_search(DynArray<T> & a, const T & x, const long l, const long r,
2129 const Compare & cmp = Compare())
2130 {
2131 if (l > r)
2132 return Not_Found;
2133
2134 const long pivot = partition(a, l, r, cmp);
2135
2136 if (cmp(x, a(pivot)))
2137 return random_search<T, Compare>(a, x, l, pivot - 1, cmp);
2138 if (cmp(a(pivot), x))
2139 return random_search<T, Compare>(a, x, pivot + 1, r, cmp);
2140
2141 return pivot; // element found at index x
2142 }
2143
2170 template <typename T, class Compare>
2171 inline
2173 const Compare & cmp = Compare())
2174 {
2175 if (list.is_empty())
2176 return nullptr;
2177
2178 Dnode<T> item(x);
2179 Dnode<T> *item_ptr = &item; // pointer to the cell containing x
2180
2181 Dlink smaller; // list of those smaller than pivot
2182 Dlink bigger; // list of those greater than pivot
2183
2184 auto *pivot = static_cast<Dnode<T> *>(list.remove_next());
2185
2186 while (not list.is_empty())
2187 if (Dlink *p = list.remove_next(); cmp(p, pivot))
2188 smaller.append(p);
2189 else
2190 bigger.append(p);
2191
2192 Dnode<T> *ret_val = nullptr;
2193 if (cmp(item_ptr, pivot))
2195 else if (cmp(pivot, item_ptr))
2197 else
2198 ret_val = pivot;
2199
2200 assert(list.is_empty());
2201
2202 list.swap(&smaller);
2203 list.append(pivot);
2204 list.concat_list(&bigger);
2205
2206 return ret_val;
2207 }
2208
2238 template <typename T, class Compare = Aleph::less<T>>
2239 Dnode<T> * random_search(Dlink & list, const T & x, const Compare & cmp = Compare())
2240 {
2242 }
2243
2273 template <typename T, class Compare = Aleph::less<T>>
2274 inline
2275 T * random_search(DynDlist<T> & list, const T & x, const Compare & cmp = Compare())
2276 {
2278
2279 return p == nullptr ? nullptr : &(p->get_data());
2280 }
2281
2282 template <typename T, class Compare>
2283 static inline
2284 const T &__random_select(T *a, const long i, const long l, const long r,
2285 const Compare & cmp)
2286 {
2287 if (l >= r)
2288 return a[l];
2289
2290 const long pivot = partition<T, Compare>(a, l, r, cmp);
2291 if (i == pivot)
2292 return a[i];
2293
2294 if (i < pivot) // Is it in left partition?
2295 return __random_select<T, Compare>(a, i, l, pivot - 1, cmp);
2296 return __random_select<T, Compare>(a, i, pivot + 1, r, cmp);
2297 }
2298
2299 template <typename T, class Compare, typename Container>
2300 inline
2301 long select_pivot_op_impl(const Container & a, const long l, const long r,
2302 const Compare & cmp)
2303 {
2304 assert(l <= r);
2305
2306 if (r - l <= 5)
2307 return r;
2308
2309 const long m = l + (r - l) / 2; // central element
2310
2311 // Access array entries only once
2312 const T & la = a(l);
2313 const T & ra = a(r);
2314 const T & ma = a(m);
2315
2317
2318 if (med_ptr == &la)
2319 return l;
2320
2321 if (med_ptr == &ma)
2322 return m;
2323
2324 assert(med_ptr == &ra);
2325
2326 return r;
2327 }
2328
2334 template <typename T, class Compare = Aleph::less<T>>
2335 inline
2336 long select_pivot_op(const DynArray<T> & a, const long l, const long r,
2337 const Compare & cmp = Compare())
2338 {
2339 return select_pivot_op_impl<T, Compare>(a, l, r, cmp);
2340 }
2341
2347 template <typename T, class Compare = Aleph::less<T>>
2348 inline
2349 long select_pivot_op(const Array<T> & a, const long l, const long r,
2350 const Compare & cmp = Compare())
2351 {
2352 return select_pivot_op_impl<T, Compare>(a, l, r, cmp);
2353 }
2354
2355 template <typename T, class Compare, typename Container>
2356 inline
2357 long partition_op_impl(Container & a, const long l, const long r,
2358 const Compare & cmp)
2359 {
2360 if (l == r)
2361 return l;
2362
2363 long i = l - 1;
2364 long j = r;
2365
2366 // Move selected pivot to position r
2367 if (const long pivot_idx = select_pivot_op<T, Compare>(a, l, r, cmp); pivot_idx != r)
2368 std::swap(a(pivot_idx), a(r));
2369
2370 // Now pivot value is at a(r) - use direct access instead of reference
2371 while (true)
2372 {
2373 while (cmp(a(++i), a(r))) {}
2374
2375 while (cmp(a(r), a(--j)))
2376 if (j == l)
2377 break;
2378
2379 if (i >= j)
2380 break;
2381
2382 std::swap(a(i), a(j));
2383 }
2384
2385 std::swap(a(i), a(r));
2386
2387 return i;
2388 }
2389
2390 template <typename T, class Compare = Aleph::less<T>>
2391 inline
2392 long partition_op(DynArray<T> & a, const long l, const long r,
2393 const Compare & cmp = Compare())
2394 {
2395 return partition_op_impl<T, Compare>(a, l, r, cmp);
2396 }
2397
2398 template <typename T, class Compare = Aleph::less<T>>
2399 inline
2400 long partition_op(Array<T> & a, const long l, const long r,
2401 const Compare & cmp = Compare())
2402 {
2403 return partition_op_impl<T, Compare>(a, l, r, cmp);
2404 }
2405
2406 template <typename T, class Compare>
2407 static inline
2408 const T &__random_select(DynArray<T> & a, const long i,
2409 const long l, const long r,
2410 const Compare & cmp = Compare())
2411 {
2412 assert(i >= l and i <= r);
2413
2414 if (l >= r)
2415 return a(l);
2416
2417 const long pivot = partition_op<T, Compare>(a, l, r, cmp);
2418 if (i == pivot)
2419 return a(i);
2420
2421 if (i < pivot) // is it in left partition?
2422 return __random_select<T, Compare>(a, i, l, pivot - 1, cmp);
2423 return __random_select<T, Compare>(a, i, pivot + 1, r, cmp);
2424 }
2425
2426 template <typename T, class Compare>
2427 static inline
2428 const T &__random_select(Array<T> & a, const long i,
2429 const long l, const long r,
2430 const Compare & cmp = Compare())
2431 {
2432 assert(i >= l and i <= r);
2433
2434 if (l >= r)
2435 return a(l);
2436
2437 const long pivot = partition_op<T, Compare>(a, l, r, cmp);
2438 if (i == pivot)
2439 return a(i);
2440
2441 if (i < pivot) // Is it in left partition?
2442 return __random_select<T, Compare>(a, i, l, pivot - 1, cmp);
2443 return __random_select<T, Compare>(a, i, pivot + 1, r, cmp);
2444 }
2445
2446 template <typename T, class Compare = Aleph::less<T>>
2447 const T &random_select(DynArray<T> & a, const long i, const Compare & cmp = Compare())
2448 {
2449 const auto n_sz = a.size();
2450 ah_out_of_range_error_if(n_sz == 0 or i < 0) << "index out of range";
2451
2452 const long n = static_cast<long>(n_sz) - 1;
2453 ah_out_of_range_error_if(i > n) << "index out of range";
2454
2455 return __random_select<T, Compare>(a, i, 0, n, cmp);
2456 }
2457
2458 template <typename T, class Compare = Aleph::less<T>>
2459 const T &random_select(Array<T> & a, const long i, const Compare & cmp = Compare())
2460 {
2461 const auto n_sz = a.size();
2462 ah_out_of_range_error_if(n_sz == 0 or i < 0) << "index out of range";
2463
2464 const long n = static_cast<long>(n_sz) - 1;
2465 ah_out_of_range_error_if(i > n) << "index out of range";
2466
2467 return __random_select<T, Compare>(a, i, 0, n, cmp);
2468 }
2469
2510 template <typename T, class Compare = Aleph::less<T>>
2511 const T &random_select(T *a, const long i, const long n,
2512 const Compare & cmp = Compare())
2513 {
2514 ah_out_of_range_error_if(i >= n) << "index out of range";
2515
2516 return __random_select<T, Compare>(a, i, 0, n - 1, cmp);
2517 }
2518
2519 template <typename T, class Compare = Aleph::less<T>>
2520 const T &random_select(T *a, const long i, const long n,
2521 Compare && cmp = Compare())
2522 {
2523 return random_select<T, Compare>(a, i, n, cmp);
2524 }
2525
2548 template <class Compare>
2549 Dlink * dlink_random_select(Dlink & list, const size_t i,
2550 const Compare & cmp = Compare())
2551 {
2552 if (list.is_empty())
2553 return nullptr;
2554
2555 Dlink smaller; // list of minors than pivot
2556 Dlink bigger; // list of majors than pivot
2557
2558 size_t smaller_count = 0, // number of elements in smaller
2559 bigger_count = 0; // number of elements in bigger
2560
2561 Dlink *pivot = list.remove_next();
2562
2563 while (not list.is_empty())
2564 if (Dlink *p = list.remove_next(); cmp(p, pivot)) // p < pivot?
2565 {
2566 smaller.append(p);
2567 ++smaller_count;
2568 }
2569 else
2570 {
2571 bigger.append(p);
2572 ++bigger_count;
2573 }
2574
2575 if (i >= smaller_count + bigger_count + 1)
2576 {
2577 list.concat_list(&smaller);
2578 list.append(pivot);
2579 list.concat_list(&bigger);
2580 ah_out_of_range_error() << "index of selection greater than list's size";
2581 }
2582
2583 Dlink *ret_val = nullptr;
2584 if (i == smaller_count)
2585 ret_val = pivot;
2586 else if (i < smaller_count)
2588 else
2590
2591 list.concat_list(&smaller);
2592 list.append(pivot);
2593 list.concat_list(&bigger);
2594
2595 return ret_val;
2596 }
2597
2623 template <typename T, class Compare = Aleph::less<T>>
2624 Dnode<T> * random_select(Dlink & list, const size_t i, const Compare & cmp = Compare())
2625 {
2626 return static_cast<Dnode<T> *>(dlink_random_select<Compare_Dnode<T, Compare>>(list, i, cmp));
2627 }
2628
2654 template <typename T, class Compare = Aleph::less<T>>
2655 T * random_select(DynDlist<T> & list, const size_t i, const Compare & cmp = Compare())
2656 {
2658
2659 auto *p = static_cast<Dnode<T> *>(link);
2660
2661 return p != nullptr ? &(p->get_data()) : nullptr;
2662 }
2663
2683 template <typename T, class Compare = Aleph::less<T>>
2684 inline
2685 void selection_sort(DynArray<T> & a, const Compare & cmp = Compare())
2686 {
2687 const long n = static_cast<long>(a.size());
2688 if (n < 2)
2689 return;
2690
2691 for (long i = 0; i < n - 1; ++i)
2692 {
2693 long min = i;
2694
2695 for (long j = i + 1; j < n; ++j)
2696 if (cmp(a(j), a(min)))
2697 min = j;
2698
2699 if (cmp(a(min), a(i)))
2700 std::swap(a(min), a(i));
2701 }
2702 }
2703
2734 template <typename T, class Compare = Aleph::less<T>>
2735 inline
2736 void bubble_sort(DynArray<T> & a, const Compare & cmp = Compare())
2737 {
2738 const long n = static_cast<long>(a.size());
2739 if (n < 2)
2740 return;
2741
2742 for (long i = 0; i < n - 1; ++i)
2743 for (long j = n - 1; j > i; --j)
2744 if (cmp(a(j), a(j - 1)))
2745 std::swap(a(j - 1), a(j));
2746 }
2747
2774 template <template <typename> class C, typename T,
2775 class Compare = Aleph::less<T>>
2776 inline
2777 void insertion_sort(C<T> & a, const long l, const long r, const Compare & cmp = Compare())
2778 {
2779 for (long i = l + 1; i <= r; i++)
2780 {
2781 T tmp = a(i);
2782 long j = i;
2783 for (/* nothing */; j > l and cmp(tmp, a(j - 1)); --j)
2784 a(j) = a(j - 1);
2785
2786 a(j) = tmp;
2787 }
2788 }
2789
2794 template <template <typename> class C, typename T,
2795 class Compare = Aleph::less<T>>
2796 inline
2797 void insertion_sort(C<T> & a, const Compare & cmp = Compare())
2798 {
2799 const auto n = a.size();
2800 if (n <= 1)
2801 return;
2802 insertion_sort(a, 0, static_cast<long>(n) - 1, cmp);
2803 }
2804
2839 template <typename T, class Compare = Aleph::less<T>>
2840 inline
2841 void shellsort(DynArray<T> & a, const Compare & cmp = Compare())
2842 {
2843 const long n = a.size();
2844 if (n <= 1)
2845 return;
2846
2847 // Ciura's gap sequence - empirically optimal for most data distributions
2848 // Extended with ~2.25x multiplier for larger arrays
2849 static constexpr long ciura_gaps[] =
2850 {
2851 1, 4, 10, 23, 57, 132, 301, 701, 1750, 4024, 9233,
2852 21223, 48805, 112217, 258100, 593630, 1365513, 3140680
2853 };
2854 static constexpr int num_gaps = sizeof(ciura_gaps) / sizeof(ciura_gaps[0]);
2855
2856 // Find first gap smaller than array size
2857 int gap_idx = num_gaps - 1;
2858 while (gap_idx >= 0 && ciura_gaps[gap_idx] >= n)
2859 --gap_idx;
2860
2861 // Sort with decreasing gaps
2862 for (; gap_idx >= 0; --gap_idx)
2863 {
2864 const long h = ciura_gaps[gap_idx];
2865 for (long i = h; i < n; i++)
2866 {
2867 T tmp = std::move(a(i));
2868 long j = i;
2869
2870 while (j >= h and cmp(tmp, a(j - h)))
2871 {
2872 a(j) = std::move(a(j - h));
2873 j -= h;
2874 }
2875
2876 a(j) = std::move(tmp);
2877 }
2878 }
2879 }
2880
2881
2882 inline static long back_index(const long i) noexcept { return i - 1; }
2883
2884
2885 template <typename T, class Compare>
2886 inline
2887 void sift_up(DynArray<T> & table, const long n, const Compare & cmp)
2888 {
2889 long p;
2890 for (long i = n; i > 1; i = p)
2891 {
2892 p = i >> 1; // c = i/2
2893
2894 if (cmp(table(back_index(p)), table(back_index(i))))
2895 return;
2896
2897 std::swap(table(back_index(p)), table(back_index(i)));
2898 }
2899 }
2900
2901 template <typename T, class Compare>
2902 inline
2903 void sift_down(DynArray<T> & table, const long start, const long n, const Compare & cmp)
2904 {
2905 long i = start;
2906
2907 while (true)
2908 {
2909 long c = i << 1; // c = 2*i (left child)
2910
2911 if (c > n)
2912 return;
2913
2914 // Select the smaller/larger child depending on comparator
2915 if (c + 1 <= n)
2916 if (cmp(table(back_index(c + 1)), table(back_index(c))))
2917 c++;
2918
2919 if (cmp(table(back_index(i)), table(back_index(c))))
2920 return;
2921
2922 std::swap(table(back_index(c)), table(back_index(i)));
2923 i = c;
2924 }
2925 }
2926
2927 // Legacy overload for backward compatibility
2928 template <typename T, class Compare>
2929 inline
2930 void sift_down(DynArray<T> & table, const long n, const Compare & cmp)
2931 {
2932 sift_down<T, Compare>(table, 1, n, cmp);
2933 }
2934
2947 template <typename T, class Compare>
2949 {
2950 Compare cmp;
2951
2952 public:
2954 Negate_Compare(Compare __cmp = Compare())
2956 : cmp(__cmp)
2957 { /* Empty */
2958 }
2959
2961 bool operator ()(const T & e1, const T & e2) const
2962 noexcept(noexcept(std::declval<const Compare &>()(e2, e1)))
2963 {
2964 return cmp(e2, e1);
2965 }
2966 };
2967
3008 template <typename T, class Compare = Aleph::less<T>>
3009 inline
3010 void heapsort(DynArray<T> & a, const Compare & cmp = Compare())
3011 {
3012 const long n = a.size();
3013 if (n <= 1)
3014 return;
3015
3017
3018 // Floyd's heap construction: O(n) instead of O(n log n)
3019 // Start from last non-leaf node and sift down each node
3020 for (long i = n / 2; i >= 1; --i)
3022
3023 // Extract elements from heap one by one
3024 for (long i = n; i >= 2; --i)
3025 {
3026 std::swap(a(0), a(i - 1));
3028 }
3029 }
3030
3031 template <template <typename> class C, typename T,
3032 class Compare = Aleph::less<T>>
3033 inline
3034 long partition(C<T> & a, const long l, const long r, const Compare & cmp = Compare())
3035 {
3036 if (l == r)
3037 return l;
3038
3039 long i = l - 1;
3040 long j = r;
3041 const T & pivot = a(r);
3042
3043 while (true)
3044 {
3045 while (cmp(a(++i), pivot)) { /* Nothing else */ }
3046
3047 while (cmp(pivot, a(--j)))
3048 if (j == l)
3049 break;
3050
3051 if (i >= j)
3052 break;
3053
3054 std::swap(a(i), a(j));
3055 }
3056
3057 std::swap(a(i), a(r));
3058
3059 return i;
3060 }
3061
3062 template <typename T, class Compare = Aleph::less<T>>
3063 inline
3064 void quicksort_rec(DynArray<T> & a, const long l, const long r,
3065 const Compare & cmp = Compare())
3066 {
3067 if (r <= l)
3068 return;
3069
3070 if (const long i = partition(a, l, r, cmp); i - l < r - i)
3071 {
3072 quicksort_rec<T, Compare>(a, l, i - 1, cmp);
3073 quicksort_rec<T, Compare>(a, i + 1, r, cmp);
3074 }
3075 else
3076 {
3077 quicksort_rec<T, Compare>(a, i + 1, r, cmp);
3078 quicksort_rec<T, Compare>(a, l, i - 1, cmp);
3079 }
3080 }
3081
3082 template <class Stack, class A, class B>
3083 inline
3084 void push2(Stack & stack, const A & a, const B & b)
3085 {
3086 stack.push(b);
3087 stack.push(a);
3088 }
3089
3118 template <typename T, class Compare = Aleph::less<T>>
3119 inline
3120 void quicksort(DynArray<T> & a, const Compare & cmp = Compare())
3121 {
3122 long l = 0, r = a.size() - 1;
3123
3124 FixedStack<long> stack(64);
3125
3126 push2(stack, l, r);
3127
3128 while (not stack.is_empty())
3129 {
3130 l = stack.pop();
3131 r = stack.pop();
3132
3133 if (r <= l)
3134 continue;
3135
3136 if (const long i = partition(a, l, r, cmp); i - l > r - i)
3137 {
3138 push2(stack, l, i - 1);
3139 push2(stack, i + 1, r);
3140 }
3141 else
3142 {
3143 push2(stack, i + 1, r);
3144 push2(stack, l, i - 1);
3145 }
3146 }
3147 }
3148
3158 template <typename T, class Compare>
3159 inline
3160 void sift_down_subrange(DynArray<T> & a, long start, const long n,
3161 const long offset, const Compare & cmp)
3162 {
3163 while (true)
3164 {
3165 long c = start << 1; // c = 2*start (left child)
3166 if (c > n)
3167 return;
3168
3169 // Select the child with higher priority
3170 if (c + 1 <= n)
3171 if (cmp(a(offset + c), a(offset + c - 1)))
3172 c++;
3173
3174 if (cmp(a(offset + start - 1), a(offset + c - 1)))
3175 return;
3176
3177 std::swap(a(offset + start - 1), a(offset + c - 1));
3178 start = c;
3179 }
3180 }
3181
3186 template <typename T, class Compare>
3187 inline
3188 void heapsort_subrange(DynArray<T> & a, const long l, const long r,
3189 const Compare & cmp)
3190 {
3191 const long n = r - l + 1;
3192 if (n <= 1)
3193 return;
3194
3196
3197 // Floyd's heap construction: O(n)
3198 for (long i = n / 2; i >= 1; --i)
3200
3201 // Extract elements
3202 for (long i = n; i >= 2; --i)
3203 {
3204 std::swap(a(l), a(l + i - 1));
3206 }
3207 }
3208
3213 template <typename T, class Compare>
3214 void introsort_loop(DynArray<T> & a, long l, long r, size_t depth_limit,
3215 const Compare & cmp)
3216 {
3217 while (r - l >= static_cast<long>(Quicksort_Threshold))
3218 {
3219 if (depth_limit == 0) [[unlikely]]
3220 {
3221 // Depth limit reached: switch to heapsort for guaranteed O(n log n)
3223 return;
3224 }
3225
3226 --depth_limit;
3227
3228 // Partition and continue
3229 const long pivot = partition(a, l, r, cmp);
3230
3231 // Recurse on smaller partition, iterate on larger (tail call elimination)
3232 if (pivot - l < r - pivot)
3233 {
3235 l = pivot + 1;
3236 }
3237 else
3238 {
3240 r = pivot - 1;
3241 }
3242 }
3243 }
3244
3275 template <typename T, class Compare = Aleph::less<T>>
3276 inline
3277 void introsort(DynArray<T> & a, const Compare & cmp = Compare())
3278 {
3279 const long n = a.size();
3280 if (n <= 1)
3281 return;
3282
3283 if (n < static_cast<long>(Quicksort_Threshold))
3284 {
3285 insertion_sort(a, 0, n - 1, cmp);
3286 return;
3287 }
3288
3289 // Main introsort loop with depth limit
3291
3292 // Final insertion sort pass for small unsorted subarrays
3293 insertion_sort(a, 0, n - 1, cmp);
3294 }
3295
3310 template <typename T, class Compare = Aleph::less<T>>
3311 inline
3312 long search_extreme(const DynArray<T> & a, const long l, const long r,
3313 const Compare & cmp = Compare())
3314 {
3315 long extreme_index = l;
3316
3317 for (long i = l + 1; i <= r; i++)
3318 if (cmp(a(i), a(extreme_index)))
3319 extreme_index = i;
3320
3321 return extreme_index;
3322 }
3323
3328 template <typename T, class Compare = Aleph::greater<T>>
3329 inline
3330 long search_max(const DynArray<T> & a, const long l, const long r,
3331 const Compare & cmp = Compare())
3332 {
3333 return search_extreme<T, Compare>(a, l, r, cmp);
3334 }
3335
3381 template <template <typename> class C, typename T,
3382 class Compare = Aleph::less<T>>
3383 inline
3384 long binary_search(const C<T> & a, const T & x, long l, long r,
3385 const Compare & cmp = Compare())
3386 {
3387 if (l > r)
3388 return l;
3389
3390 while (l <= r)
3391 if (long m = l + (r - l) / 2; cmp(x, a(m)))
3392 r = m - 1;
3393 else if (cmp(a(m), x))
3394 l = m + 1;
3395 else
3396 return m; // key found
3397
3398 return l;
3399 }
3400
3401 template <template <typename> class C, typename T,
3402 class Compare = Aleph::less<T>>
3403 inline
3404 long binary_search(const C<T *> & a, const T & x, long l, long r,
3405 const Compare & cmp = Compare())
3406 {
3407 if (l > r)
3408 return l;
3409
3410 while (l <= r)
3411 if (long m = l + (r - l) / 2; cmp(x, *a(m)))
3412 r = m - 1;
3413 else if (cmp(*a(m), x))
3414 l = m + 1;
3415 else
3416 return m; // found key
3417
3418 return l;
3419 }
3420
3421 template <template <typename> class C, typename T,
3422 class Compare = Aleph::less<T>>
3423 inline
3424 long binary_search(const C<T *> & a, const T & x, Compare && cmp = Compare())
3425 {
3426 const auto n = a.size();
3427 if (n == 0)
3428 return 0;
3429
3430 return binary_search(a, x, 0, static_cast<long>(n) - 1, cmp);
3431 }
3432
3459 template <template <typename> class C, typename T,
3460 class Compare = Aleph::less<T>>
3461 inline
3462 long binary_search(const C<T> & a, const T & x, const Compare & cmp = Compare())
3463 {
3464 const auto n = a.size();
3465 if (n == 0)
3466 return 0;
3467
3468 return binary_search(a, x, 0, static_cast<long>(n) - 1, cmp);
3469 }
3470
3471 template <template <typename> class C, typename T,
3472 class Compare = Aleph::less<T>>
3473 inline
3475 const Compare & cmp = Compare())
3476 {
3478 const auto n = a.size();
3479 if (n == 0)
3480 return ret;
3481
3482 long idx = binary_search(a, x, 0, static_cast<long>(n) - 1, cmp);
3483 if (idx < 0)
3484 return ret;
3485
3486 if (not are_equals(a(idx), x, cmp))
3487 return ret;
3488
3489 ret.append(idx);
3490 for (long i = idx - 1; i >= 0; --i)
3491 {
3492 if (not are_equals(a(i), x, cmp))
3493 break;
3494 ret.insert(i);
3495 }
3496
3497 for (long i = idx + 1; i < static_cast<long>(n); ++i)
3498 {
3499 if (not are_equals(a(i), x, cmp))
3500 break;
3501 ret.append(i);
3502 }
3503
3504 return ret;
3505 }
3506
3507 template <template <typename> class C, typename T,
3508 class Compare = Aleph::less<T>>
3509 inline
3510 T * bsearch(const C<T> & a, const T & x, const Compare & cmp = Compare())
3511 {
3512 long i = binary_search(a, x, cmp);
3513 if (i < 0)
3514 return nullptr;
3515 T *ptr = &a(i);
3516 return are_equals(*ptr, x, cmp) ? ptr : nullptr;
3517 }
3518
3519 template <template <typename> class C, typename T,
3520 class Compare = Aleph::less<T>>
3521 inline
3522 T * bsearch(const C<T *> & a, const T & x, const Compare & cmp = Compare())
3523 {
3524 long i = binary_search(a, x, cmp);
3525 if (i < 0)
3526 return nullptr;
3527 T *ptr = a(i);
3528 return are_equals(*ptr, x, cmp) ? ptr : nullptr;
3529 }
3530
3531 template <template <typename> class C, typename T,
3532 class Compare = Aleph::less<T>>
3533 inline
3534 DynList<T *> bsearch_dup(const C<T> & a, const T & x, const Compare & cmp = Compare())
3535 {
3537 long idx = binary_search(a, x, cmp);
3538 if (idx < 0)
3539 return ret;
3540
3541 T *found_ptr = const_cast<T *>(&a(idx));
3542 if (not are_equals(*found_ptr, x, cmp))
3543 return ret;
3544
3545 for (long i = idx - 1; i >= 0; --i)
3546 {
3547 T *ptr = const_cast<T *>(&a(i));
3548 if (not are_equals(*ptr, x, cmp))
3549 break;
3550 ret.insert(ptr);
3551 }
3552
3554
3555 for (long i = idx + 1, n = a.size(); i < n; ++i)
3556 {
3557 T *ptr = const_cast<T *>(&a(i));
3558 if (not are_equals(*ptr, x, cmp))
3559 break;
3560 ret.append(ptr);
3561 }
3562
3563 return ret;
3564 }
3565
3566 template <template <typename> class C, typename T,
3567 class Compare = Aleph::less<T>>
3568 inline
3569 DynList<T *> bsearch_dup(const C<T *> & a, const T & x, const Compare & cmp = Compare())
3570 {
3572 const auto n = a.size();
3573 if (n == 0)
3574 return ret;
3575
3576 long idx = binary_search(a, x, 0, static_cast<long>(n) - 1, cmp);
3577 if (idx < 0)
3578 return ret;
3579
3580 T *found_ptr = a(idx);
3581 if (not are_equals(*found_ptr, x, cmp))
3582 return ret;
3583
3584 for (long i = idx - 1; i >= 0; --i)
3585 {
3586 T *ptr = a(i);
3587 if (not are_equals(*ptr, x, cmp))
3588 break;
3589 ret.insert(ptr);
3590 }
3591
3593
3594 for (long i = idx + 1, n = a.size(); i < n; ++i)
3595 {
3596 T *ptr = a(i);
3597 if (not are_equals(*ptr, x, cmp))
3598 break;
3599 ret.append(ptr);
3600 }
3601
3602 return ret;
3603 }
3604
3638 template <template <typename> class C, typename T,
3639 class Compare = Aleph::less<T>>
3640 inline
3641 long binindex(const C<T> & a, const T & x, const Compare & cmp = Compare())
3642 {
3643 return binary_search(a, x, cmp);
3644 }
3645
3675 template <template <typename> class C, typename T,
3676 class Compare = Aleph::less<T>>
3677 inline
3678 DynList<long> binindex_dup(const C<T> & a, const T & x, const Compare & cmp = Compare())
3679 {
3681 long idx = binary_search(a, x, cmp);
3682 if (idx < 0)
3683 return ret;
3684
3685 T *ptr = const_cast<T *>(&a(idx));
3686 if (not are_equals(*ptr, x, cmp))
3687 return ret;
3688
3689 const long mid = idx;
3690
3691 for (long i = idx - 1; i >= 0; --i)
3692 {
3693 ptr = const_cast<T *>(&a(i));
3694 if (not are_equals(*ptr, x, cmp))
3695 break;
3696 ret.insert(i);
3697 }
3698
3699 ret.append(mid);
3700
3701 for (long i = idx + 1, n = a.size(); i < n; ++i)
3702 {
3703 ptr = const_cast<T *>(&a(i));
3704 if (not are_equals(*ptr, x, cmp))
3705 break;
3706 ret.append(i);
3707 }
3708
3709 return ret;
3710 }
3711
3712 template <template <typename> class C, typename T,
3713 class Compare = Aleph::less<T>>
3714 inline
3715 DynList<long> binindex_dup(const C<T *> & a, const T & x, const Compare & cmp = Compare())
3716 {
3718 long idx = binary_search(a, x, cmp);
3719 if (idx < 0)
3720 return ret;
3721
3722 T *ptr = a(idx);
3723 if (not are_equals(*ptr, x, cmp))
3724 return ret;
3725
3726 for (long i = idx - 1; i >= 0; --i)
3727 {
3728 ptr = a(i);
3729 if (not are_equals(*ptr, x, cmp))
3730 break;
3731 ret.insert(i);
3732 }
3733
3734 ret.append(idx);
3735
3736 for (long i = idx + 1, n = a.size(); i < n; ++i)
3737 {
3738 T *ptr = a(i);
3739 if (not are_equals(*ptr, x, cmp))
3740 break;
3741 ret.append(i);
3742 }
3743
3744 return ret;
3745 }
3746
3782 template <template <typename> class C, typename T,
3783 class Compare = Aleph::less<T>>
3784 inline
3785 DynArray<size_t> build_index(const C<T> & a, const Compare & cmp = Compare())
3786 {
3787 const size_t & n = a.size();
3789 ret.reserve(a.size());
3790 for (size_t i = 0; i < n; ++i)
3791 ret(i) = i;
3792
3794 [&a, &cmp](size_t i, size_t j) { return cmp(a(i), a(j)); });
3795
3796 return ret;
3797 }
3798
3824 template <template <typename> class C, typename T,
3825 class Compare = Aleph::less<T>>
3826 inline
3827 DynArray<T *> build_index_ptr(const C<T> & a, const Compare & cmp = Compare())
3828 {
3829 const size_t & n = a.size();
3831 ret.reserve(a.size());
3832 for (size_t i = 0; i < n; ++i)
3833 ret(i) = &a(i);
3834
3835 quicksort_op(ret, [&cmp](const T *ptr1, const T *ptr2)
3836 {
3837 return cmp(*ptr1, *ptr2);
3838 });
3839
3840 return ret;
3841 }
3842
3870 template <template <typename> class C, typename T,
3871 class Compare = Aleph::less<T>>
3872 inline
3873 void quicksort_op(C<T> & a, const Compare & cmp = Compare(),
3874 const size_t threshold = Quicksort_Threshold)
3875 {
3876 const size_t n = a.size();
3877 if (n <= 1)
3878 return;
3879
3880 size_t l = 0, r = n - 1;
3881
3882 FixedStack<size_t> stack(64);
3883
3884 push2(stack, l, r);
3885
3886 while (not stack.is_empty())
3887 {
3888 l = stack.pop();
3889 r = stack.pop();
3890
3891 const size_t partition_size = r - l + 1;
3892 if (partition_size <= 1)
3893 continue;
3894
3895 if (partition_size <= threshold)
3896 {
3897 insertion_sort(a, l, r, cmp);
3898 continue;
3899 }
3900
3901 const auto i =
3902 static_cast<size_t>(partition_op<T, Compare>(a,
3903 static_cast<long>(l),
3904 static_cast<long>(r),
3905 cmp));
3906
3907 const size_t left_size = i > l ? i - l : 0;
3908 const size_t right_size = r > i ? r - i : 0;
3909
3910 if (left_size > right_size)
3911 {
3912 if (left_size > 0)
3913 push2(stack, l, i - 1);
3914 if (right_size > 0)
3915 push2(stack, i + 1, r);
3916 }
3917 else
3918 {
3919 if (right_size > 0)
3920 push2(stack, i + 1, r);
3921 if (left_size > 0)
3922 push2(stack, l, i - 1);
3923 }
3924 }
3925 }
3926
3957 template <typename T, class Compare = Aleph::less<T>>
3958 inline
3959 long binary_search_rec(T *a, const T & x, const long l, const long r,
3960 const Compare & cmp = Compare())
3961 {
3962 if (l > r)
3963 return l;
3964
3965 const long m = l + (r - l) / 2;
3966
3967 if (cmp(x, a[m]))
3968 return binary_search_rec<T, Compare>(a, x, l, m - 1, cmp);
3969 if (cmp(a[m], x))
3970 return binary_search_rec<T, Compare>(a, x, m + 1, r, cmp);
3971
3972 return m;
3973 }
3974
4005 template <typename T, class Compare = Aleph::less<T>>
4006 inline
4007 long binary_search(T *a, const T & x, long l, long r,
4008 const Compare & cmp = Compare())
4009 {
4010 while (l <= r)
4011 {
4012 long m = l + (r - l) / 2;
4013 if (cmp(x, a[m]))
4014 r = m - 1;
4015 else if (cmp(a[m], x))
4016 l = m + 1;
4017 else
4018 return m;
4019 }
4020 return l;
4021 }
4022}
4023
4024#endif // TPL_SORT_UTILS_H
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
#define ah_logic_error()
Throws std::logic_error unconditionally.
Definition ah-errors.H:341
#define ah_out_of_range_error()
Throws std::out_of_range unconditionally.
Definition ah-errors.H:611
Functional programming utilities for Aleph-w containers.
General utility functions and helpers.
long double h
Definition btreepic.C:154
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:333
bool operator()(Tlink *l1, Tlink *l2) const noexcept(noexcept(std::declval< const Compare & >()(std::declval< const T & >(), std::declval< const T & >())))
Compare_Tnode(Compare cmp_fct=Compare()) noexcept(std::is_nothrow_copy_constructible_v< Compare >)
Node belonging to a double circular linked list with header node.
Definition tpl_dnode.H:106
T & get_data() noexcept
Return a modifiable reference to the data contained in the node.
Definition tpl_dnode.H:232
size_t size() const noexcept
Return the current dimension of array.
bool exist(const size_t i) const
Return true if the i-th entry is accessible.
Dynamic doubly linked list with O(1) size and bidirectional access.
Iterator on the items of list.
Definition htlist.H:1714
T & get_curr_ne() const noexcept
Return the current link guaranteeing no exception. Be careful.
Definition htlist.H:1730
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
Fixed length stack.
T & push(const T &data) noexcept
Push a copy of data
size_t size() const noexcept
Return the number of elements stored in the stack.
bool is_empty() const noexcept
Return true if stack is empty.
T pop() noexcept
Pop by moving the top of stack.
Iterator on HTList.
Definition htlist.H:1083
void next_ne() noexcept
Move the iterator one position forward guaranteeing no exception.
Definition htlist.H:1190
void next()
Move the iterator one item forward.
Definition htlist.H:1222
Slinknc * get_curr() const
Return the current node on which the iterator is positioned.
Definition htlist.H:1177
bool has_curr() const noexcept
Return true if iterator has current item.
Definition htlist.H:1150
Single linked list of nodes.
Definition htlist.H:507
Slinknc * get_first() const noexcept
Return list first element.
Definition htlist.H:547
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
void concat_list(HTList &l) noexcept
Definition htlist.H:663
void append(Slinknc *link) noexcept
Insert link as last element.
Definition htlist.H:613
size_t split_list(HTList &l, HTList &r) noexcept
It divides 'this' into two equal lists without modifying elements order.
Definition htlist.H:930
Slinknc * remove_first_ne() noexcept
Definition htlist.H:801
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
void insert(Slinknc *link) noexcept
Insert link as first element.
Definition htlist.H:588
Slinknc * get_last() const noexcept
Return the last item of the list (nullptr if the list is empty)
Definition htlist.H:550
size_t split_list_ne(HTList &l, HTList &r) noexcept
Definition htlist.H:971
bool is_unitarian_or_empty() const noexcept
Return true if list contains one element or is empty.
Definition htlist.H:535
Comparator wrapper that inverts the comparison order.
Negate_Compare(Compare __cmp=Compare()) noexcept(std::is_nothrow_copy_assignable_v< Compare >)
Construct from a comparator.
bool operator()(const T &e1, const T &e2) const noexcept(noexcept(std::declval< const Compare & >()(e2, e1)))
Compare in reverse order: returns cmp(e2, e1).
Link of a single linked list non-circular and without header node.
Definition htlist.H:100
void insert(Slinknc *p) noexcept
Insert p after this
Definition htlist.H:159
Node belonging to a single non-circular linked list without header node.
Definition htlist.H:328
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_min_function > > min(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4111
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
Singly linked list implementations with head-tail access.
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< size_t > binary_search_dup(const C< T > &a, const T &x, const Compare &cmp=Compare())
long search_min(T *a, const long l, const long r, const Compare &cmp=Compare())
Returns the smallest element of the array a between l and r.
bool is_sorted(const Container< T > &cont, const Compare &cmp=Compare())
Check if a container is sorted in ascending order.
long select_pivot(T *a, long l, long r, const Compare &cmp=Compare()) noexcept(noexcept(cmp(a[0], a[0])) &&std::is_nothrow_swappable_v< T >)
long select_pivot_op_impl(const Container &a, const long l, const long r, const Compare &cmp)
std::pair< bool, size_t > search_inversion(const Container< T > &cont, const Compare &cmp=Compare())
Find the first inversion in a container.
void heapsort_subrange(DynArray< T > &a, const long l, const long r, const Compare &cmp)
Heapsort a subrange of a DynArray.
size_t introsort_depth_limit(size_t n) noexcept
Compute the depth limit for introsort.
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
long select_pivot_op(const DynArray< T > &a, const long l, const long r, const Compare &cmp=Compare())
Selects a pivot element as the median between the ends and the center.
Dnode< T > * dlink_random_search(Dlink &list, const T &x, const Compare &cmp=Compare())
Random search for an element in a dlink list.
void sift_down(T *ptr, const size_t l, const size_t r, Compare &cmp)
Restore the heap property by moving the element at position l downwards.
DynArray< T * > build_index_ptr(const C< T > &a, const Compare &cmp=Compare())
Builds and returns an array of pointers to the elements of container a sorted according to the compar...
void sift_down_subrange(DynArray< T > &a, long start, const long n, const long offset, const Compare &cmp)
Sift down operation for heapsort on a DynArray subrange.
void quicksort_no_tail(T *a, long l, long r, const Compare &cmp=Compare())
long random_search(T *a, const T &x, const long l, const long r, const Compare &cmp=Compare())
Random search for an element in an array.
size_t Quicksort_Threshold
Threshold for using quicksort vs simpler algorithms.
const int Not_Found
Return value for search functions when element is not found.
std::pair< TgtContainer< typename SrcContainer::Item_Type >, TgtContainer< typename SrcContainer::Item_Type > > partition(const SrcContainer &c, std::function< bool(const typename SrcContainer::Item_Type &)> operation)
Partition a container into two based on a predicate.
std::pair< bool, size_t > test_sorted(const Container< T > &cont, const Compare &cmp=Compare())
Test if a container is sorted, returning the inversion position.
void introsort_loop(T *a, long l, long r, size_t depth_limit, const Compare &cmp)
Internal recursive function for introsort.
long search_max(T *a, const long l, const long r, const Compare &cmp=Compare())
Returns the maximum element of the array a between l and r.
void mergeinsertsort(Tlist< T > &list, const Compare &cmp=Compare(), const size_t lsz=Aleph::Insertion_Threshold)
Sort a list by mergesort combined with the insert method.
void insert_sorted(Dlink &list, Dlink *p, const Compare &cmp)
Inserts a node orderly into a doubly linked list.
Dlink * dlink_random_select(Dlink &list, const size_t i, const Compare &cmp=Compare())
Random selection of the ith element from a list based about Dlink.
void heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Sort an array using the heapsort algorithm.
void faster_heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Optimized version of heapsort.
void mergesort(T *a, const long l, const long r, std::vector< T > &buf, Compare cmp)
T * bsearch(const C< T > &a, const T &x, const Compare &cmp=Compare())
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
DynArray< size_t > build_index(const C< T > &a, const Compare &cmp=Compare())
Build an index array for indirect sorting.
void list_insertion_sort(ListType &list, const Compare &cmp)
Sorts a list of simple nodes by insertion method.
static const T & __random_select(T *a, const long i, const long l, const long r, const Compare &cmp)
const T & random_select(DynArray< T > &a, const long i, const Compare &cmp=Compare())
static long back_index(const long i) noexcept
void bubble_sort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using bubble sort.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
DynList< T * > bsearch_dup(const C< T > &a, const T &x, const Compare &cmp=Compare())
void quicksort(T *a, const long l, const long r, const Compare &cmp=Compare())
Sort an array using iterative quicksort with optimizations.
void insertion_sort(T *a, const long l, const long r, const Compare &cmp=Compare()) noexcept(noexcept(cmp(a[0], a[0])) &&std::is_nothrow_move_assignable_v< T >)
Sort an array using insertion sort.
void shellsort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using Shell sort.
bool are_equals(const T &op1, const T &op2, Compare &&cmp=Compare())
Determines if operands are equal using a comparison operator.
Definition ahFunction.H:983
Itor3 merge(Itor1 source1Beg, Itor1 source1End, Itor2 source2Beg, Itor2 source2End, Itor3 destBeg)
Merge two sorted ranges.
Definition ahAlgo.H:1410
void quicksort_rec_min(T *a, const long l, const long r, const Compare &cmp=Compare())
Sorts an array according to the quicksort method with minimum space consumption.
long sequential_search(T *a, const T &x, const long l, const long r, Equal eq=Equal())
Linear search for an element in an array.
Link * search_extreme(const Link &list, const Compare &cmp)
Find the extreme (minimum or maximum) element in a linked list.
bool binary_search(Itor beg, Itor end, const T &value)
Binary search for a value.
Definition ahAlgo.H:1284
void quicksort_rec(T *a, const long l, const long r, const Compare &cmp=Compare())
Sorts an array using the quicksort method.
DynList< long > binindex_dup(const C< T > &a, const T &x, const Compare &cmp=Compare())
Returns the indices of all occurrences of a value in a sorted container.
bool is_inversely_sorted(const Container< T > &cont, const Compare &cmp=Compare())
Check if a container is sorted in descending order.
long partition_op_impl(Container &a, const long l, const long r, const Compare &cmp)
void selection_sort(T *a, const size_t n, const Compare &cmp=Compare()) noexcept(noexcept(cmp(a[0], a[0])) &&std::is_nothrow_swappable_v< T >)
Sort an array using the selection sort algorithm.
void introsort(T *a, const long l, const long r, const Compare &cmp=Compare())
Sort an array using introsort (introspective sort).
long binindex(const C< T > &a, const T &x, const Compare &cmp=Compare())
Returns the index where a value appears (or should be inserted) in a sorted container.
void quicksort_insertion(T *a, const long l, const long r, const Compare &cmp=Compare())
Sorts an array by the improved quicksort method.
size_t Insertion_Threshold
Threshold for switching to insertion sort in hybrid algorithms.
long binary_search_rec(T *a, const T &x, const long l, const long r, const Compare &cmp=Compare())
Recursive binary search on an ordered array.
long partition_op(DynArray< T > &a, const long l, const long r, const Compare &cmp=Compare())
T & sift_up(T *ptr, const size_t l, const size_t r, Compare &cmp)
Restore the heap property by moving the element at position r upwards.
void merge_lists(Tlist &l1, Tlist &l2, Tlist &result, const Compare &cmp=Compare())
Merge two sorted lists into a single sorted list.
DynList< T > maps(const C &c, Op op)
Classic map operation.
void push2(Stack &stack, const A &a, const B &b)
void quicksort_op(C< T > &a, const Compare &cmp=Compare(), const size_t threshold=Quicksort_Threshold)
Optimized quicksort for containers using operator().
STL namespace.
Compare_Dnode(const Compare &cmp=Compare()) noexcept(std::is_nothrow_copy_constructible_v< Compare >)
Fixed-capacity binary heap and heapsort algorithms.
Stack implementations backed by dynamic or fixed arrays.
Dynamic array container with automatic resizing.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
DynList< int > l