Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
sort_utils.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
37#include <gtest/gtest.h>
38
39#include <algorithm>
40#include <chrono>
41#include <cstdint>
42#include <cstdlib>
43#include <limits>
44#include <random>
45#include <string>
46#include <type_traits>
47#include <vector>
48#include <array>
49
50#include <tpl_sort_utils.H>
51#include <tpl_dynArray.H>
52#include <tpl_array.H>
53#include <tpl_dynList.H>
54#include <tpl_dynDlist.H>
55#include <tpl_dnode.H>
56
57using namespace Aleph;
58using namespace std;
59
60namespace {
61
62static_assert(CountingSortable<int>);
64static_assert(not CountingSortable<bool>);
65static_assert(RadixSortable<int>);
67static_assert(not RadixSortable<bool>);
68
75static DynArray<int> make_dynarray(std::initializer_list<int> xs)
76{
78 a.reserve(xs.size());
79 size_t i = 0;
80 for (const int x : xs)
81 a(i++) = x;
82 return a;
83}
84
85static DynList<int> make_dynlist(std::initializer_list<int> xs)
86{
88 for (int x : xs)
89 l.append(x);
90 return l;
91}
92
93static DynDlist<int> make_dyndlist(std::initializer_list<int> xs)
94{
96 for (int x : xs)
97 l.append(x);
98 return l;
99}
100
101static Dnode<int> make_dnode_list(std::initializer_list<int> xs)
102{
104 for (int x : xs)
105 h.append(new Dnode<int>(x));
106 return h;
107}
108
116static void delete_all_nodes(Dnode<int> & h)
117{
118 while (not h.is_empty())
119 delete h.remove_first_ne();
120}
121
128template <typename T>
129static void sort_dynarray(DynArray<T> & a)
130{
131 quicksort(a);
132}
133
145template <typename T>
146static void expect_same_dynarray(const DynArray<T> & a, const DynArray<T> & b)
147{
148 EXPECT_EQ(a.size(), b.size());
149 if (a.size() != b.size())
150 return;
151 for (size_t i = 0; i < a.size(); ++i)
152 EXPECT_EQ(a(i), b(i));
153}
154
162template <typename T>
164{
166 ret.reserve(l.size());
167 size_t i = 0;
168 for (HTList::Iterator it(l); it.has_curr(); it.next())
169 ret(i++) = reinterpret_cast<uintptr_t>(it.get_curr());
171 return ret;
172}
173
184template <typename T>
186{
188 ret.reserve(l.size());
189 size_t i = 0;
190 for (typename Dnode<T>::Iterator it(l); it.has_curr(); it.next())
191 ret(i++) = reinterpret_cast<uintptr_t>(it.get_curr());
193 return ret;
194}
195
197{
198 DynList<int> l = make_dynlist({1, 1, 2, 2, 3});
200 EXPECT_TRUE(test_sorted(l).first);
202}
203
205{
206 DynList<int> l = make_dynlist({1, 3, 2, 4});
208 auto inv = search_inversion(l);
209 EXPECT_FALSE(inv.first);
210 EXPECT_EQ(inv.second, 2u);
211}
212
214{
215 DynList<int> l = make_dynlist({5, 4, 4, 2, 1});
218}
219
221{
222 int a0[1] = {0};
223 selection_sort(a0, 0);
224 selection_sort(a0, 1);
225 EXPECT_EQ(a0[0], 0);
226}
227
229{
230 int a[] = {3, 1, 2, 1, 0};
231 selection_sort(a, sizeof(a) / sizeof(a[0]));
232 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
233}
234
236{
237 auto a = make_dynarray({10, 9, 3, 2, 1, 8, 7});
238 // sort only [2..4] (3,2,1)
239 insertion_sort(a, 2, 4);
240 EXPECT_EQ(a(0), 10);
241 EXPECT_EQ(a(1), 9);
242 EXPECT_EQ(a(2), 1);
243 EXPECT_EQ(a(3), 2);
244 EXPECT_EQ(a(4), 3);
245 EXPECT_EQ(a(5), 8);
246 EXPECT_EQ(a(6), 7);
247}
248
250{
251 auto a = make_dynarray({3, 1, 2, 1, 0});
253 for (size_t i = 1; i < a.size(); ++i)
254 ASSERT_LE(a(i - 1), a(i));
255}
256
258{
259 auto a = make_dynarray({3, 1, 2, 1, 0});
261 for (size_t i = 1; i < a.size(); ++i)
262 ASSERT_GE(a(i - 1), a(i));
263}
264
266{
267 auto a = make_dynarray({3, 1, 2, 1, 0});
268 bubble_sort(a);
269 for (size_t i = 1; i < a.size(); ++i)
270 ASSERT_LE(a(i - 1), a(i));
271}
272
274{
275 auto a = make_dynarray({0, 0, 1, 1, 2, 2});
276 bubble_sort(a);
277 for (size_t i = 1; i < a.size(); ++i)
278 ASSERT_LE(a(i - 1), a(i));
279 EXPECT_EQ(a(0), 0);
280 EXPECT_EQ(a(5), 2);
281}
282
283static bool is_min_heap(const DynArray<int> & a, size_t n)
284{
285 if (n <= 1)
286 return true;
287
288 for (size_t child = 2; child <= n; ++child)
289 {
290 size_t parent = child / 2;
291 if (a(parent - 1) > a(child - 1))
292 return false;
293 }
294 return true;
295}
296
298{
299 auto a = make_dynarray({5, 99, 0, 99, 99, 3, 99});
300 // l=0 => 5, m=3 => 99, r=6 => 99 => median is 99 => either m or r
301 long p = select_pivot_op<int>(a, 0, 6);
302 EXPECT_TRUE(p == 3 || p == 6);
303
304 auto b = make_dynarray({10, 99, 5, 99, 99, 99, 0});
305 // l=0 => 10, m=3 => 99, r=6 => 0 => median is 10 => l
306 EXPECT_EQ(select_pivot_op<int>(b, 0, 6), 0);
307
308 auto c = make_dynarray({0, 99, 99, 5, 99, 99, 10});
309 // l=0 => 0, m=3 => 5, r=6 => 10 => median is 5 => m
310 EXPECT_EQ(select_pivot_op<int>(c, 0, 6), 3);
311}
312
314{
315 Array<int> a;
316 for (int x : {5, 4, 3, 2, 1, 0})
317 a.append(x);
318
319 // r - l <= 5 => returns r
320 EXPECT_EQ(select_pivot_op<int>(a, 0, 5), 5);
321}
322
324{
325 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
326 std::vector<int> before;
327 before.reserve(a.size());
328 for (size_t i = 0; i < a.size(); ++i)
329 before.push_back(a(i));
330
331 long p = partition_op<int>(a, 0, static_cast<long>(a.size() - 1));
332 ASSERT_GE(p, 0);
333 ASSERT_LT(static_cast<size_t>(p), a.size());
334
335 const int pivot = a(p);
336 for (long i = 0; i < p; ++i)
338 for (long i = p + 1; i < static_cast<long>(a.size()); ++i)
340
341 std::vector<int> after;
342 after.reserve(a.size());
343 for (size_t i = 0; i < a.size(); ++i)
344 after.push_back(a(i));
345 std::sort(before.begin(), before.end());
346 std::sort(after.begin(), after.end());
348}
349
351{
352 Array<int> a;
353 for (int x : {4, 1, 3, 2, 0, 2})
354 a.append(x);
355
356 std::vector<int> before;
357 before.reserve(a.size());
358 for (size_t i = 0; i < a.size(); ++i)
359 before.push_back(a(i));
360
361 long p = partition_op<int>(a, 0, static_cast<long>(a.size() - 1));
362 ASSERT_GE(p, 0);
363 ASSERT_LT(static_cast<size_t>(p), a.size());
364
365 const int pivot = a(p);
366 for (long i = 0; i < p; ++i)
368 for (long i = p + 1; i < static_cast<long>(a.size()); ++i)
370
371 std::vector<int> after;
372 after.reserve(a.size());
373 for (size_t i = 0; i < a.size(); ++i)
374 after.push_back(a(i));
375 std::sort(before.begin(), before.end());
376 std::sort(after.begin(), after.end());
378}
379
381{
382 {
383 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
384 auto expected = std::vector<int>{4, 1, 3, 2, 0, 2};
385 std::sort(expected.begin(), expected.end());
389 }
390
391 {
392 Array<int> a;
393 for (int x : {4, 1, 3, 2, 0, 2})
394 a.append(x);
395 auto expected = std::vector<int>{4, 1, 3, 2, 0, 2};
396 std::sort(expected.begin(), expected.end());
400 }
401}
402
404{
405 EXPECT_EQ(back_index(10), 9);
406
408 EXPECT_TRUE(nc(2, 1));
409 EXPECT_FALSE(nc(1, 2));
410}
411
413{
414 int a[] = {4, 1, 3, 2, 0, 2};
416 int p = select_pivot<int, Aleph::less<int>>(a, 0, 5, cmp);
417 EXPECT_GE(p, 0);
418 EXPECT_LE(p, 5);
419
420 int q = partition<int, Aleph::less<int>>(a, 0, 5, cmp);
421 EXPECT_GE(q, 0);
422 EXPECT_LE(q, 5);
423}
424
426{
427 // [0..2] and [3..5] are already sorted
428 int a[] = {0, 2, 4, 1, 3, 5};
429 merge(a, 0, 2, 5, Aleph::less<int>());
430 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
431}
432
434{
435 FixedStack<int> st(10);
436 push2(st, 1, 2);
437 EXPECT_EQ(st.pop(), 1);
438 EXPECT_EQ(st.pop(), 2);
439 EXPECT_TRUE(st.is_empty());
440}
441
443{
444 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
445 quicksort_no_tail(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
446 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
447}
448
450{
451 Snodenc<int> n1(1), n2(2);
453 EXPECT_TRUE(cmp(static_cast<Slinknc *>(&n1), static_cast<Slinknc *>(&n2)));
454 EXPECT_TRUE(cmp(static_cast<Slinknc *>(&n1), 5));
455}
456
458{
460 Dlink & base = static_cast<Dlink &>(h);
461
462 auto * n2 = new Dnode<int>(2);
463 auto * n0 = new Dnode<int>(0);
464 auto * n1 = new Dnode<int>(1);
465
468
469 insert_sorted<Cmp>(base, n2, cmp);
470 insert_sorted<Cmp>(base, n0, cmp);
471 insert_sorted<Cmp>(base, n1, cmp);
473
474 // list_insertion_sort on Dlink
475 Dnode<int> h2 = make_dnode_list({3, 1, 2, 0});
476 Dlink & base2 = static_cast<Dlink &>(h2);
479
480 delete_all_nodes(h);
481 delete_all_nodes(h2);
482}
483
485{
487 l.append(0);
488 l.append(2);
489
490 auto * node = new Snodenc<int>(1);
492 insert_sorted(l, static_cast<Slinknc *>(node), cmp);
494
496 for (int x : {3, 1, 2, 0})
497 l2.append(x);
499 static_cast<HTList &>(l2), cmp);
501}
502
504{
505 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
506 Dlink & base = static_cast<Dlink &>(h);
507
510
511 auto * found = dlink_random_search(base, 3, cmp);
512 ASSERT_NE(found, nullptr);
513 EXPECT_EQ(found->get_data(), 3);
514
515 auto * sel = dlink_random_select(base, 0, cmp);
516 ASSERT_NE(sel, nullptr);
517 EXPECT_EQ(static_cast<Dnode<int> *>(sel)->get_data(), 0);
518
519 delete_all_nodes(h);
520}
521
523{
524 const auto a = make_dynarray({0, 1, 1, 1, 2, 3});
525 EXPECT_EQ(binindex(a, 2), 4);
526}
527
529{
530 int a[] = {4, 1, 3, 2, 0, 2};
531 std::vector<int> expected(std::begin(a), std::end(a));
532 std::sort(expected.begin(), expected.end());
533
538}
539
541{
543
544 // sift_up: insert new element at end and bubble up
545 {
547 a.reserve(4);
548 a(0) = 1;
549 a(1) = 3;
550 a(2) = 5;
551 a(3) = 0;
554 }
555
556 // sift_down: restore heap after root replaced
557 {
559 a.reserve(4);
560 a(0) = 3;
561 a(1) = 1;
562 a(2) = 2;
563 a(3) = 0; // outside heap when n=3
566 }
567}
568
570{
571 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
572 mergesort(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
573 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
574}
575
577{
578 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
579 quicksort(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
580 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
581}
582
584{
585 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
586 quicksort_rec(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
587 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
588}
589
591{
592 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
593 quicksort_rec_min(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
594 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
595}
596
598{
599 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
600 quicksort_insertion(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
601 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
602
603 int b[] = {2, 1};
604 quicksort_insertion(b, 0, 1);
605 EXPECT_TRUE(std::is_sorted(std::begin(b), std::end(b)));
606}
607
608// Introsort tests - hybrid algorithm with O(n log n) guaranteed
610{
611 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
612 introsort(a, 0L, static_cast<long>((sizeof(a) / sizeof(a[0])) - 1));
613 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
614}
615
617{
618 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
619 introsort(a, sizeof(a) / sizeof(a[0]));
620 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
621}
622
624{
625 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
626 introsort(a, 0L, 8L, std::greater<int>());
627 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a), std::greater<int>()));
628}
629
631{
632 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
633 introsort(a);
634 for (size_t i = 1; i < a.size(); ++i)
635 ASSERT_LE(a(i - 1), a(i));
636}
637
639{
640 // Empty array
641 int empty[] = {0};
642 introsort(empty, 0);
643 EXPECT_EQ(empty[0], 0);
644
645 // Single element
646 int single[] = {42};
647 introsort(single, 1);
648 EXPECT_EQ(single[0], 42);
649
650 // Empty DynArray
653}
654
656{
657 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
658 introsort(a, sizeof(a) / sizeof(a[0]));
659 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
660}
661
663{
664 int a[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
665 introsort(a, sizeof(a) / sizeof(a[0]));
666 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
667}
668
670{
671 int a[] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
672 introsort(a, sizeof(a) / sizeof(a[0]));
673 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
674}
675
677{
678 // Create an array large enough that might trigger heapsort fallback
679 // This tests the depth limit mechanism
680 const size_t n = 10000;
681 std::vector<int> v(n);
682 for (size_t i = 0; i < n; ++i)
683 v[i] = static_cast<int>(n - i); // Reverse sorted (worst case for quicksort)
684
685 introsort(v.data(), n);
686 EXPECT_TRUE(std::is_sorted(v.begin(), v.end()));
687}
688
690{
691 // Test with larger DynArray
692 const size_t n = 5000;
694 a.reserve(n);
695 for (size_t i = 0; i < n; ++i)
696 a(i) = static_cast<int>(n - i); // Reverse sorted
697
698 introsort(a);
699 for (size_t i = 1; i < n; ++i)
700 ASSERT_LE(a(i - 1), a(i)) << "Failed at index " << i;
701}
702
703// Introsort with STL-style pointer interface (begin, end)
705{
706 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
707 introsort(a, a + 10); // STL-style: introsort(begin, end)
708 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
709}
710
712{
713 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
714 // Sort only middle portion [2, 7)
715 introsort(a + 2, a + 7);
716 // Elements 0,1 unchanged, 2-6 sorted, 7-9 unchanged
717 EXPECT_EQ(a[0], 9);
718 EXPECT_EQ(a[1], 1);
719 EXPECT_TRUE(std::is_sorted(a + 2, a + 7));
720 EXPECT_EQ(a[7], 4);
721}
722
724{
725 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
726 introsort(a, a + 9, std::greater<int>());
727 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a), std::greater<int>()));
728}
729
731{
732 int a[] = {42};
733 // Empty range - should not crash
734 introsort(a, a);
735 EXPECT_EQ(a[0], 42); // Unchanged
736}
737
738// Introsort for Array<T> container
740{
741 Array<int> arr;
742 arr.append(5);
743 arr.append(2);
744 arr.append(8);
745 arr.append(1);
746 arr.append(9);
747 arr.append(3);
748
749 introsort(arr);
750
751 for (size_t i = 1; i < arr.size(); ++i)
752 ASSERT_LE(arr(i - 1), arr(i));
753}
754
756{
757 Array<int> arr;
758 for (int i = 1; i <= 10; ++i)
759 arr.append(i);
760
761 introsort(arr, std::greater<int>());
762
763 for (size_t i = 1; i < arr.size(); ++i)
764 ASSERT_GE(arr(i - 1), arr(i)); // Descending order
765}
766
768{
769 Array<int> arr;
771 EXPECT_TRUE(arr.is_empty());
772}
773
775{
776 Array<int> arr;
777 arr.append(42);
778 introsort(arr);
779 EXPECT_EQ(arr.size(), 1u);
780 EXPECT_EQ(arr(0), 42);
781}
782
784{
785 const size_t n = 5000;
786 Array<int> arr(n);
787 for (size_t i = 0; i < n; ++i)
788 arr.append(static_cast<int>(n - i)); // Reverse sorted
789
790 introsort(arr);
791
792 for (size_t i = 1; i < n; ++i)
793 ASSERT_LE(arr(i - 1), arr(i)) << "Failed at index " << i;
794}
795
797{
798 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
799 heapsort(a);
800 for (size_t i = 1; i < a.size(); ++i)
801 ASSERT_LE(a(i - 1), a(i));
802}
803
805{
806 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
807 quicksort_op(a);
808 for (size_t i = 1; i < a.size(); ++i)
809 ASSERT_LE(a(i - 1), a(i));
810}
811
813{
817}
818
820{
821 auto a = make_dynarray({9, 1, 8, 2, 7, 3, 6, 4, 5, 0});
822 shellsort(a);
823 for (size_t i = 1; i < a.size(); ++i)
824 ASSERT_LE(a(i - 1), a(i));
825}
826
828{
829 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
830 quicksort(a);
831 for (size_t i = 1; i < a.size(); ++i)
832 ASSERT_LE(a(i - 1), a(i));
833}
834
836{
837 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
838 quicksort_rec(a, 0, static_cast<long>(a.size() - 1));
839 for (size_t i = 1; i < a.size(); ++i)
840 ASSERT_LE(a(i - 1), a(i));
841}
842
844{
845 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
846 mergesort(l);
848}
849
851{
852 DynList<int> l = make_dynlist({9, 8, 7, 6, 5, 4, 3, 2, 1, 0});
855}
856
858{
859 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
860 DynList<int> sorted = insertion_sort(std::move(l));
863}
864
866{
867 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
868 DynList<int> sorted = mergesort(std::move(l));
871}
872
874{
875 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
876 quicksort(l);
878 EXPECT_EQ(l.get_first(), 0);
879 EXPECT_EQ(l.get_last(), 4);
880}
881
883{
884 DynList<int> l1 = make_dynlist({0, 2, 4});
885 DynList<int> l2 = make_dynlist({1, 3, 5});
887
892 EXPECT_EQ(out.size(), 6u);
893 EXPECT_EQ(out.get_first(), 0);
894 EXPECT_EQ(out.get_last(), 5);
895}
896
898{
899 auto l1 = make_dnode_list({0, 2, 4});
900 auto l2 = make_dnode_list({1, 3, 5});
902
904
907 EXPECT_FALSE(out.is_empty());
908
909 int expected = 0;
910 for (Dnode<int>::Iterator it(out); it.has_curr(); it.next_ne(), ++expected)
911 EXPECT_EQ(it.get_curr_ne()->get_data(), expected);
913
914 delete_all_nodes(out);
915}
916
918{
919 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
920 mergesort(l);
922}
923
925{
926 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
927 int * p = search_extreme(l);
928 ASSERT_NE(p, nullptr);
929 EXPECT_EQ(*p, 0);
930}
931
933{
934 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
935 int * p = random_select(l, 0);
936 ASSERT_NE(p, nullptr);
937 EXPECT_EQ(*p, 0);
938
939 p = random_select(l, 5);
940 ASSERT_NE(p, nullptr);
941 EXPECT_EQ(*p, 4);
942}
943
945{
946 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
947
948 int * p = random_search(l, 3);
949 ASSERT_NE(p, nullptr);
950 EXPECT_EQ(*p, 3);
951
952 p = random_search(l, 99);
953 EXPECT_EQ(p, nullptr);
954}
955
957{
958 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
959
960 auto * n0 = random_select<int>(h, 0);
961 ASSERT_NE(n0, nullptr);
962 EXPECT_EQ(n0->get_data(), 0);
963
964 auto * nmax = random_select<int>(h, 5);
965 ASSERT_NE(nmax, nullptr);
966 EXPECT_EQ(nmax->get_data(), 4);
967
968 auto * nfound = random_search<int>(h, 3);
969 ASSERT_NE(nfound, nullptr);
970 EXPECT_EQ(nfound->get_data(), 3);
971
972 auto * nmiss = random_search<int>(h, 99);
973 EXPECT_EQ(nmiss, nullptr);
974
975 delete_all_nodes(h);
976}
977
979{
980 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
981 quicksort<int>(static_cast<HTList &>(l), Aleph::less<int>());
983}
984
986{
987 int a[] = {4, 1, 3, 2, 0, 2};
988 EXPECT_EQ(sequential_search(a, int{3}, 0, 5), 2);
989 EXPECT_EQ(sequential_search(a, int{99}, 0, 5), Not_Found);
990}
991
993{
994 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
995 EXPECT_EQ(sequential_search(a, 3, 0, static_cast<int>(a.size() - 1)), 2);
996 EXPECT_EQ(sequential_search(a, 99, 0, static_cast<int>(a.size() - 1)), Not_Found);
997}
998
1000{
1001 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1002 int * p = sequential_search(l, 3);
1003 ASSERT_NE(p, nullptr);
1004 EXPECT_EQ(*p, 3);
1005
1006 p = sequential_search(l, 99);
1007 EXPECT_EQ(p, nullptr);
1008}
1009
1011{
1012 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
1013 int * p = sequential_search(l, 3);
1014 ASSERT_NE(p, nullptr);
1015 EXPECT_EQ(*p, 3);
1016 p = sequential_search(l, 99);
1017 EXPECT_EQ(p, nullptr);
1018}
1019
1021{
1022 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1023
1024 auto * n = sequential_search(h, 3);
1025 ASSERT_NE(n, nullptr);
1026 EXPECT_EQ(n->get_data(), 3);
1027
1028 n = sequential_search(h, 99);
1029 EXPECT_EQ(n, nullptr);
1030
1031 delete_all_nodes(h);
1032}
1033
1035{
1036 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1037 auto * n = search_extreme<int>(h, Aleph::less<int>());
1038 ASSERT_NE(n, nullptr);
1039 EXPECT_EQ(n->get_data(), 0);
1040 delete_all_nodes(h);
1041}
1042
1044{
1045 int a[] = {4, 1, 3, 2, 0, 2};
1046 EXPECT_EQ(search_min(a, 0, 5), 4);
1047 EXPECT_EQ(search_max(a, 0, 5), 0);
1048}
1049
1051{
1052 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
1053 EXPECT_EQ(search_extreme(a, 0, static_cast<long>(a.size() - 1)), 4);
1054 EXPECT_EQ(search_max(a, 0, static_cast<long>(a.size() - 1)), 0);
1055}
1056
1058{
1059 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
1060 int * mn = search_min(l);
1061 int * mx = search_max(l);
1062 ASSERT_NE(mn, nullptr);
1063 ASSERT_NE(mx, nullptr);
1064 EXPECT_EQ(*mn, 0);
1065 EXPECT_EQ(*mx, 4);
1066}
1067
1069{
1070 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1071 int * mn = search_extreme(l);
1073 ASSERT_NE(mn, nullptr);
1074 ASSERT_NE(mx, nullptr);
1075 EXPECT_EQ(*mn, 0);
1076 EXPECT_EQ(*mx, 4);
1077}
1078
1080{
1081 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1082 int * mn = search_extreme(l, Aleph::less<int>());
1084 ASSERT_NE(mn, nullptr);
1085 ASSERT_NE(mx, nullptr);
1086 EXPECT_EQ(*mn, 0);
1087 EXPECT_EQ(*mx, 4);
1088}
1089
1091{
1092 {
1093 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1095 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1096 delete_all_nodes(h);
1097 }
1098
1099 {
1100 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1102 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1103 delete_all_nodes(h);
1104 }
1105
1106 {
1107 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1108 quicksort(h);
1109 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1110 delete_all_nodes(h);
1111 }
1112
1113 {
1114 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1115 mergesort(h);
1116 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1117 delete_all_nodes(h);
1118 }
1119}
1120
1122{
1123 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1124 Dlink & base = static_cast<Dlink &>(h);
1125
1127 quicksort(base, Cmp(Aleph::less<int>()));
1128
1129 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1131
1132 delete_all_nodes(h);
1133}
1134
1136{
1137 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1138
1139 auto idxs = binary_search_dup(a, 1);
1140 ASSERT_EQ(idxs.size(), 3u);
1141 EXPECT_EQ(idxs.get_first(), 1u);
1142 EXPECT_EQ(idxs.get_last(), 3u);
1143
1144 int * p = bsearch(a, 1);
1145 ASSERT_NE(p, nullptr);
1146 EXPECT_EQ(*p, 1);
1147 EXPECT_EQ(bsearch(a, 99), nullptr);
1148}
1149
1151{
1152 {
1153 auto a = make_dynarray({1, 1, 1, 2, 3});
1154 auto idxs = binary_search_dup(a, 1);
1155 ASSERT_EQ(idxs.size(), 3u);
1156 EXPECT_EQ(idxs.get_first(), 0u);
1157 EXPECT_EQ(idxs.get_last(), 2u);
1158 }
1159
1160 {
1161 auto a = make_dynarray({0, 1, 2, 3, 3, 3});
1162 auto idxs = binary_search_dup(a, 3);
1163 ASSERT_EQ(idxs.size(), 3u);
1164 EXPECT_EQ(idxs.get_first(), 3u);
1165 EXPECT_EQ(idxs.get_last(), 5u);
1166 }
1167}
1168
1170{
1171 // Descending sorted with duplicates
1172 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1174 ASSERT_EQ(idxs.size(), 3u);
1175 EXPECT_EQ(idxs.get_first(), 2u);
1176 EXPECT_EQ(idxs.get_last(), 4u);
1177
1179 ASSERT_EQ(idxs.size(), 2u);
1180 EXPECT_EQ(idxs.get_first(), 6u);
1181 EXPECT_EQ(idxs.get_last(), 7u);
1182}
1183
1185{
1186 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1187 auto ps = bsearch_dup(a, 3, Aleph::greater<int>());
1188 ASSERT_EQ(ps.size(), 3u);
1189 for (auto p : ps)
1190 {
1191 ASSERT_NE(p, nullptr);
1192 EXPECT_EQ(*p, 3);
1193 }
1194}
1195
1197{
1198 auto a = make_dynarray({3, 1, 2, 1, 0});
1199
1200 auto idx = build_index(a);
1201 ASSERT_EQ(idx.size(), a.size());
1202 for (size_t i = 1; i < idx.size(); ++i)
1203 ASSERT_LE(a(idx(i - 1)), a(idx(i)));
1204
1205 auto ptrs = build_index_ptr(a);
1206 ASSERT_EQ(ptrs.size(), a.size());
1207 for (size_t i = 1; i < ptrs.size(); ++i)
1208 ASSERT_LE(*ptrs(i - 1), *ptrs(i));
1209}
1210
1212{
1213 Slinknc head;
1214 auto * n1 = new Snodenc<int>(4);
1215 auto * n2 = new Snodenc<int>(1);
1216 auto * n3 = new Snodenc<int>(3);
1217 auto * n4 = new Snodenc<int>(0);
1218 head.insert(n1);
1219 head.insert(n2);
1220 head.insert(n3);
1221 head.insert(n4);
1222
1223 auto found = sequential_search(head, 3);
1224 ASSERT_NE(found, nullptr);
1225 EXPECT_EQ(static_cast<Snodenc<int>*>(found)->get_data(), 3);
1226
1227 auto missing = sequential_search(head, 99);
1228 EXPECT_EQ(missing, nullptr);
1229
1231 ASSERT_NE(extreme_min, nullptr);
1232 EXPECT_EQ(static_cast<Snodenc<int>*>(extreme_min)->get_data(), 0);
1233
1234 while (not head.is_empty())
1235 delete static_cast<Snodenc<int>*>(head.remove_next());
1236}
1237
1239{
1240 Slinknc head;
1241 auto * n1 = new Snodenc<int>(2);
1242 auto * n2 = new Snodenc<int>(1);
1243 auto * n3 = new Snodenc<int>(0);
1244 head.insert(n1);
1245 head.insert(n2);
1246 head.insert(n3);
1247
1248 auto * found = sequential_search<int>(head, 1);
1249 ASSERT_NE(found, nullptr);
1250 EXPECT_EQ(found->to_data<int>(), 1);
1251
1252 auto * missing = sequential_search<int>(head, 99);
1253 EXPECT_EQ(missing, nullptr);
1254
1255 while (not head.is_empty())
1256 delete static_cast<Snodenc<int>*>(head.remove_next());
1257}
1258
1260{
1261 auto h = make_dnode_list({3, 1, 2, 0});
1262 Dlink & base = static_cast<Dlink &>(h);
1263
1264 auto * found = sequential_search<int>(base, 2);
1265 ASSERT_NE(found, nullptr);
1266 EXPECT_EQ(static_cast<Dnode<int>*>(found)->get_data(), 2);
1267
1270 ASSERT_NE(mn, nullptr);
1271 EXPECT_EQ(mn->get_data(), 0);
1272
1273 delete_all_nodes(h);
1274}
1275
1277{
1278 int a[] = {4, 1, 3, 2, 0, 2};
1279 int idx = random_search(a, 3, 0, 5);
1280 ASSERT_NE(idx, Not_Found);
1281 EXPECT_EQ(a[idx], 3);
1282 EXPECT_EQ(random_search(a, 99, 0, 5), Not_Found);
1283
1284 auto d = make_dynarray({4, 1, 3, 2, 0, 2});
1285 idx = random_search(d, 3, 0, static_cast<long>(d.size() - 1));
1286 ASSERT_NE(idx, Not_Found);
1287 EXPECT_EQ(d(idx), 3);
1288 EXPECT_EQ(random_search(d, 99, 0, static_cast<long>(d.size() - 1)), Not_Found);
1289}
1290
1292{
1293 Array<int> a;
1294 for (int x : {4, 1, 3, 2, 0, 2})
1295 a.append(x);
1296
1297 EXPECT_EQ(random_select(a, 0), 0);
1298 EXPECT_EQ(random_select(a, 5), 4);
1299}
1300
1302{
1303 {
1304 DynArray<int> a;
1305 EXPECT_THROW(random_select(a, 0), std::out_of_range);
1306 }
1307
1308 {
1309 auto a = make_dynarray({4, 1, 3});
1310 EXPECT_THROW(random_select(a, 3), std::out_of_range);
1311 }
1312
1313 {
1314 Array<int> a;
1315 a.append(1);
1316 EXPECT_THROW(random_select(a, 1), std::out_of_range);
1317 }
1318
1319 {
1320 int b[] = {4, 1, 3};
1321 using Cmp = Aleph::less<int>;
1322 auto fn = static_cast<const int & (*)(int *, const long, const long, const Cmp &)>(
1324 EXPECT_THROW(fn(b, 3, 3, Cmp()), std::out_of_range);
1325 }
1326
1327 {
1328 Dnode<int> h;
1329 EXPECT_EQ(random_select<int>(h, 0), nullptr);
1330 EXPECT_EQ(random_select<int>(h, 1), nullptr);
1331 }
1332
1333 {
1335 EXPECT_EQ(random_select(l, 0), nullptr);
1336 EXPECT_EQ(random_select(l, 1), nullptr);
1337 }
1338
1339 {
1340 auto h = make_dnode_list({4, 1});
1341 EXPECT_THROW(random_select<int>(h, 2), std::out_of_range);
1342 delete_all_nodes(h);
1343 }
1344
1345 {
1346 auto l = make_dyndlist({4, 1});
1347 EXPECT_THROW(random_select(l, 2), std::out_of_range);
1348 }
1349}
1350
1352{
1353 auto a = make_dynarray({0, 2, 4, 6});
1354
1355 EXPECT_EQ(binary_search(a, 0), 0);
1356 EXPECT_EQ(binary_search(a, 6), 3);
1357
1358 // insertion points
1359 EXPECT_EQ(binary_search(a, 1), 1);
1360 EXPECT_EQ(binary_search(a, 5), 3);
1361 EXPECT_EQ(binary_search(a, 7), 4);
1362}
1363
1365{
1366 int a[] = {0, 2, 4, 6};
1367 EXPECT_EQ(binary_search(a, 0, 0, 3), 0);
1368 EXPECT_EQ(binary_search(a, 6, 0, 3), 3);
1369 EXPECT_EQ(binary_search(a, 1, 0, 3), 1);
1370 EXPECT_EQ(binary_search(a, 5, 0, 3), 3);
1371 EXPECT_EQ(binary_search(a, 7, 0, 3), 4);
1372}
1373
1375{
1376 int a[] = {0, 2, 4, 6};
1377 EXPECT_EQ(binary_search_rec(a, 0, 0, 3), 0);
1378 EXPECT_EQ(binary_search_rec(a, 6, 0, 3), 3);
1379 EXPECT_EQ(binary_search_rec(a, 1, 0, 3), 1);
1380 EXPECT_EQ(binary_search_rec(a, 5, 0, 3), 3);
1381 EXPECT_EQ(binary_search_rec(a, 7, 0, 3), 4);
1382}
1383
1385{
1386 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
1387 EXPECT_EQ(random_select(a, 0), 0);
1388 EXPECT_EQ(random_select(a, 5), 4);
1389
1390 int b[] = {4, 1, 3, 2, 0, 2};
1391 using Cmp = Aleph::less<int>;
1392 auto fn = static_cast<const int & (*)(int *, const long, const long, const Cmp &)>(
1394 EXPECT_EQ(fn(b, 0, 6, Cmp()), 0);
1395 EXPECT_EQ(fn(b, 5, 6, Cmp()), 4);
1396}
1397
1399{
1400 auto a = make_dynarray({0, 2, 4, 6});
1401 DynArray<int *> idx;
1402 idx.reserve(a.size());
1403 for (size_t i = 0; i < a.size(); ++i)
1404 idx(i) = &a(i);
1405
1406 // already sorted pointers by value
1407 EXPECT_EQ(binary_search(idx, 0), 0);
1408 EXPECT_EQ(binary_search(idx, 6), 3);
1409 EXPECT_EQ(binary_search(idx, 1), 1);
1410 EXPECT_EQ(binary_search(idx, 7), 4);
1411}
1412
1414{
1415 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1416 auto ptrs = bsearch_dup(a, 1);
1417 ASSERT_EQ(ptrs.size(), 3u);
1418 for (auto p : ptrs)
1419 ASSERT_NE(p, nullptr);
1420
1421 auto idxs = binindex_dup(a, 1);
1422 ASSERT_EQ(idxs.size(), 3u);
1423 EXPECT_EQ(idxs.get_first(), 1);
1424 EXPECT_EQ(idxs.get_last(), 3);
1425}
1426
1428{
1429 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1431 ptrs.reserve(a.size());
1432 for (size_t i = 0; i < a.size(); ++i)
1433 ptrs(i) = &a(i);
1434
1435 auto dup = bsearch_dup(ptrs, 3, Aleph::greater<int>());
1436 ASSERT_EQ(dup.size(), 3u);
1437 for (auto p : dup)
1438 {
1439 ASSERT_NE(p, nullptr);
1440 EXPECT_EQ(*p, 3);
1441 }
1442}
1443
1445{
1446 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1448 ptrs.reserve(a.size());
1449 for (size_t i = 0; i < a.size(); ++i)
1450 ptrs(i) = &a(i);
1451
1453 ASSERT_EQ(idxs.size(), 3u);
1454 EXPECT_EQ(idxs.get_first(), 2);
1455 EXPECT_EQ(idxs.get_last(), 4);
1456}
1457
1459{
1460 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1462 ptrs.reserve(a.size());
1463 for (size_t i = 0; i < a.size(); ++i)
1464 ptrs(i) = &a(i);
1465
1466 auto found = bsearch(ptrs, 1);
1467 ASSERT_NE(found, nullptr);
1468 EXPECT_EQ(*found, 1);
1469
1470 auto dup = bsearch_dup(ptrs, 1);
1471 ASSERT_EQ(dup.size(), 3u);
1472 for (auto p : dup)
1473 {
1474 ASSERT_NE(p, nullptr);
1475 EXPECT_EQ(*p, 1);
1476 }
1477}
1478
1480{
1481 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1483 ptrs.reserve(a.size());
1484 for (size_t i = 0; i < a.size(); ++i)
1485 ptrs(i) = &a(i);
1486
1487 auto idxs = binindex_dup(ptrs, 1);
1488 ASSERT_EQ(idxs.size(), 3u);
1489 EXPECT_EQ(idxs.get_first(), 1);
1490 EXPECT_EQ(idxs.get_last(), 3);
1491}
1492
1494{
1495 auto a = make_dynarray({5, 4, 3, 2, 1, 0});
1497 ptrs.reserve(a.size());
1498 for (size_t i = 0; i < a.size(); ++i)
1499 ptrs(i) = &a(i);
1500
1501 // The container is sorted in descending order, so we must use greater<int>
1505}
1506
1508{
1509 auto a = make_dynarray({0, 1, 2, 3, 4, 5});
1511 ptrs.reserve(a.size());
1512 for (size_t i = 0; i < a.size(); ++i)
1513 ptrs(i) = &a(i);
1514
1515 // search only in [2..4] => values {2,3,4}
1516 EXPECT_EQ(binary_search(ptrs, 3, 2, 4), 3);
1517
1518 // insertion points within the restricted range
1519 EXPECT_EQ(binary_search(ptrs, 1, 2, 4), 2);
1520 EXPECT_EQ(binary_search(ptrs, 5, 2, 4), 5);
1521}
1522
1524{
1525 auto a = make_dynarray({5, 4, 3, 2, 1, 0});
1527 ptrs.reserve(a.size());
1528 for (size_t i = 0; i < a.size(); ++i)
1529 ptrs(i) = &a(i);
1530
1531 // search only in [1..3] => values {4,3,2} under greater<int>
1533
1534 // insertion points within the restricted range for descending order
1535 // 5 would be inserted before 4 => at l
1537 // 0 would be inserted after 2 => at r+1
1539}
1540
1542{
1545 sa[0] = 3; sa[1] = 0; sa[2] = 4; sa[3] = 1; sa[4] = 2;
1546
1547 counting_sort_indices(sa, tmp, 5, 0, 4,
1548 [](size_t idx) -> int { return static_cast<int>(idx); });
1549
1550 for (size_t i = 0; i < 5; ++i)
1551 EXPECT_EQ(sa[i], i);
1552}
1553
1563{
1564 // Two pairs with same key: (10,key=1) and (20,key=1)
1565 // Original order: indices 0(key=2), 1(key=1), 2(key=1), 3(key=0)
1568 sa[0] = 0; sa[1] = 1; sa[2] = 2; sa[3] = 3;
1569
1570 std::array<int, 4> keys = {2, 1, 1, 0};
1571 counting_sort_indices(sa, tmp, 4, 0, 2,
1572 [&](size_t idx) -> int { return keys[idx]; });
1573
1574 // Expected: 3(key=0), 1(key=1), 2(key=1), 0(key=2)
1575 EXPECT_EQ(sa[0], 3u);
1576 EXPECT_EQ(sa[1], 1u); // stable: 1 before 2
1577 EXPECT_EQ(sa[2], 2u);
1578 EXPECT_EQ(sa[3], 0u);
1579}
1580
1582{
1585 sa[0] = 0; sa[1] = 1; sa[2] = 2; sa[3] = 3;
1586
1587 std::array<int, 4> keys = {0, -1, 2, -2};
1588 counting_sort_indices(sa, tmp, 4, -2, 2,
1589 [&](size_t idx) -> int { return keys[idx]; });
1590
1591 // Sorted by key: 3(-2), 1(-1), 0(0), 2(2)
1592 EXPECT_EQ(sa[0], 3u);
1593 EXPECT_EQ(sa[1], 1u);
1594 EXPECT_EQ(sa[2], 0u);
1595 EXPECT_EQ(sa[3], 2u);
1596}
1597
1599{
1602 sa[0] = 42;
1603
1604 counting_sort_indices(sa, tmp, 1, 0, 0,
1605 [](size_t) -> int { return 0; });
1606 EXPECT_EQ(sa[0], 42u);
1607}
1608
1610{
1611 Array<size_t> sa;
1613 counting_sort_indices(sa, tmp, 0, 0, 0,
1614 [](size_t) -> int { return 0; });
1615 EXPECT_TRUE(sa.is_empty());
1616}
1617
1619{
1622 sa[0] = 0;
1623
1625 counting_sort_indices(sa, tmp, 1, 3, 2,
1626 [](size_t) -> int { return 0; }),
1627 std::domain_error);
1628}
1629
1631{
1634 sa[0] = 0;
1635 sa[1] = 1;
1636
1638 counting_sort_indices(sa, tmp, 2, 0, 1,
1639 [](size_t idx) -> int { return idx == 0 ? 0 : 2; }),
1640 std::out_of_range);
1641}
1642
1644{
1647 sa[0] = 0;
1648
1650 counting_sort_indices(sa, tmp, 2, 0, 1,
1651 [](size_t idx) -> int { return static_cast<int>(idx); }),
1652 std::out_of_range);
1653}
1654
1656{
1657 auto a = make_dynarray({5, -2, 3, -2, 0, 9, -10});
1658 counting_sort(a);
1659 EXPECT_EQ(a(0), -10);
1660 EXPECT_EQ(a(1), -2);
1661 EXPECT_EQ(a(2), -2);
1662 for (size_t i = 1; i < a.size(); ++i)
1663 ASSERT_LE(a(i - 1), a(i));
1664}
1665
1667{
1669 for (unsigned int x : {7u, 0u, 3u, 7u, 1u, 2u})
1670 a.append(x);
1671
1672 counting_sort(a);
1673 EXPECT_EQ(a(0), 0u);
1674 EXPECT_EQ(a(1), 1u);
1675 EXPECT_EQ(a(2), 2u);
1676 EXPECT_EQ(a(3), 3u);
1677 EXPECT_EQ(a(4), 7u);
1678 EXPECT_EQ(a(5), 7u);
1679}
1680
1682{
1683 int a[] = {4, 1, 3, 0, 2};
1684 counting_sort(a, sizeof(a) / sizeof(a[0]));
1685 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1686
1687 EXPECT_THROW((counting_sort<int>(nullptr, 1)), std::invalid_argument);
1688 EXPECT_NO_THROW((counting_sort<int>(nullptr, 0)));
1689}
1690
1692{
1693 int a[] = {5, 1, 4, 2, 3, 0};
1694 counting_sort(a);
1695 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1696}
1697
1699{
1700 auto a = make_dynarray({9, -1, 3, 0, -1, 2});
1701 counting_sort(a);
1702 for (size_t i = 1; i < a.size(); ++i)
1703 ASSERT_LE(a(i - 1), a(i));
1704 ASSERT_EQ(a.size(), 6u);
1705 EXPECT_EQ(a(0), -1);
1706 EXPECT_EQ(a(1), -1);
1707 EXPECT_EQ(a(5), 9);
1708}
1709
1711{
1712 DynArray<int> d;
1713 counting_sort(d);
1714 EXPECT_TRUE(d.is_empty());
1715
1716 Array<int> a;
1717 a.append(7);
1718 counting_sort(a);
1719 ASSERT_EQ(a.size(), 1u);
1720 EXPECT_EQ(a(0), 7);
1721}
1722
1724{
1725 DynList<int> l = make_dynlist({4, -1, 3, 0, -1, 2});
1727
1728 std::array<int, 6> expected = {-1, -1, 0, 2, 3, 4};
1729 size_t i = 0;
1730 for (DynList<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
1731 EXPECT_EQ(it.get_curr(), expected[i]);
1732 EXPECT_EQ(i, expected.size());
1733}
1734
1736{
1737 DynList<int> l = make_dynlist({4, -1, 3, 0, -1, 2});
1738 const auto before = dynlist_node_addresses(l);
1740 const auto after = dynlist_node_addresses(l);
1742}
1743
1745{
1746 DynDlist<int> l = make_dyndlist({7, 3, 7, 1, 0, -2});
1748
1749 std::array<int, 6> expected = {-2, 0, 1, 3, 7, 7};
1750 size_t i = 0;
1751 for (DynDlist<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
1752 EXPECT_EQ(it.get_curr(), expected[i]);
1753 EXPECT_EQ(i, expected.size());
1754}
1755
1757{
1758 DynDlist<int> l = make_dyndlist({7, 3, 7, 1, 0, -2});
1759 const auto before = dyndlist_node_addresses(l);
1761 const auto after = dyndlist_node_addresses(l);
1763}
1764
1766{
1768 a.reserve(2);
1769 a(0) = 0ull;
1770 a(1) = std::numeric_limits<unsigned long long>::max();
1771 EXPECT_THROW(counting_sort(a), std::runtime_error);
1772}
1773
1775{
1776 auto a = make_dynarray({170, 45, 75, 90, 802, 24, 2, 66});
1777 radix_sort(a);
1778 for (size_t i = 1; i < a.size(); ++i)
1779 ASSERT_LE(a(i - 1), a(i));
1780}
1781
1783{
1784 auto a = make_dynarray({0, -1, 5, -10, 3, -1, 2});
1785 radix_sort(a);
1786 EXPECT_EQ(a(0), -10);
1787 EXPECT_EQ(a(1), -1);
1788 EXPECT_EQ(a(2), -1);
1789 for (size_t i = 1; i < a.size(); ++i)
1790 ASSERT_LE(a(i - 1), a(i));
1791}
1792
1794{
1795 Array<int> a;
1796 for (int x : {9, 1, 8, 2, 7, 3, 6, 4, 5, 0})
1797 a.append(x);
1798
1799 radix_sort(a);
1800 for (size_t i = 1; i < a.size(); ++i)
1801 ASSERT_LE(a(i - 1), a(i));
1802}
1803
1805{
1806 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
1807 radix_sort(a, sizeof(a) / sizeof(a[0]));
1808 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1809}
1810
1812{
1813 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
1814 radix_sort(a);
1815 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1816}
1817
1819{
1820 EXPECT_THROW((radix_sort<int>(nullptr, 1)), std::invalid_argument);
1821 EXPECT_NO_THROW((radix_sort<int>(nullptr, 0)));
1822}
1823
1825{
1826 DynList<int> l = make_dynlist({3, -1, 2, -5, 0, 3});
1827 radix_sort(l);
1828
1829 std::array<int, 6> expected = {-5, -1, 0, 2, 3, 3};
1830 size_t i = 0;
1831 for (DynList<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
1832 EXPECT_EQ(it.get_curr(), expected[i]);
1833 EXPECT_EQ(i, expected.size());
1834}
1835
1837{
1838 DynList<int> l = make_dynlist({3, -1, 2, -5, 0, 3});
1839 const auto before = dynlist_node_addresses(l);
1840 radix_sort(l);
1841 const auto after = dynlist_node_addresses(l);
1843}
1844
1846{
1847 DynDlist<int> l = make_dyndlist({10, -2, 7, 0, -2, 1});
1848 radix_sort(l);
1849
1850 std::array<int, 6> expected = {-2, -2, 0, 1, 7, 10};
1851 size_t i = 0;
1852 for (DynDlist<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
1853 EXPECT_EQ(it.get_curr(), expected[i]);
1854 EXPECT_EQ(i, expected.size());
1855}
1856
1858{
1859 DynDlist<int> l = make_dyndlist({10, -2, 7, 0, -2, 1});
1860 const auto before = dyndlist_node_addresses(l);
1861 radix_sort(l);
1862 const auto after = dyndlist_node_addresses(l);
1864}
1865
1867{
1868 DynArray<int> a;
1869 a.reserve(6);
1870 a(0) = std::numeric_limits<int>::max();
1871 a(1) = 0;
1872 a(2) = std::numeric_limits<int>::min();
1873 a(3) = -1;
1874 a(4) = std::numeric_limits<int>::max();
1875 a(5) = std::numeric_limits<int>::min();
1876
1877 radix_sort(a);
1878
1879 EXPECT_EQ(a(0), std::numeric_limits<int>::min());
1880 EXPECT_EQ(a(1), std::numeric_limits<int>::min());
1881 EXPECT_EQ(a(4), std::numeric_limits<int>::max());
1882 EXPECT_EQ(a(5), std::numeric_limits<int>::max());
1883 for (size_t i = 1; i < a.size(); ++i)
1884 ASSERT_LE(a(i - 1), a(i));
1885}
1886
1888{
1890 for (unsigned int x : {std::numeric_limits<unsigned int>::max(),
1891 0u, 10u, 1u, 1024u, 10u})
1892 a.append(x);
1893
1894 radix_sort(a);
1895
1896 EXPECT_EQ(a(0), 0u);
1897 EXPECT_EQ(a(1), 1u);
1898 EXPECT_EQ(a(2), 10u);
1899 EXPECT_EQ(a(3), 10u);
1900 EXPECT_EQ(a(a.size() - 1), std::numeric_limits<unsigned int>::max());
1901 for (size_t i = 1; i < a.size(); ++i)
1902 ASSERT_LE(a(i - 1), a(i));
1903}
1904
1906{
1907 DynArray<int> d;
1908 radix_sort(d);
1909 EXPECT_EQ(d.size(), 0u);
1910
1911 Array<int> a;
1912 a.append(7);
1913 radix_sort(a);
1914 ASSERT_EQ(a.size(), 1u);
1915 EXPECT_EQ(a(0), 7);
1916}
1917
1919{
1920 DynArray<int> v = make_dynarray({9, 2, 4, 7, 3, 7, 10, 2, 7, 1, 8, 7, 7, 7, 7});
1921 std::vector<int> expected = {9, 2, 4, 7, 3, 7, 10, 2, 7, 1, 8, 7, 7, 7, 7};
1922 std::sort(expected.begin(), expected.end());
1923
1924 for (size_t i = 0; i < v.size(); ++i)
1925 {
1926 DynArray<int> copy = v;
1927 int res = Aleph::random_select(&copy(0), static_cast<long>(i), static_cast<long>(copy.size()), std::less<int>());
1928 EXPECT_EQ(res, expected[i]) << "Mismatch at index " << i;
1929 }
1930}
1931
1933{
1934 DynArray<int> v;
1935 for (int i = 0; i < 100; ++i)
1936 v.append(42);
1937
1938 for (size_t i = 0; i < v.size(); i += 10)
1939 {
1940 DynArray<int> copy = v;
1941 int res = Aleph::random_select(&copy(0), static_cast<long>(i), static_cast<long>(copy.size()), std::less<int>());
1942 EXPECT_EQ(res, 42) << "Mismatch at index " << i;
1943 }
1944}
1945
1947{
1948 DynArray<int> v;
1949 for (int i = 0; i < 50; ++i)
1950 v.append(i);
1951
1952 DynArray<int> rev;
1953 for (int i = 49; i >= 0; --i)
1954 rev.append(i);
1955
1956 for (size_t i = 0; i < v.size(); i += 5)
1957 {
1959 DynArray<int> copy_rev = rev;
1960
1961 EXPECT_EQ(Aleph::random_select(&copy_v(0), static_cast<long>(i), static_cast<long>(copy_v.size()), std::less<int>()), static_cast<int>(i));
1962 EXPECT_EQ(Aleph::random_select(&copy_rev(0), static_cast<long>(i), static_cast<long>(copy_rev.size()), std::less<int>()), static_cast<int>(i));
1963 }
1964}
1965
1967{
1968 std::mt19937 gen(42);
1969 for (int iter = 0; iter < 100; ++iter)
1970 {
1971 const size_t N = std::uniform_int_distribution<size_t>(1, 200)(gen);
1972 DynArray<int> a;
1973 std::vector<int> expected;
1974 for (size_t i = 0; i < N; ++i)
1975 {
1976 int val = std::uniform_int_distribution<int>(-1000, 1000)(gen);
1977 a.append(val);
1978 expected.push_back(val);
1979 }
1980 std::sort(expected.begin(), expected.end());
1981
1982 const long k = std::uniform_int_distribution<long>(0, static_cast<long>(N) - 1)(gen);
1983 DynArray<int> copy = a;
1984 int res = Aleph::random_select(&copy(0), k, static_cast<long>(N), std::less<int>());
1985 EXPECT_EQ(res, expected[k]) << "Mismatch at iter " << iter << " rank " << k << " N " << N;
1986 }
1987}
1988
1989// ================================================================
1990// Bucket Sort Tests
1991// ================================================================
1992
1994{
1995 constexpr size_t N = 500;
1997 a.reserve(N);
1998 std::mt19937 gen(42);
1999 std::uniform_real_distribution<float> dist(0.0f, 1.0f);
2000 for (size_t i = 0; i < N; ++i)
2001 a(i) = dist(gen);
2002
2003 bucket_sort(a);
2004 for (size_t i = 1; i < N; ++i)
2005 ASSERT_LE(a(i - 1), a(i));
2006}
2007
2009{
2010 constexpr size_t N = 300;
2012 a.reserve(N);
2013 std::mt19937 gen(123);
2014 std::uniform_real_distribution<float> dist(-100.0f, 100.0f);
2015 for (size_t i = 0; i < N; ++i)
2016 a(i) = dist(gen);
2017
2018 bucket_sort(a);
2019 for (size_t i = 1; i < N; ++i)
2020 ASSERT_LE(a(i - 1), a(i));
2021}
2022
2024{
2025 constexpr size_t N = 200;
2027 a.reserve(N);
2028 std::mt19937 gen(77);
2029 std::uniform_real_distribution<double> dist(-50.0, 50.0);
2030 for (size_t i = 0; i < N; ++i)
2031 a(i) = dist(gen);
2032
2033 bucket_sort(a);
2034 for (size_t i = 1; i < N; ++i)
2035 ASSERT_LE(a(i - 1), a(i));
2036}
2037
2039{
2040 constexpr size_t N = 100;
2042 a.reserve(N);
2043 std::mt19937 gen(99);
2044 std::uniform_real_distribution<double> dist(-10.0, 10.0);
2045 for (size_t i = 0; i < N; ++i)
2046 a(i) = dist(gen);
2047
2049 for (size_t i = 1; i < N; ++i)
2050 ASSERT_GE(a(i - 1), a(i)) << "Failed at index " << i << " values: " << a(i-1) << ", " << a(i);
2051}
2052
2054{
2055 int a[] = {95, 23, 67, 12, 45, 78, 34, 56, 89, 1};
2056 const size_t n = sizeof(a) / sizeof(a[0]);
2057 const size_t num_buckets = 10;
2058
2059 auto key = [](const int & val) -> size_t
2060 {
2061 return static_cast<size_t>(val / 10);
2062 };
2063
2064 bucket_sort(a, n, num_buckets, key);
2065 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2066}
2067
2069{
2070 struct MoveOnlyInt
2071 {
2072 int value = 0;
2073
2074 MoveOnlyInt() = default;
2075 explicit MoveOnlyInt(const int v) : value(v) {}
2076 MoveOnlyInt(const MoveOnlyInt &) = delete;
2077 MoveOnlyInt & operator = (const MoveOnlyInt &) = delete;
2080 };
2081
2084
2085 MoveOnlyInt a[] = {
2088 };
2089 const size_t n = sizeof(a) / sizeof(a[0]);
2090 const size_t num_buckets = 4;
2091 auto key = [](const MoveOnlyInt & x) -> size_t
2092 {
2093 return static_cast<size_t>(x.value / 2);
2094 };
2095 auto cmp = [](const MoveOnlyInt & lhs, const MoveOnlyInt & rhs)
2096 {
2097 return lhs.value < rhs.value;
2098 };
2099
2100 bucket_sort(a, n, num_buckets, key, cmp);
2101
2102 for (size_t i = 1; i < n; ++i)
2103 ASSERT_LE(a[i - 1].value, a[i].value);
2104}
2105
2107{
2108 constexpr size_t N = 100;
2110 a.reserve(N);
2111 std::mt19937 gen(55);
2112 std::uniform_real_distribution<double> dist(0.0, 1.0);
2113 for (size_t i = 0; i < N; ++i)
2114 a(i) = dist(gen);
2115
2116 bucket_sort(a);
2117 for (size_t i = 1; i < N; ++i)
2118 ASSERT_LE(a(i - 1), a(i));
2119}
2120
2122{
2123 Array<double> a;
2124 std::mt19937 gen(99);
2125 std::uniform_real_distribution<double> dist(-10.0, 10.0);
2126 for (size_t i = 0; i < 50; ++i)
2127 a.append(dist(gen));
2128
2129 bucket_sort(a);
2130 for (size_t i = 1; i < a.size(); ++i)
2131 ASSERT_LE(a(i - 1), a(i));
2132}
2133
2135{
2136 double a[] = {3.5, 1.2, 4.8, 0.3, 2.7, 1.9, 4.1, 0.1};
2137 bucket_sort(a);
2138 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2139}
2140
2142{
2144 l.append(3.5);
2145 l.append(1.2);
2146 l.append(4.8);
2147 l.append(0.3);
2148 l.append(2.7);
2149
2150 bucket_sort(l);
2151
2152 double prev = -std::numeric_limits<double>::infinity();
2153 for (DynList<double>::Iterator it(l); it.has_curr(); it.next())
2154 {
2155 EXPECT_GE(it.get_curr(), prev);
2156 prev = it.get_curr();
2157 }
2158}
2159
2161{
2163 bucket_sort(d);
2164 EXPECT_EQ(d.size(), 0u);
2165
2167 s.reserve(1);
2168 s(0) = 42.0f;
2169 bucket_sort(s);
2170 ASSERT_EQ(s.size(), 1u);
2171 EXPECT_FLOAT_EQ(s(0), 42.0f);
2172}
2173
2175{
2176 constexpr size_t N = 50;
2178 a.reserve(N);
2179 for (size_t i = 0; i < N; ++i)
2180 a(i) = 7.7f;
2181
2182 bucket_sort(a);
2183 for (size_t i = 0; i < N; ++i)
2184 EXPECT_FLOAT_EQ(a(i), 7.7f);
2185}
2186
2188{
2189 constexpr size_t N = 100;
2191 a.reserve(N);
2192 for (size_t i = 0; i < N; ++i)
2193 a(i) = static_cast<double>(N - i);
2194
2195 bucket_sort(a);
2196 for (size_t i = 1; i < N; ++i)
2197 ASSERT_LE(a(i - 1), a(i));
2198}
2199
2201{
2202 EXPECT_THROW((bucket_sort<float>(nullptr, 1)), std::invalid_argument);
2203 EXPECT_NO_THROW((bucket_sort<float>(nullptr, 0)));
2204}
2205
2207{
2208 // Records with same bucket should preserve relative order
2209 struct Record
2210 {
2211 int group;
2212 int seq;
2213 };
2214
2215 Record data[] = {{0, 0}, {2, 1}, {0, 2}, {1, 3}, {2, 4}, {1, 5}};
2216 const size_t n = sizeof(data) / sizeof(data[0]);
2217 const size_t num_buckets = 3;
2218
2219 auto key = [](const Record & r) -> size_t { return r.group; };
2220 auto cmp = [](const Record & a, const Record & b) { return a.group < b.group; };
2221
2222 bucket_sort(data, n, num_buckets, key, cmp);
2223
2224 // Verify sorted by group
2225 for (size_t i = 1; i < n; ++i)
2226 ASSERT_LE(data[i - 1].group, data[i].group);
2227
2228 // Verify stability: within same group, original order preserved
2229 // Group 0: seq 0, 2
2230 EXPECT_EQ(data[0].seq, 0);
2231 EXPECT_EQ(data[1].seq, 2);
2232 // Group 1: seq 3, 5
2233 EXPECT_EQ(data[2].seq, 3);
2234 EXPECT_EQ(data[3].seq, 5);
2235 // Group 2: seq 1, 4
2236 EXPECT_EQ(data[4].seq, 1);
2237 EXPECT_EQ(data[5].seq, 4);
2238}
2239
2240
2242{
2243 int a[] = {3, 1, 2};
2244 const size_t n = 3;
2245 const size_t num_buckets = 0;
2246 auto key = [](const int &) -> size_t { return 0; };
2247
2248 // Zero buckets with n >= 2 must throw domain_error
2249 EXPECT_THROW(bucket_sort(a, n, num_buckets, key), std::domain_error);
2250}
2251
2252// ================================================================
2253// Timsort Tests
2254// ================================================================
2255
2257{
2258 constexpr size_t N = 200;
2259 DynArray<int> a;
2260 a.reserve(N);
2261 for (size_t i = 0; i < N; ++i)
2262 a(i) = static_cast<int>(i);
2263
2264 timsort(a);
2265 for (size_t i = 1; i < N; ++i)
2266 ASSERT_LE(a(i - 1), a(i));
2267}
2268
2270{
2271 constexpr size_t N = 200;
2272 DynArray<int> a;
2273 a.reserve(N);
2274 for (size_t i = 0; i < N; ++i)
2275 a(i) = static_cast<int>(N - i);
2276
2277 timsort(a);
2278 for (size_t i = 1; i < N; ++i)
2279 ASSERT_LE(a(i - 1), a(i));
2280}
2281
2283{
2284 int a[] = {5, 3, 8, 1, 9, 2, 7, 4, 6, 0};
2285 timsort(static_cast<int*>(a), size_t{10});
2286 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2287}
2288
2290{
2291 constexpr size_t N = 10000;
2292 DynArray<int> a;
2293 a.reserve(N);
2294 std::mt19937 gen(42);
2295 std::uniform_int_distribution<int> dist(-1000000, 1000000);
2296 for (size_t i = 0; i < N; ++i)
2297 a(i) = dist(gen);
2298
2299 timsort(a);
2300 for (size_t i = 1; i < N; ++i)
2301 ASSERT_LE(a(i - 1), a(i));
2302}
2303
2305{
2306 if (not std::getenv("ENABLE_PERF_TESTS"))
2307 GTEST_SKIP() << "Skipping perf test (set ENABLE_PERF_TESTS to enable)";
2308
2309 constexpr size_t N = 100000;
2310 DynArray<int> a;
2311 a.reserve(N);
2312 std::mt19937 gen(42);
2313 std::uniform_int_distribution<int> dist(-1000000, 1000000);
2314 for (size_t i = 0; i < N; ++i)
2315 a(i) = dist(gen);
2316
2317 auto start = std::chrono::steady_clock::now();
2318 timsort(a);
2319 auto end = std::chrono::steady_clock::now();
2320
2321 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
2322
2323 long max_ms = 500;
2324 if (const char * env_ms = std::getenv("TIMSORT_MAX_MS"))
2325 max_ms = std::atol(env_ms);
2326
2327 EXPECT_LE(duration, max_ms) << "Timsort performance regression detected";
2328
2329 for (size_t i = 1; i < N; ++i)
2330 ASSERT_LE(a(i - 1), a(i));
2331}
2332
2334{
2335 constexpr size_t N = 100;
2336 DynArray<int> a;
2337 a.reserve(N);
2338 for (size_t i = 0; i < N; ++i)
2339 a(i) = 42;
2340
2341 timsort(a);
2342 for (size_t i = 0; i < N; ++i)
2343 EXPECT_EQ(a(i), 42);
2344}
2345
2347{
2348 constexpr size_t N = 200;
2349 DynArray<int> a;
2350 a.reserve(N);
2351 // First half: 0, 2, 4, ... 198
2352 for (size_t i = 0; i < N / 2; ++i)
2353 a(i) = static_cast<int>(i * 2);
2354 // Second half: 1, 3, 5, ... 199
2355 for (size_t i = N / 2; i < N; ++i)
2356 a(i) = static_cast<int>((i - N / 2) * 2 + 1);
2357
2358 timsort(a);
2359 for (size_t i = 1; i < N; ++i)
2360 ASSERT_LE(a(i - 1), a(i));
2361}
2362
2364{
2365 constexpr size_t N = 50;
2366 DynArray<int> a;
2367 a.reserve(N);
2368 std::mt19937 gen(99);
2369 for (size_t i = 0; i < N; ++i)
2370 a(i) = static_cast<int>(gen() % 1000);
2371
2373 for (size_t i = 1; i < N; ++i)
2374 ASSERT_GE(a(i - 1), a(i));
2375}
2376
2378{
2379 auto a = make_dynarray({9, 1, 8, 2, 7, 3, 6, 4, 5, 0});
2380 timsort(a);
2381 for (size_t i = 1; i < a.size(); ++i)
2382 ASSERT_LE(a(i - 1), a(i));
2383}
2384
2386{
2387 Array<int> a;
2388 for (int x : {9, 1, 8, 2, 7, 3, 6, 4, 5, 0})
2389 a.append(x);
2390
2391 timsort(a);
2392 for (size_t i = 1; i < a.size(); ++i)
2393 ASSERT_LE(a(i - 1), a(i));
2394}
2395
2397{
2398 int a[] = {5, 3, 8, 1, 9, 2, 7, 4, 6, 0};
2399 timsort(a);
2400 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2401}
2402
2404{
2405 DynList<int> l = make_dynlist({5, 3, 8, 1, 9, 2, 7, 4, 6, 0});
2406 timsort(l);
2407
2408 int prev = std::numeric_limits<int>::min();
2409 for (DynList<int>::Iterator it(l); it.has_curr(); it.next())
2410 {
2411 EXPECT_GE(it.get_curr(), prev);
2412 prev = it.get_curr();
2413 }
2414}
2415
2417{
2418 DynArray<int> d;
2419 timsort(d);
2420 EXPECT_EQ(d.size(), 0u);
2421
2422 Array<int> a;
2423 a.append(7);
2424 timsort(a);
2425 ASSERT_EQ(a.size(), 1u);
2426 EXPECT_EQ(a(0), 7);
2427}
2428
2430{
2431 EXPECT_THROW((timsort<int>(nullptr, 1)), std::invalid_argument);
2432 EXPECT_NO_THROW((timsort<int>(nullptr, 0)));
2433}
2434
2436{
2437 struct Record
2438 {
2439 int key;
2440 int seq; // original order
2441 bool operator<(const Record & rhs) const { return key < rhs.key; }
2442 };
2443
2444 Record data[] = {
2445 {3, 0}, {1, 1}, {4, 2}, {1, 3}, {5, 4},
2446 {9, 5}, {2, 6}, {6, 7}, {5, 8}, {3, 9}
2447 };
2448 const size_t n = sizeof(data) / sizeof(data[0]);
2449
2450 auto cmp = [](const Record & a, const Record & b) { return a.key < b.key; };
2451 timsort(data, n, cmp);
2452
2453 // Verify sorted by key
2454 for (size_t i = 1; i < n; ++i)
2455 ASSERT_LE(data[i - 1].key, data[i].key);
2456
2457 // Verify stability: equal keys preserve original seq order
2458 for (size_t i = 1; i < n; ++i)
2459 if (data[i - 1].key == data[i].key)
2460 EXPECT_LT(data[i - 1].seq, data[i].seq)
2461 << "Stability violated at index " << i;
2462}
2463
2465{
2467 a.append("banana");
2468 a.append("apple");
2469 a.append("cherry");
2470 a.append("date");
2471 a.append("apricot");
2472
2474
2475 EXPECT_EQ(a(0), "apple");
2476 EXPECT_EQ(a(1), "apricot");
2477 EXPECT_EQ(a(2), "banana");
2478 EXPECT_EQ(a(3), "cherry");
2479 EXPECT_EQ(a(4), "date");
2480}
2481
2482TEST(Timsort, nearly_sorted)
2483{
2484 constexpr size_t N = 500;
2485 DynArray<int> a;
2486 a.reserve(N);
2487 for (size_t i = 0; i < N; ++i)
2488 a(i) = static_cast<int>(i);
2489
2490 // Introduce a few inversions
2491 std::mt19937 gen(12);
2492 for (int k = 0; k < 10; ++k)
2493 {
2494 size_t i = gen() % N;
2495 size_t j = gen() % N;
2496 std::swap(a(i), a(j));
2497 }
2498
2499 timsort(a);
2500 for (size_t i = 1; i < N; ++i)
2501 ASSERT_LE(a(i - 1), a(i));
2502}
2503
2505{
2506 int a[] = {9, 5, 3, 8, 1, 7, 2, 6, 4, 0};
2507 // Sort only the subrange [2, 7] (inclusive)
2508 timsort(a, 2L, 7L);
2509
2510 // a[2..7] should be sorted
2511 for (int i = 3; i <= 7; ++i)
2512 ASSERT_LE(a[i - 1], a[i]);
2513
2514 // Elements outside the range should be unchanged
2515 EXPECT_EQ(a[0], 9);
2516 EXPECT_EQ(a[1], 5);
2517 EXPECT_EQ(a[8], 4);
2518 EXPECT_EQ(a[9], 0);
2519}
2520
2521TEST(Timsort, compute_minrun)
2522{
2524
2525 // n < 64: minrun == n
2526 EXPECT_EQ(compute_minrun(1), 1u);
2527 EXPECT_EQ(compute_minrun(32), 32u);
2528 EXPECT_EQ(compute_minrun(63), 63u);
2529
2530 // n == 64: minrun == 32
2531 EXPECT_EQ(compute_minrun(64), 32u);
2532
2533 // minrun should always be in [32, 64] for n >= 64
2534 for (size_t n = 64; n < 10000; ++n)
2535 {
2536 const size_t mr = compute_minrun(n);
2537 EXPECT_GE(mr, 32u) << "n=" << n;
2538 EXPECT_LE(mr, 64u) << "n=" << n;
2539 }
2540}
2541
2542} // namespace
static DynArray< int > make_dynarray(std::initializer_list< int > vals)
bool operator<(const Time &l, const Time &r)
Definition ah-time.H:142
static bool is_min_heap(const std::vector< int > &v)
long double h
Definition btreepic.C:154
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:348
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
Helper class to compare nodes of a linked list.
Iterator on a list of Dnode objects.
Definition tpl_dnode.H:261
Node belonging to a double circular linked list with header node.
Definition tpl_dnode.H:106
Dnode< T > * remove_first_ne() noexcept
Remove the first node and return its address.
Definition tpl_dnode.H:152
size_t size() const noexcept
Return the current dimension of array.
T & append()
Allocate a new entry to the end of array.
bool is_empty() const noexcept
Return true if the array is empty.
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
Iterator dynamic list.
Dynamic doubly linked list with O(1) size and bidirectional access.
Iterator on the items of list.
Definition htlist.H:1420
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
T & get_last() const
Return the last item of the list.
Definition htlist.H:1363
T & get_first() const
Return the first item of the list.
Definition htlist.H:1375
Fixed length stack.
bool has_curr() const noexcept
Definition htlist.H:930
Single linked list of nodes.
Definition htlist.H:403
constexpr bool is_empty() const noexcept
Definition htlist.H:419
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Comparator wrapper that inverts the comparison order.
Link of a single linked list non-circular and without header node.
Definition htlist.H:95
constexpr bool is_empty() const noexcept
Return true if this is empty.
Definition htlist.H:103
Slinknc * remove_next() noexcept
Definition htlist.H:156
void insert(Slinknc *p) noexcept
insert(p) inserts the node pointed by p after this.
Definition htlist.H:143
#define TEST(name)
#define N
Definition fib.C:294
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
constexpr size_t compute_minrun(size_t n) noexcept
Compute the minimum run length for timsort.
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())
Binary search for all occurrences of a value.
and std::convertible_to< std::invoke_result_t< const KeyFn &, size_t >, int > void counting_sort_indices(Array< size_t > &sa, Array< size_t > &tmp, const size_t n, const int min_key, const int max_key, const KeyFn &key_of)
Stable counting sort on an index array by integer keys.
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.
std::pair< bool, size_t > search_inversion(const Container< T > &cont, const Compare &cmp=Compare())
Find the first inversion in a container.
Dnode< T > * dlink_random_search(Dlink &list, const T &x, const Compare &cmp=Compare())
Random search for an element in a dlink list.
void quicksort_no_tail(T *a, long l, long r, const Compare &cmp=Compare())
Quicksort implementation with tail-recursion optimization.
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.
void insertion_sort(T *a, const long l, const long r, const Compare &cmp=Compare()) noexcept(noexcept(cmp(std::declval< T & >(), std::declval< T & >())) and std::is_nothrow_move_constructible_v< T > and std::is_nothrow_move_assignable_v< T >)
Sort an array using insertion sort.
const int Not_Found
Return value for search functions when element is not found.
void counting_sort(DynArray< T > &a)
Stable counting sort for integral DynArray values.
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.
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 timsort(T *a, const size_t n, const Compare &cmp=Compare())
Timsort — adaptive, stable, natural merge sort.
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 on Dlink.
void heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Sort an array using the heapsort algorithm.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
void mergesort(T *a, const long l, const long r, std::vector< T > &buf, Compare cmp)
Sort an array using merge sort with a reusable buffer.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
T * bsearch(C< T > &a, const T &x, const Compare &cmp=Compare())
Search for a value in a sorted container returning a pointer.
DynArray< size_t > build_index(const C< T > &a, const Compare &cmp=Compare())
Build an index array for indirect sorting.
const T & random_select(DynArray< T > &a, const long i, const Compare &cmp=Compare())
Select the i-th smallest element in a DynArray.
void bucket_sort(T *a, const size_t n, const size_t num_buckets, const BucketKey &bucket_key, const Compare &cmp=Compare())
Bucket sort with user-supplied bucket mapping.
static long back_index(const long i) noexcept
Convert a 1-based heap index to a 0-based array index.
void bubble_sort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using bubble sort.
void quicksort(T *a, const long l, const long r, const Compare &cmp=Compare())
Sort an array using iterative quicksort with optimizations.
void radix_sort(DynArray< T > &a)
LSD radix sort for integral DynArray values.
void shellsort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using Shell sort.
DynArray< const T * > build_index_ptr(const C< T > &a, const Compare &cmp=Compare())
Build an index array of pointers for indirect sorting (const version).
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
static const T & __random_select(T *a, const long i, long l, long r, const Compare &cmp)
void quicksort_rec(T *a, const long l, const long r, const Compare &cmp=Compare())
Recursively sort an array using quicksort.
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.
DynList< const T * > bsearch_dup(const C< T > &a, const T &x, const Compare &cmp=Compare())
Search for all occurrences of a value returning pointers (const version).
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.
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.
void merge_lists(Tlist &l1, Tlist &l2, Tlist &result, const Compare &cmp=Compare())
Merge two sorted lists into a single sorted list.
void push2(Stack &stack, const A &a, const B &b)
Push two values onto a stack.
void quicksort_op(C< T > &a, const Compare &cmp=Compare(), const size_t threshold=Quicksort_Threshold)
Optimized quicksort for containers using operator().
STL namespace.
Comparator specialization for Dnode objects.
DynList< int > l1
DynList< int > l2
int keys[]
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
Doubly linked list node with typed data.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Alias for htlist.H (DynList implementation).
Comprehensive sorting algorithms and search utilities for Aleph-w.
DynList< int > l