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 <functional>
44#include <limits>
45#include <random>
46#include <string>
47#include <type_traits>
48#include <vector>
49#include <array>
50
51#include <tpl_sort_utils.H>
52#include <tpl_dynArray.H>
53#include <tpl_array.H>
54#include <tpl_dynList.H>
55#include <tpl_dynDlist.H>
56#include <tpl_dnode.H>
57
58using namespace Aleph;
59using namespace std;
60
61namespace {
62
63static_assert(CountingSortable<int>);
65static_assert(not CountingSortable<bool>);
66static_assert(RadixSortable<int>);
68static_assert(not RadixSortable<bool>);
69
76static DynArray<int> make_dynarray(std::initializer_list<int> xs)
77{
79 a.reserve(xs.size());
80 size_t i = 0;
81 for (const int x : xs)
82 a(i++) = x;
83 return a;
84}
85
86template <class Compare>
87std::vector<size_t> stable_index_reference(const std::vector<int> &values,
88 const Compare &cmp)
89{
90 std::vector<size_t> ref(values.size());
91 for (size_t i = 0; i < ref.size(); ++i)
92 ref[i] = i;
93
94 std::stable_sort(ref.begin(), ref.end(),
95 [&values, &cmp](const size_t i, const size_t j)
96 {
97 return cmp(values[i], values[j]);
98 });
99
100 return ref;
101}
102
103template <class Index>
104void expect_index_matches_reference(const Index &idx,
105 const std::vector<size_t> &ref)
106{
107 ASSERT_EQ(idx.size(), ref.size());
108 for (size_t i = 0; i < ref.size(); ++i)
109 EXPECT_EQ(idx(i), ref[i]) << "position " << i;
110}
111
112template <class Compare>
114{
115 constexpr size_t max_n = 7;
116 constexpr size_t alphabet = 3;
117
118 for (size_t n = 0; n <= max_n; ++n)
119 {
120 size_t cases = 1;
121 for (size_t i = 0; i < n; ++i)
122 cases *= alphabet;
123
124 for (size_t code = 0; code < cases; ++code)
125 {
126 std::vector<int> values(n);
127 size_t x = code;
128 for (size_t i = 0; i < n; ++i)
129 {
130 values[i] = static_cast<int>(x % alphabet);
131 x /= alphabet;
132 }
133
134 const auto idx = stable_build_index(values, cmp);
135 const auto ref = stable_index_reference(values, cmp);
137 }
138 }
139}
140
141static DynList<int> make_dynlist(std::initializer_list<int> xs)
142{
144 for (int x : xs)
145 l.append(x);
146 return l;
147}
148
149static DynDlist<int> make_dyndlist(std::initializer_list<int> xs)
150{
152 for (int x : xs)
153 l.append(x);
154 return l;
155}
156
157static Dnode<int> make_dnode_list(std::initializer_list<int> xs)
158{
160 for (int x : xs)
161 h.append(new Dnode<int>(x));
162 return h;
163}
164
172static void delete_all_nodes(Dnode<int> & h)
173{
174 while (not h.is_empty())
175 delete h.remove_first_ne();
176}
177
184template <typename T>
185static void sort_dynarray(DynArray<T> & a)
186{
187 quicksort(a);
188}
189
201template <typename T>
202static void expect_same_dynarray(const DynArray<T> & a, const DynArray<T> & b)
203{
204 EXPECT_EQ(a.size(), b.size());
205 if (a.size() != b.size())
206 return;
207 for (size_t i = 0; i < a.size(); ++i)
208 EXPECT_EQ(a(i), b(i));
209}
210
218template <typename T>
220{
222 ret.reserve(l.size());
223 size_t i = 0;
224 for (HTList::Iterator it(l); it.has_curr(); it.next())
225 ret(i++) = reinterpret_cast<uintptr_t>(it.get_curr());
227 return ret;
228}
229
240template <typename T>
242{
244 ret.reserve(l.size());
245 size_t i = 0;
246 for (typename Dnode<T>::Iterator it(l); it.has_curr(); it.next())
247 ret(i++) = reinterpret_cast<uintptr_t>(it.get_curr());
249 return ret;
250}
251
253{
254 DynList<int> l = make_dynlist({1, 1, 2, 2, 3});
256 EXPECT_TRUE(test_sorted(l).first);
258}
259
261{
262 DynList<int> l = make_dynlist({1, 3, 2, 4});
264 auto inv = search_inversion(l);
265 EXPECT_FALSE(inv.first);
266 EXPECT_EQ(inv.second, 2u);
267}
268
270{
271 DynList<int> l = make_dynlist({5, 4, 4, 2, 1});
274}
275
277{
278 int a0[1] = {0};
279 selection_sort(a0, 0);
280 selection_sort(a0, 1);
281 EXPECT_EQ(a0[0], 0);
282}
283
285{
286 int a[] = {3, 1, 2, 1, 0};
287 selection_sort(a, sizeof(a) / sizeof(a[0]));
288 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
289}
290
292{
293 auto a = make_dynarray({10, 9, 3, 2, 1, 8, 7});
294 // sort only [2..4] (3,2,1)
295 insertion_sort(a, 2, 4);
296 EXPECT_EQ(a(0), 10);
297 EXPECT_EQ(a(1), 9);
298 EXPECT_EQ(a(2), 1);
299 EXPECT_EQ(a(3), 2);
300 EXPECT_EQ(a(4), 3);
301 EXPECT_EQ(a(5), 8);
302 EXPECT_EQ(a(6), 7);
303}
304
306{
307 auto a = make_dynarray({3, 1, 2, 1, 0});
309 for (size_t i = 1; i < a.size(); ++i)
310 ASSERT_LE(a(i - 1), a(i));
311}
312
314{
315 auto a = make_dynarray({3, 1, 2, 1, 0});
317 for (size_t i = 1; i < a.size(); ++i)
318 ASSERT_GE(a(i - 1), a(i));
319}
320
322{
323 auto a = make_dynarray({3, 1, 2, 1, 0});
324 bubble_sort(a);
325 for (size_t i = 1; i < a.size(); ++i)
326 ASSERT_LE(a(i - 1), a(i));
327}
328
330{
331 auto a = make_dynarray({0, 0, 1, 1, 2, 2});
332 bubble_sort(a);
333 for (size_t i = 1; i < a.size(); ++i)
334 ASSERT_LE(a(i - 1), a(i));
335 EXPECT_EQ(a(0), 0);
336 EXPECT_EQ(a(5), 2);
337}
338
339static bool is_min_heap(const DynArray<int> & a, size_t n)
340{
341 if (n <= 1)
342 return true;
343
344 for (size_t child = 2; child <= n; ++child)
345 {
346 size_t parent = child / 2;
347 if (a(parent - 1) > a(child - 1))
348 return false;
349 }
350 return true;
351}
352
354{
355 auto a = make_dynarray({5, 99, 0, 99, 99, 3, 99});
356 // l=0 => 5, m=3 => 99, r=6 => 99 => median is 99 => either m or r
357 long p = select_pivot_op<int>(a, 0, 6);
358 EXPECT_TRUE(p == 3 || p == 6);
359
360 auto b = make_dynarray({10, 99, 5, 99, 99, 99, 0});
361 // l=0 => 10, m=3 => 99, r=6 => 0 => median is 10 => l
362 EXPECT_EQ(select_pivot_op<int>(b, 0, 6), 0);
363
364 auto c = make_dynarray({0, 99, 99, 5, 99, 99, 10});
365 // l=0 => 0, m=3 => 5, r=6 => 10 => median is 5 => m
366 EXPECT_EQ(select_pivot_op<int>(c, 0, 6), 3);
367}
368
370{
371 Array<int> a;
372 for (int x : {5, 4, 3, 2, 1, 0})
373 a.append(x);
374
375 // r - l <= 5 => returns r
376 EXPECT_EQ(select_pivot_op<int>(a, 0, 5), 5);
377}
378
380{
381 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
382 std::vector<int> before;
383 before.reserve(a.size());
384 for (size_t i = 0; i < a.size(); ++i)
385 before.push_back(a(i));
386
387 long p = partition_op<int>(a, 0, static_cast<long>(a.size() - 1));
388 ASSERT_GE(p, 0);
389 ASSERT_LT(static_cast<size_t>(p), a.size());
390
391 const int pivot = a(p);
392 for (long i = 0; i < p; ++i)
394 for (long i = p + 1; i < static_cast<long>(a.size()); ++i)
396
397 std::vector<int> after;
398 after.reserve(a.size());
399 for (size_t i = 0; i < a.size(); ++i)
400 after.push_back(a(i));
401 std::sort(before.begin(), before.end());
402 std::sort(after.begin(), after.end());
404}
405
407{
408 Array<int> a;
409 for (int x : {4, 1, 3, 2, 0, 2})
410 a.append(x);
411
412 std::vector<int> before;
413 before.reserve(a.size());
414 for (size_t i = 0; i < a.size(); ++i)
415 before.push_back(a(i));
416
417 long p = partition_op<int>(a, 0, static_cast<long>(a.size() - 1));
418 ASSERT_GE(p, 0);
419 ASSERT_LT(static_cast<size_t>(p), a.size());
420
421 const int pivot = a(p);
422 for (long i = 0; i < p; ++i)
424 for (long i = p + 1; i < static_cast<long>(a.size()); ++i)
426
427 std::vector<int> after;
428 after.reserve(a.size());
429 for (size_t i = 0; i < a.size(); ++i)
430 after.push_back(a(i));
431 std::sort(before.begin(), before.end());
432 std::sort(after.begin(), after.end());
434}
435
437{
438 {
439 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
440 auto expected = std::vector<int>{4, 1, 3, 2, 0, 2};
441 std::sort(expected.begin(), expected.end());
445 }
446
447 {
448 Array<int> a;
449 for (int x : {4, 1, 3, 2, 0, 2})
450 a.append(x);
451 auto expected = std::vector<int>{4, 1, 3, 2, 0, 2};
452 std::sort(expected.begin(), expected.end());
456 }
457}
458
460{
461 EXPECT_EQ(back_index(10), 9);
462
464 EXPECT_TRUE(nc(2, 1));
465 EXPECT_FALSE(nc(1, 2));
466}
467
469{
470 int a[] = {4, 1, 3, 2, 0, 2};
472 int p = select_pivot<int, Aleph::less<int>>(a, 0, 5, cmp);
473 EXPECT_GE(p, 0);
474 EXPECT_LE(p, 5);
475
476 int q = partition<int, Aleph::less<int>>(a, 0, 5, cmp);
477 EXPECT_GE(q, 0);
478 EXPECT_LE(q, 5);
479}
480
482{
483 // [0..2] and [3..5] are already sorted
484 int a[] = {0, 2, 4, 1, 3, 5};
485 merge(a, 0, 2, 5, Aleph::less<int>());
486 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
487}
488
490{
491 FixedStack<int> st(10);
492 push2(st, 1, 2);
493 EXPECT_EQ(st.pop(), 1);
494 EXPECT_EQ(st.pop(), 2);
495 EXPECT_TRUE(st.is_empty());
496}
497
499{
500 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
501 quicksort_no_tail(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
502 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
503}
504
506{
507 Snodenc<int> n1(1), n2(2);
509 EXPECT_TRUE(cmp(static_cast<Slinknc *>(&n1), static_cast<Slinknc *>(&n2)));
510 EXPECT_TRUE(cmp(static_cast<Slinknc *>(&n1), 5));
511}
512
514{
516 Dlink & base = static_cast<Dlink &>(h);
517
518 auto * n2 = new Dnode<int>(2);
519 auto * n0 = new Dnode<int>(0);
520 auto * n1 = new Dnode<int>(1);
521
524
525 insert_sorted<Cmp>(base, n2, cmp);
526 insert_sorted<Cmp>(base, n0, cmp);
527 insert_sorted<Cmp>(base, n1, cmp);
529
530 // list_insertion_sort on Dlink
531 Dnode<int> h2 = make_dnode_list({3, 1, 2, 0});
532 Dlink & base2 = static_cast<Dlink &>(h2);
535
536 delete_all_nodes(h);
537 delete_all_nodes(h2);
538}
539
541{
543 l.append(0);
544 l.append(2);
545
546 auto * node = new Snodenc<int>(1);
548 insert_sorted(l, static_cast<Slinknc *>(node), cmp);
550
552 for (int x : {3, 1, 2, 0})
553 l2.append(x);
555 static_cast<HTList &>(l2), cmp);
557}
558
560{
561 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
562 Dlink & base = static_cast<Dlink &>(h);
563
566
567 auto * found = dlink_random_search(base, 3, cmp);
568 ASSERT_NE(found, nullptr);
569 EXPECT_EQ(found->get_data(), 3);
570
571 auto * sel = dlink_random_select(base, 0, cmp);
572 ASSERT_NE(sel, nullptr);
573 EXPECT_EQ(static_cast<Dnode<int> *>(sel)->get_data(), 0);
574
575 delete_all_nodes(h);
576}
577
579{
580 const auto a = make_dynarray({0, 1, 1, 1, 2, 3});
581 EXPECT_EQ(binindex(a, 2), 4);
582}
583
585{
586 int a[] = {4, 1, 3, 2, 0, 2};
587 std::vector<int> expected(std::begin(a), std::end(a));
588 std::sort(expected.begin(), expected.end());
589
594}
595
597{
599
600 // sift_up: insert new element at end and bubble up
601 {
603 a.reserve(4);
604 a(0) = 1;
605 a(1) = 3;
606 a(2) = 5;
607 a(3) = 0;
610 }
611
612 // sift_down: restore heap after root replaced
613 {
615 a.reserve(4);
616 a(0) = 3;
617 a(1) = 1;
618 a(2) = 2;
619 a(3) = 0; // outside heap when n=3
622 }
623}
624
626{
627 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
628 mergesort(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
629 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
630}
631
633{
634 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
635 quicksort(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
636 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
637}
638
640{
641 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
642 quicksort_rec(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
643 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
644}
645
647{
648 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
649 quicksort_rec_min(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
650 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
651}
652
654{
655 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
656 quicksort_insertion(a, 0, static_cast<int>((sizeof(a) / sizeof(a[0])) - 1));
657 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
658
659 int b[] = {2, 1};
660 quicksort_insertion(b, 0, 1);
661 EXPECT_TRUE(std::is_sorted(std::begin(b), std::end(b)));
662}
663
664// Introsort tests - hybrid algorithm with O(n log n) guaranteed
666{
667 int a[] = {5, 4, 3, 2, 1, 0, 0, 9};
668 introsort(a, 0L, static_cast<long>((sizeof(a) / sizeof(a[0])) - 1));
669 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
670}
671
673{
674 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
675 introsort(a, sizeof(a) / sizeof(a[0]));
676 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
677}
678
680{
681 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
682 introsort(a, 0L, 8L, std::greater<int>());
683 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a), std::greater<int>()));
684}
685
687{
688 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
689 introsort(a);
690 for (size_t i = 1; i < a.size(); ++i)
691 ASSERT_LE(a(i - 1), a(i));
692}
693
695{
696 // Empty array
697 int empty[] = {0};
698 introsort(empty, 0);
699 EXPECT_EQ(empty[0], 0);
700
701 // Single element
702 int single[] = {42};
703 introsort(single, 1);
704 EXPECT_EQ(single[0], 42);
705
706 // Empty DynArray
709}
710
712{
713 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
714 introsort(a, sizeof(a) / sizeof(a[0]));
715 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
716}
717
719{
720 int a[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
721 introsort(a, sizeof(a) / sizeof(a[0]));
722 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
723}
724
726{
727 int a[] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
728 introsort(a, sizeof(a) / sizeof(a[0]));
729 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
730}
731
733{
734 // Create an array large enough that might trigger heapsort fallback
735 // This tests the depth limit mechanism
736 const size_t n = 10000;
737 std::vector<int> v(n);
738 for (size_t i = 0; i < n; ++i)
739 v[i] = static_cast<int>(n - i); // Reverse sorted (worst case for quicksort)
740
741 introsort(v.data(), n);
742 EXPECT_TRUE(std::is_sorted(v.begin(), v.end()));
743}
744
746{
747 // Test with larger DynArray
748 const size_t n = 5000;
750 a.reserve(n);
751 for (size_t i = 0; i < n; ++i)
752 a(i) = static_cast<int>(n - i); // Reverse sorted
753
754 introsort(a);
755 for (size_t i = 1; i < n; ++i)
756 ASSERT_LE(a(i - 1), a(i)) << "Failed at index " << i;
757}
758
759// Introsort with STL-style pointer interface (begin, end)
761{
762 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
763 introsort(a, a + 10); // STL-style: introsort(begin, end)
764 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
765}
766
768{
769 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
770 // Sort only middle portion [2, 7)
771 introsort(a + 2, a + 7);
772 // Elements 0,1 unchanged, 2-6 sorted, 7-9 unchanged
773 EXPECT_EQ(a[0], 9);
774 EXPECT_EQ(a[1], 1);
775 EXPECT_TRUE(std::is_sorted(a + 2, a + 7));
776 EXPECT_EQ(a[7], 4);
777}
778
780{
781 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
782 introsort(a, a + 9, std::greater<int>());
783 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a), std::greater<int>()));
784}
785
787{
788 int a[] = {42};
789 // Empty range - should not crash
790 introsort(a, a);
791 EXPECT_EQ(a[0], 42); // Unchanged
792}
793
794// Introsort for Array<T> container
796{
797 Array<int> arr;
798 arr.append(5);
799 arr.append(2);
800 arr.append(8);
801 arr.append(1);
802 arr.append(9);
803 arr.append(3);
804
805 introsort(arr);
806
807 for (size_t i = 1; i < arr.size(); ++i)
808 ASSERT_LE(arr(i - 1), arr(i));
809}
810
812{
813 Array<int> arr;
814 for (int i = 1; i <= 10; ++i)
815 arr.append(i);
816
817 introsort(arr, std::greater<int>());
818
819 for (size_t i = 1; i < arr.size(); ++i)
820 ASSERT_GE(arr(i - 1), arr(i)); // Descending order
821}
822
824{
825 Array<int> arr;
827 EXPECT_TRUE(arr.is_empty());
828}
829
831{
832 Array<int> arr;
833 arr.append(42);
834 introsort(arr);
835 EXPECT_EQ(arr.size(), 1u);
836 EXPECT_EQ(arr(0), 42);
837}
838
840{
841 const size_t n = 5000;
842 Array<int> arr(n);
843 for (size_t i = 0; i < n; ++i)
844 arr.append(static_cast<int>(n - i)); // Reverse sorted
845
846 introsort(arr);
847
848 for (size_t i = 1; i < n; ++i)
849 ASSERT_LE(arr(i - 1), arr(i)) << "Failed at index " << i;
850}
851
853{
854 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
855 heapsort(a);
856 for (size_t i = 1; i < a.size(); ++i)
857 ASSERT_LE(a(i - 1), a(i));
858}
859
861{
862 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
863 quicksort_op(a);
864 for (size_t i = 1; i < a.size(); ++i)
865 ASSERT_LE(a(i - 1), a(i));
866}
867
869{
873}
874
876{
877 auto a = make_dynarray({9, 1, 8, 2, 7, 3, 6, 4, 5, 0});
878 shellsort(a);
879 for (size_t i = 1; i < a.size(); ++i)
880 ASSERT_LE(a(i - 1), a(i));
881}
882
884{
885 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
886 quicksort(a);
887 for (size_t i = 1; i < a.size(); ++i)
888 ASSERT_LE(a(i - 1), a(i));
889}
890
892{
893 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
894 quicksort_rec(a, 0, static_cast<long>(a.size() - 1));
895 for (size_t i = 1; i < a.size(); ++i)
896 ASSERT_LE(a(i - 1), a(i));
897}
898
900{
901 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
902 mergesort(l);
904}
905
907{
908 DynList<int> l = make_dynlist({9, 8, 7, 6, 5, 4, 3, 2, 1, 0});
911}
912
914{
915 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
916 DynList<int> sorted = insertion_sort(std::move(l));
919}
920
922{
923 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
924 DynList<int> sorted = mergesort(std::move(l));
927}
928
930{
931 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
932 quicksort(l);
934 EXPECT_EQ(l.get_first(), 0);
935 EXPECT_EQ(l.get_last(), 4);
936}
937
939{
940 DynList<int> l1 = make_dynlist({0, 2, 4});
941 DynList<int> l2 = make_dynlist({1, 3, 5});
943
948 EXPECT_EQ(out.size(), 6u);
949 EXPECT_EQ(out.get_first(), 0);
950 EXPECT_EQ(out.get_last(), 5);
951}
952
954{
955 auto l1 = make_dnode_list({0, 2, 4});
956 auto l2 = make_dnode_list({1, 3, 5});
958
960
963 EXPECT_FALSE(out.is_empty());
964
965 int expected = 0;
966 for (Dnode<int>::Iterator it(out); it.has_curr(); it.next_ne(), ++expected)
967 EXPECT_EQ(it.get_curr_ne()->get_data(), expected);
969
970 delete_all_nodes(out);
971}
972
974{
975 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
976 mergesort(l);
978}
979
981{
982 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
983 int * p = search_extreme(l);
984 ASSERT_NE(p, nullptr);
985 EXPECT_EQ(*p, 0);
986}
987
989{
990 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
991 int * p = random_select(l, 0);
992 ASSERT_NE(p, nullptr);
993 EXPECT_EQ(*p, 0);
994
995 p = random_select(l, 5);
996 ASSERT_NE(p, nullptr);
997 EXPECT_EQ(*p, 4);
998}
999
1001{
1002 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
1003
1004 int * p = random_search(l, 3);
1005 ASSERT_NE(p, nullptr);
1006 EXPECT_EQ(*p, 3);
1007
1008 p = random_search(l, 99);
1009 EXPECT_EQ(p, nullptr);
1010}
1011
1013{
1014 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1015
1016 auto * n0 = random_select<int>(h, 0);
1017 ASSERT_NE(n0, nullptr);
1018 EXPECT_EQ(n0->get_data(), 0);
1019
1020 auto * nmax = random_select<int>(h, 5);
1021 ASSERT_NE(nmax, nullptr);
1022 EXPECT_EQ(nmax->get_data(), 4);
1023
1024 auto * nfound = random_search<int>(h, 3);
1025 ASSERT_NE(nfound, nullptr);
1026 EXPECT_EQ(nfound->get_data(), 3);
1027
1028 auto * nmiss = random_search<int>(h, 99);
1029 EXPECT_EQ(nmiss, nullptr);
1030
1031 delete_all_nodes(h);
1032}
1033
1035{
1036 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1037 quicksort<int>(static_cast<HTList &>(l), Aleph::less<int>());
1039}
1040
1042{
1043 int a[] = {4, 1, 3, 2, 0, 2};
1044 EXPECT_EQ(sequential_search(a, int{3}, 0, 5), 2);
1045 EXPECT_EQ(sequential_search(a, int{99}, 0, 5), Not_Found);
1046}
1047
1049{
1050 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
1051 EXPECT_EQ(sequential_search(a, 3, 0, static_cast<int>(a.size() - 1)), 2);
1052 EXPECT_EQ(sequential_search(a, 99, 0, static_cast<int>(a.size() - 1)), Not_Found);
1053}
1054
1056{
1057 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1058 int * p = sequential_search(l, 3);
1059 ASSERT_NE(p, nullptr);
1060 EXPECT_EQ(*p, 3);
1061
1062 p = sequential_search(l, 99);
1063 EXPECT_EQ(p, nullptr);
1064}
1065
1067{
1068 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
1069 int * p = sequential_search(l, 3);
1070 ASSERT_NE(p, nullptr);
1071 EXPECT_EQ(*p, 3);
1072 p = sequential_search(l, 99);
1073 EXPECT_EQ(p, nullptr);
1074}
1075
1077{
1078 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1079
1080 auto * n = sequential_search(h, 3);
1081 ASSERT_NE(n, nullptr);
1082 EXPECT_EQ(n->get_data(), 3);
1083
1084 n = sequential_search(h, 99);
1085 EXPECT_EQ(n, nullptr);
1086
1087 delete_all_nodes(h);
1088}
1089
1091{
1092 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1093 auto * n = search_extreme<int>(h, Aleph::less<int>());
1094 ASSERT_NE(n, nullptr);
1095 EXPECT_EQ(n->get_data(), 0);
1096 delete_all_nodes(h);
1097}
1098
1100{
1101 int a[] = {4, 1, 3, 2, 0, 2};
1102 EXPECT_EQ(search_min(a, 0, 5), 4);
1103 EXPECT_EQ(search_max(a, 0, 5), 0);
1104}
1105
1107{
1108 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
1109 EXPECT_EQ(search_extreme(a, 0, static_cast<long>(a.size() - 1)), 4);
1110 EXPECT_EQ(search_max(a, 0, static_cast<long>(a.size() - 1)), 0);
1111}
1112
1114{
1115 DynDlist<int> l = make_dyndlist({4, 1, 3, 2, 0, 2});
1116 int * mn = search_min(l);
1117 int * mx = search_max(l);
1118 ASSERT_NE(mn, nullptr);
1119 ASSERT_NE(mx, nullptr);
1120 EXPECT_EQ(*mn, 0);
1121 EXPECT_EQ(*mx, 4);
1122}
1123
1125{
1126 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1127 int * mn = search_extreme(l);
1129 ASSERT_NE(mn, nullptr);
1130 ASSERT_NE(mx, nullptr);
1131 EXPECT_EQ(*mn, 0);
1132 EXPECT_EQ(*mx, 4);
1133}
1134
1136{
1137 DynList<int> l = make_dynlist({4, 1, 3, 2, 0, 2});
1138 int * mn = search_extreme(l, Aleph::less<int>());
1140 ASSERT_NE(mn, nullptr);
1141 ASSERT_NE(mx, nullptr);
1142 EXPECT_EQ(*mn, 0);
1143 EXPECT_EQ(*mx, 4);
1144}
1145
1147{
1148 {
1149 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1151 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1152 delete_all_nodes(h);
1153 }
1154
1155 {
1156 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1158 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1159 delete_all_nodes(h);
1160 }
1161
1162 {
1163 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1164 quicksort(h);
1165 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1166 delete_all_nodes(h);
1167 }
1168
1169 {
1170 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1171 mergesort(h);
1172 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1173 delete_all_nodes(h);
1174 }
1175}
1176
1178{
1179 auto h = make_dnode_list({4, 1, 3, 2, 0, 2});
1180 Dlink & base = static_cast<Dlink &>(h);
1181
1183 quicksort(base, Cmp(Aleph::less<int>()));
1184
1185 EXPECT_EQ(search_extreme<int>(h, Aleph::less<int>())->get_data(), 0);
1187
1188 delete_all_nodes(h);
1189}
1190
1192{
1193 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1194
1195 auto idxs = binary_search_dup(a, 1);
1196 ASSERT_EQ(idxs.size(), 3u);
1197 EXPECT_EQ(idxs.get_first(), 1u);
1198 EXPECT_EQ(idxs.get_last(), 3u);
1199
1200 int * p = bsearch(a, 1);
1201 ASSERT_NE(p, nullptr);
1202 EXPECT_EQ(*p, 1);
1203 EXPECT_EQ(bsearch(a, 99), nullptr);
1204}
1205
1207{
1208 {
1209 auto a = make_dynarray({1, 1, 1, 2, 3});
1210 auto idxs = binary_search_dup(a, 1);
1211 ASSERT_EQ(idxs.size(), 3u);
1212 EXPECT_EQ(idxs.get_first(), 0u);
1213 EXPECT_EQ(idxs.get_last(), 2u);
1214 }
1215
1216 {
1217 auto a = make_dynarray({0, 1, 2, 3, 3, 3});
1218 auto idxs = binary_search_dup(a, 3);
1219 ASSERT_EQ(idxs.size(), 3u);
1220 EXPECT_EQ(idxs.get_first(), 3u);
1221 EXPECT_EQ(idxs.get_last(), 5u);
1222 }
1223}
1224
1226{
1227 // Descending sorted with duplicates
1228 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1230 ASSERT_EQ(idxs.size(), 3u);
1231 EXPECT_EQ(idxs.get_first(), 2u);
1232 EXPECT_EQ(idxs.get_last(), 4u);
1233
1235 ASSERT_EQ(idxs.size(), 2u);
1236 EXPECT_EQ(idxs.get_first(), 6u);
1237 EXPECT_EQ(idxs.get_last(), 7u);
1238}
1239
1241{
1242 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1243 auto ps = bsearch_dup(a, 3, Aleph::greater<int>());
1244 ASSERT_EQ(ps.size(), 3u);
1245 for (auto p : ps)
1246 {
1247 ASSERT_NE(p, nullptr);
1248 EXPECT_EQ(*p, 3);
1249 }
1250}
1251
1253{
1254 auto a = make_dynarray({3, 1, 2, 1, 0});
1255
1256 auto idx = build_index(a);
1257
1258 static_assert(std::is_same_v<decltype(idx), Array<size_t>>);
1259 ASSERT_EQ(idx.size(), a.size());
1260 for (size_t i = 1; i < idx.size(); ++i)
1261 ASSERT_LE(a(idx(i - 1)), a(idx(i)));
1262
1263 auto ptrs = build_index_ptr(a);
1264 static_assert(std::is_same_v<decltype(ptrs), Array<int *>>);
1265 ASSERT_EQ(ptrs.size(), a.size());
1266 for (size_t i = 1; i < ptrs.size(); ++i)
1267 ASSERT_LE(*ptrs(i - 1), *ptrs(i));
1268
1269 const auto &ca = a;
1270 auto cptrs = build_index_ptr(ca);
1271 static_assert(std::is_same_v<decltype(cptrs), Array<const int *>>);
1272 ASSERT_EQ(cptrs.size(), a.size());
1273 for (size_t i = 1; i < cptrs.size(); ++i)
1274 ASSERT_LE(*cptrs(i - 1), *cptrs(i));
1275}
1276
1278{
1279 std::vector<int> a = {3, 1, 2, 1, 0};
1280
1281 auto idx = build_index(a);
1282
1283 static_assert(std::is_same_v<decltype(idx), Array<size_t>>);
1284 ASSERT_EQ(idx.size(), a.size());
1285 for (size_t i = 1; i < idx.size(); ++i)
1286 ASSERT_LE(a[idx(i - 1)], a[idx(i)]);
1287}
1288
1290{
1291 auto a = make_dynarray({2, 1, 2, 1, 2});
1292
1293 auto idx = stable_build_index(a);
1294
1295 static_assert(std::is_same_v<decltype(idx), Array<size_t>>);
1296 ASSERT_EQ(idx.size(), a.size());
1297 EXPECT_EQ(idx(0), 1u);
1298 EXPECT_EQ(idx(1), 3u);
1299 EXPECT_EQ(idx(2), 0u);
1300 EXPECT_EQ(idx(3), 2u);
1301 EXPECT_EQ(idx(4), 4u);
1302}
1303
1305{
1306 auto a = make_dynarray({2, 1, 2, 1, 2});
1307
1308 auto ptrs = stable_build_index_ptr(a);
1309
1310 static_assert(std::is_same_v<decltype(ptrs), Array<int *>>);
1311 ASSERT_EQ(ptrs.size(), a.size());
1312 // Same stable order as stable_build_index's {1, 3, 0, 2, 4} on this
1313 // exact input, expressed as pointers into `a` instead of indices.
1314 EXPECT_EQ(ptrs(0), &a(1));
1315 EXPECT_EQ(ptrs(1), &a(3));
1316 EXPECT_EQ(ptrs(2), &a(0));
1317 EXPECT_EQ(ptrs(3), &a(2));
1318 EXPECT_EQ(ptrs(4), &a(4));
1319
1320 const auto &ca = a;
1322 static_assert(std::is_same_v<decltype(cptrs), Array<const int *>>);
1323 ASSERT_EQ(cptrs.size(), a.size());
1324 for (size_t i = 0; i < ptrs.size(); ++i)
1325 EXPECT_EQ(cptrs(i), ptrs(i));
1326}
1327
1329{
1330 DynArray<int> a;
1331 a.reserve(75);
1332 for (size_t i = 0; i < 75; ++i)
1333 a(i) = static_cast<int>((i * 17) % 5);
1334
1335 auto ptrs = stable_build_index_ptr(a);
1336
1337 static_assert(std::is_same_v<decltype(ptrs), Array<int *>>);
1338 ASSERT_EQ(ptrs.size(), a.size());
1339 for (size_t i = 1; i < ptrs.size(); ++i)
1340 {
1341 ASSERT_LE(*ptrs(i - 1), *ptrs(i));
1342 if (*ptrs(i - 1) == *ptrs(i))
1343 EXPECT_LT(ptrs(i - 1), ptrs(i))
1344 << "equal-valued elements must keep their original relative order";
1345 }
1346}
1347
1349{
1350 std::vector<int> a;
1351 for (size_t i = 0; i < 75; ++i)
1352 a.push_back(static_cast<int>((i * 17) % 5));
1353
1354 auto idx = stable_build_index(a);
1355
1356 static_assert(std::is_same_v<decltype(idx), Array<size_t>>);
1357 ASSERT_EQ(idx.size(), a.size());
1358 for (size_t i = 1; i < idx.size(); ++i)
1359 {
1360 ASSERT_LE(a[idx(i - 1)], a[idx(i)]);
1361 if (a[idx(i - 1)] == a[idx(i)])
1362 EXPECT_LT(idx(i - 1), idx(i));
1363 }
1364}
1365
1367{
1369}
1370
1372{
1374}
1375
1377{
1378 std::vector<int> a = {2, 1, 2, 1, 2};
1379
1380 auto idx = stable_build_index(a);
1381
1382 static_assert(std::is_same_v<decltype(idx), Array<size_t>>);
1383 ASSERT_EQ(idx.size(), a.size());
1384 EXPECT_EQ(idx(0), 1u);
1385 EXPECT_EQ(idx(1), 3u);
1386 EXPECT_EQ(idx(2), 0u);
1387 EXPECT_EQ(idx(3), 2u);
1388 EXPECT_EQ(idx(4), 4u);
1389}
1390
1392{
1393 Slinknc head;
1394 auto * n1 = new Snodenc<int>(4);
1395 auto * n2 = new Snodenc<int>(1);
1396 auto * n3 = new Snodenc<int>(3);
1397 auto * n4 = new Snodenc<int>(0);
1398 head.insert(n1);
1399 head.insert(n2);
1400 head.insert(n3);
1401 head.insert(n4);
1402
1403 auto found = sequential_search(head, 3);
1404 ASSERT_NE(found, nullptr);
1405 EXPECT_EQ(static_cast<Snodenc<int>*>(found)->get_data(), 3);
1406
1407 auto missing = sequential_search(head, 99);
1408 EXPECT_EQ(missing, nullptr);
1409
1411 ASSERT_NE(extreme_min, nullptr);
1412 EXPECT_EQ(static_cast<Snodenc<int>*>(extreme_min)->get_data(), 0);
1413
1414 while (not head.is_empty())
1415 delete static_cast<Snodenc<int>*>(head.remove_next());
1416}
1417
1419{
1420 Slinknc head;
1421 auto * n1 = new Snodenc<int>(2);
1422 auto * n2 = new Snodenc<int>(1);
1423 auto * n3 = new Snodenc<int>(0);
1424 head.insert(n1);
1425 head.insert(n2);
1426 head.insert(n3);
1427
1428 auto * found = sequential_search<int>(head, 1);
1429 ASSERT_NE(found, nullptr);
1430 EXPECT_EQ(found->to_data<int>(), 1);
1431
1432 auto * missing = sequential_search<int>(head, 99);
1433 EXPECT_EQ(missing, nullptr);
1434
1435 while (not head.is_empty())
1436 delete static_cast<Snodenc<int>*>(head.remove_next());
1437}
1438
1440{
1441 auto h = make_dnode_list({3, 1, 2, 0});
1442 Dlink & base = static_cast<Dlink &>(h);
1443
1444 auto * found = sequential_search<int>(base, 2);
1445 ASSERT_NE(found, nullptr);
1446 EXPECT_EQ(static_cast<Dnode<int>*>(found)->get_data(), 2);
1447
1450 ASSERT_NE(mn, nullptr);
1451 EXPECT_EQ(mn->get_data(), 0);
1452
1453 delete_all_nodes(h);
1454}
1455
1457{
1458 int a[] = {4, 1, 3, 2, 0, 2};
1459 int idx = random_search(a, 3, 0, 5);
1460 ASSERT_NE(idx, Not_Found);
1461 EXPECT_EQ(a[idx], 3);
1462 EXPECT_EQ(random_search(a, 99, 0, 5), Not_Found);
1463
1464 auto d = make_dynarray({4, 1, 3, 2, 0, 2});
1465 idx = random_search(d, 3, 0, static_cast<long>(d.size() - 1));
1466 ASSERT_NE(idx, Not_Found);
1467 EXPECT_EQ(d(idx), 3);
1468 EXPECT_EQ(random_search(d, 99, 0, static_cast<long>(d.size() - 1)), Not_Found);
1469}
1470
1472{
1473 Array<int> a;
1474 for (int x : {4, 1, 3, 2, 0, 2})
1475 a.append(x);
1476
1477 EXPECT_EQ(random_select(a, 0), 0);
1478 EXPECT_EQ(random_select(a, 5), 4);
1479}
1480
1482{
1483 {
1484 DynArray<int> a;
1485 EXPECT_THROW(random_select(a, 0), std::out_of_range);
1486 }
1487
1488 {
1489 auto a = make_dynarray({4, 1, 3});
1490 EXPECT_THROW(random_select(a, 3), std::out_of_range);
1491 }
1492
1493 {
1494 Array<int> a;
1495 a.append(1);
1496 EXPECT_THROW(random_select(a, 1), std::out_of_range);
1497 }
1498
1499 {
1500 int b[] = {4, 1, 3};
1501 using Cmp = Aleph::less<int>;
1502 auto fn = static_cast<const int & (*)(int *, const long, const long, const Cmp &)>(
1504 EXPECT_THROW(fn(b, 3, 3, Cmp()), std::out_of_range);
1505 }
1506
1507 {
1508 Dnode<int> h;
1509 EXPECT_EQ(random_select<int>(h, 0), nullptr);
1510 EXPECT_EQ(random_select<int>(h, 1), nullptr);
1511 }
1512
1513 {
1515 EXPECT_EQ(random_select(l, 0), nullptr);
1516 EXPECT_EQ(random_select(l, 1), nullptr);
1517 }
1518
1519 {
1520 auto h = make_dnode_list({4, 1});
1521 EXPECT_THROW(random_select<int>(h, 2), std::out_of_range);
1522 delete_all_nodes(h);
1523 }
1524
1525 {
1526 auto l = make_dyndlist({4, 1});
1527 EXPECT_THROW(random_select(l, 2), std::out_of_range);
1528 }
1529}
1530
1532{
1533 auto a = make_dynarray({0, 2, 4, 6});
1534
1535 EXPECT_EQ(binary_search(a, 0), 0);
1536 EXPECT_EQ(binary_search(a, 6), 3);
1537
1538 // insertion points
1539 EXPECT_EQ(binary_search(a, 1), 1);
1540 EXPECT_EQ(binary_search(a, 5), 3);
1541 EXPECT_EQ(binary_search(a, 7), 4);
1542}
1543
1545{
1546 int a[] = {0, 2, 4, 6};
1547 EXPECT_EQ(binary_search(a, 0, 0, 3), 0);
1548 EXPECT_EQ(binary_search(a, 6, 0, 3), 3);
1549 EXPECT_EQ(binary_search(a, 1, 0, 3), 1);
1550 EXPECT_EQ(binary_search(a, 5, 0, 3), 3);
1551 EXPECT_EQ(binary_search(a, 7, 0, 3), 4);
1552}
1553
1555{
1556 int a[] = {0, 2, 4, 6};
1557 EXPECT_EQ(binary_search_rec(a, 0, 0, 3), 0);
1558 EXPECT_EQ(binary_search_rec(a, 6, 0, 3), 3);
1559 EXPECT_EQ(binary_search_rec(a, 1, 0, 3), 1);
1560 EXPECT_EQ(binary_search_rec(a, 5, 0, 3), 3);
1561 EXPECT_EQ(binary_search_rec(a, 7, 0, 3), 4);
1562}
1563
1565{
1566 auto a = make_dynarray({4, 1, 3, 2, 0, 2});
1567 EXPECT_EQ(random_select(a, 0), 0);
1568 EXPECT_EQ(random_select(a, 5), 4);
1569
1570 int b[] = {4, 1, 3, 2, 0, 2};
1571 using Cmp = Aleph::less<int>;
1572 auto fn = static_cast<const int & (*)(int *, const long, const long, const Cmp &)>(
1574 EXPECT_EQ(fn(b, 0, 6, Cmp()), 0);
1575 EXPECT_EQ(fn(b, 5, 6, Cmp()), 4);
1576}
1577
1579{
1580 auto a = make_dynarray({0, 2, 4, 6});
1581 DynArray<int *> idx;
1582 idx.reserve(a.size());
1583 for (size_t i = 0; i < a.size(); ++i)
1584 idx(i) = &a(i);
1585
1586 // already sorted pointers by value
1587 EXPECT_EQ(binary_search(idx, 0), 0);
1588 EXPECT_EQ(binary_search(idx, 6), 3);
1589 EXPECT_EQ(binary_search(idx, 1), 1);
1590 EXPECT_EQ(binary_search(idx, 7), 4);
1591}
1592
1594{
1595 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1596 auto ptrs = bsearch_dup(a, 1);
1597 ASSERT_EQ(ptrs.size(), 3u);
1598 for (auto p : ptrs)
1599 ASSERT_NE(p, nullptr);
1600
1601 auto idxs = binindex_dup(a, 1);
1602 ASSERT_EQ(idxs.size(), 3u);
1603 EXPECT_EQ(idxs.get_first(), 1);
1604 EXPECT_EQ(idxs.get_last(), 3);
1605}
1606
1608{
1609 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1611 ptrs.reserve(a.size());
1612 for (size_t i = 0; i < a.size(); ++i)
1613 ptrs(i) = &a(i);
1614
1615 auto dup = bsearch_dup(ptrs, 3, Aleph::greater<int>());
1616 ASSERT_EQ(dup.size(), 3u);
1617 for (auto p : dup)
1618 {
1619 ASSERT_NE(p, nullptr);
1620 EXPECT_EQ(*p, 3);
1621 }
1622}
1623
1625{
1626 auto a = make_dynarray({5, 4, 3, 3, 3, 2, 1, 1, 0});
1628 ptrs.reserve(a.size());
1629 for (size_t i = 0; i < a.size(); ++i)
1630 ptrs(i) = &a(i);
1631
1633 ASSERT_EQ(idxs.size(), 3u);
1634 EXPECT_EQ(idxs.get_first(), 2);
1635 EXPECT_EQ(idxs.get_last(), 4);
1636}
1637
1639{
1640 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1642 ptrs.reserve(a.size());
1643 for (size_t i = 0; i < a.size(); ++i)
1644 ptrs(i) = &a(i);
1645
1646 auto found = bsearch(ptrs, 1);
1647 ASSERT_NE(found, nullptr);
1648 EXPECT_EQ(*found, 1);
1649
1650 auto dup = bsearch_dup(ptrs, 1);
1651 ASSERT_EQ(dup.size(), 3u);
1652 for (auto p : dup)
1653 {
1654 ASSERT_NE(p, nullptr);
1655 EXPECT_EQ(*p, 1);
1656 }
1657}
1658
1660{
1661 auto a = make_dynarray({0, 1, 1, 1, 2, 3});
1663 ptrs.reserve(a.size());
1664 for (size_t i = 0; i < a.size(); ++i)
1665 ptrs(i) = &a(i);
1666
1667 auto idxs = binindex_dup(ptrs, 1);
1668 ASSERT_EQ(idxs.size(), 3u);
1669 EXPECT_EQ(idxs.get_first(), 1);
1670 EXPECT_EQ(idxs.get_last(), 3);
1671}
1672
1674{
1675 auto a = make_dynarray({5, 4, 3, 2, 1, 0});
1677 ptrs.reserve(a.size());
1678 for (size_t i = 0; i < a.size(); ++i)
1679 ptrs(i) = &a(i);
1680
1681 // The container is sorted in descending order, so we must use greater<int>
1685}
1686
1688{
1689 auto a = make_dynarray({0, 1, 2, 3, 4, 5});
1691 ptrs.reserve(a.size());
1692 for (size_t i = 0; i < a.size(); ++i)
1693 ptrs(i) = &a(i);
1694
1695 // search only in [2..4] => values {2,3,4}
1696 EXPECT_EQ(binary_search(ptrs, 3, 2, 4), 3);
1697
1698 // insertion points within the restricted range
1699 EXPECT_EQ(binary_search(ptrs, 1, 2, 4), 2);
1700 EXPECT_EQ(binary_search(ptrs, 5, 2, 4), 5);
1701}
1702
1704{
1705 auto a = make_dynarray({5, 4, 3, 2, 1, 0});
1707 ptrs.reserve(a.size());
1708 for (size_t i = 0; i < a.size(); ++i)
1709 ptrs(i) = &a(i);
1710
1711 // search only in [1..3] => values {4,3,2} under greater<int>
1713
1714 // insertion points within the restricted range for descending order
1715 // 5 would be inserted before 4 => at l
1717 // 0 would be inserted after 2 => at r+1
1719}
1720
1722{
1725 sa[0] = 3; sa[1] = 0; sa[2] = 4; sa[3] = 1; sa[4] = 2;
1726
1727 counting_sort_indices(sa, tmp, 5, 0, 4,
1728 [](size_t idx) -> int { return static_cast<int>(idx); });
1729
1730 for (size_t i = 0; i < 5; ++i)
1731 EXPECT_EQ(sa[i], i);
1732}
1733
1743{
1744 // Two pairs with same key: (10,key=1) and (20,key=1)
1745 // Original order: indices 0(key=2), 1(key=1), 2(key=1), 3(key=0)
1748 sa[0] = 0; sa[1] = 1; sa[2] = 2; sa[3] = 3;
1749
1750 std::array<int, 4> keys = {2, 1, 1, 0};
1751 counting_sort_indices(sa, tmp, 4, 0, 2,
1752 [&](size_t idx) -> int { return keys[idx]; });
1753
1754 // Expected: 3(key=0), 1(key=1), 2(key=1), 0(key=2)
1755 EXPECT_EQ(sa[0], 3u);
1756 EXPECT_EQ(sa[1], 1u); // stable: 1 before 2
1757 EXPECT_EQ(sa[2], 2u);
1758 EXPECT_EQ(sa[3], 0u);
1759}
1760
1762{
1765 sa[0] = 0; sa[1] = 1; sa[2] = 2; sa[3] = 3;
1766
1767 std::array<int, 4> keys = {0, -1, 2, -2};
1768 counting_sort_indices(sa, tmp, 4, -2, 2,
1769 [&](size_t idx) -> int { return keys[idx]; });
1770
1771 // Sorted by key: 3(-2), 1(-1), 0(0), 2(2)
1772 EXPECT_EQ(sa[0], 3u);
1773 EXPECT_EQ(sa[1], 1u);
1774 EXPECT_EQ(sa[2], 0u);
1775 EXPECT_EQ(sa[3], 2u);
1776}
1777
1779{
1782 sa[0] = 42;
1783
1784 counting_sort_indices(sa, tmp, 1, 0, 0,
1785 [](size_t) -> int { return 0; });
1786 EXPECT_EQ(sa[0], 42u);
1787}
1788
1790{
1791 Array<size_t> sa;
1793 counting_sort_indices(sa, tmp, 0, 0, 0,
1794 [](size_t) -> int { return 0; });
1795 EXPECT_TRUE(sa.is_empty());
1796}
1797
1799{
1802 sa[0] = 0;
1803
1805 counting_sort_indices(sa, tmp, 1, 3, 2,
1806 [](size_t) -> int { return 0; }),
1807 std::domain_error);
1808}
1809
1811{
1814 sa[0] = 0;
1815 sa[1] = 1;
1816
1818 counting_sort_indices(sa, tmp, 2, 0, 1,
1819 [](size_t idx) -> int { return idx == 0 ? 0 : 2; }),
1820 std::out_of_range);
1821}
1822
1824{
1827 sa[0] = 0;
1828
1830 counting_sort_indices(sa, tmp, 2, 0, 1,
1831 [](size_t idx) -> int { return static_cast<int>(idx); }),
1832 std::out_of_range);
1833}
1834
1836{
1837 auto a = make_dynarray({5, -2, 3, -2, 0, 9, -10});
1838 counting_sort(a);
1839 EXPECT_EQ(a(0), -10);
1840 EXPECT_EQ(a(1), -2);
1841 EXPECT_EQ(a(2), -2);
1842 for (size_t i = 1; i < a.size(); ++i)
1843 ASSERT_LE(a(i - 1), a(i));
1844}
1845
1847{
1849 for (unsigned int x : {7u, 0u, 3u, 7u, 1u, 2u})
1850 a.append(x);
1851
1852 counting_sort(a);
1853 EXPECT_EQ(a(0), 0u);
1854 EXPECT_EQ(a(1), 1u);
1855 EXPECT_EQ(a(2), 2u);
1856 EXPECT_EQ(a(3), 3u);
1857 EXPECT_EQ(a(4), 7u);
1858 EXPECT_EQ(a(5), 7u);
1859}
1860
1862{
1863 int a[] = {4, 1, 3, 0, 2};
1864 counting_sort(a, sizeof(a) / sizeof(a[0]));
1865 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1866
1867 EXPECT_THROW((counting_sort<int>(nullptr, 1)), std::invalid_argument);
1868 EXPECT_NO_THROW((counting_sort<int>(nullptr, 0)));
1869}
1870
1872{
1873 int a[] = {5, 1, 4, 2, 3, 0};
1874 counting_sort(a);
1875 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1876}
1877
1879{
1880 auto a = make_dynarray({9, -1, 3, 0, -1, 2});
1881 counting_sort(a);
1882 for (size_t i = 1; i < a.size(); ++i)
1883 ASSERT_LE(a(i - 1), a(i));
1884 ASSERT_EQ(a.size(), 6u);
1885 EXPECT_EQ(a(0), -1);
1886 EXPECT_EQ(a(1), -1);
1887 EXPECT_EQ(a(5), 9);
1888}
1889
1891{
1892 DynArray<int> d;
1893 counting_sort(d);
1894 EXPECT_TRUE(d.is_empty());
1895
1896 Array<int> a;
1897 a.append(7);
1898 counting_sort(a);
1899 ASSERT_EQ(a.size(), 1u);
1900 EXPECT_EQ(a(0), 7);
1901}
1902
1904{
1905 DynList<int> l = make_dynlist({4, -1, 3, 0, -1, 2});
1907
1908 std::array<int, 6> expected = {-1, -1, 0, 2, 3, 4};
1909 size_t i = 0;
1910 for (DynList<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
1911 EXPECT_EQ(it.get_curr(), expected[i]);
1912 EXPECT_EQ(i, expected.size());
1913}
1914
1916{
1917 DynList<int> l = make_dynlist({4, -1, 3, 0, -1, 2});
1918 const auto before = dynlist_node_addresses(l);
1920 const auto after = dynlist_node_addresses(l);
1922}
1923
1925{
1926 DynDlist<int> l = make_dyndlist({7, 3, 7, 1, 0, -2});
1928
1929 std::array<int, 6> expected = {-2, 0, 1, 3, 7, 7};
1930 size_t i = 0;
1931 for (DynDlist<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
1932 EXPECT_EQ(it.get_curr(), expected[i]);
1933 EXPECT_EQ(i, expected.size());
1934}
1935
1937{
1938 DynDlist<int> l = make_dyndlist({7, 3, 7, 1, 0, -2});
1939 const auto before = dyndlist_node_addresses(l);
1941 const auto after = dyndlist_node_addresses(l);
1943}
1944
1946{
1948 a.reserve(2);
1949 a(0) = 0ull;
1950 a(1) = std::numeric_limits<unsigned long long>::max();
1951 EXPECT_THROW(counting_sort(a), std::runtime_error);
1952}
1953
1955{
1956 auto a = make_dynarray({170, 45, 75, 90, 802, 24, 2, 66});
1957 radix_sort(a);
1958 for (size_t i = 1; i < a.size(); ++i)
1959 ASSERT_LE(a(i - 1), a(i));
1960}
1961
1963{
1964 auto a = make_dynarray({0, -1, 5, -10, 3, -1, 2});
1965 radix_sort(a);
1966 EXPECT_EQ(a(0), -10);
1967 EXPECT_EQ(a(1), -1);
1968 EXPECT_EQ(a(2), -1);
1969 for (size_t i = 1; i < a.size(); ++i)
1970 ASSERT_LE(a(i - 1), a(i));
1971}
1972
1974{
1975 Array<int> a;
1976 for (int x : {9, 1, 8, 2, 7, 3, 6, 4, 5, 0})
1977 a.append(x);
1978
1979 radix_sort(a);
1980 for (size_t i = 1; i < a.size(); ++i)
1981 ASSERT_LE(a(i - 1), a(i));
1982}
1983
1985{
1986 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
1987 radix_sort(a, sizeof(a) / sizeof(a[0]));
1988 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1989}
1990
1992{
1993 int a[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0};
1994 radix_sort(a);
1995 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
1996}
1997
1999{
2000 EXPECT_THROW((radix_sort<int>(nullptr, 1)), std::invalid_argument);
2001 EXPECT_NO_THROW((radix_sort<int>(nullptr, 0)));
2002}
2003
2005{
2006 DynList<int> l = make_dynlist({3, -1, 2, -5, 0, 3});
2007 radix_sort(l);
2008
2009 std::array<int, 6> expected = {-5, -1, 0, 2, 3, 3};
2010 size_t i = 0;
2011 for (DynList<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
2012 EXPECT_EQ(it.get_curr(), expected[i]);
2013 EXPECT_EQ(i, expected.size());
2014}
2015
2017{
2018 DynList<int> l = make_dynlist({3, -1, 2, -5, 0, 3});
2019 const auto before = dynlist_node_addresses(l);
2020 radix_sort(l);
2021 const auto after = dynlist_node_addresses(l);
2023}
2024
2026{
2027 DynDlist<int> l = make_dyndlist({10, -2, 7, 0, -2, 1});
2028 radix_sort(l);
2029
2030 std::array<int, 6> expected = {-2, -2, 0, 1, 7, 10};
2031 size_t i = 0;
2032 for (DynDlist<int>::Iterator it(l); it.has_curr(); it.next(), ++i)
2033 EXPECT_EQ(it.get_curr(), expected[i]);
2034 EXPECT_EQ(i, expected.size());
2035}
2036
2038{
2039 DynDlist<int> l = make_dyndlist({10, -2, 7, 0, -2, 1});
2040 const auto before = dyndlist_node_addresses(l);
2041 radix_sort(l);
2042 const auto after = dyndlist_node_addresses(l);
2044}
2045
2047{
2048 DynArray<int> a;
2049 a.reserve(6);
2050 a(0) = std::numeric_limits<int>::max();
2051 a(1) = 0;
2052 a(2) = std::numeric_limits<int>::min();
2053 a(3) = -1;
2054 a(4) = std::numeric_limits<int>::max();
2055 a(5) = std::numeric_limits<int>::min();
2056
2057 radix_sort(a);
2058
2059 EXPECT_EQ(a(0), std::numeric_limits<int>::min());
2060 EXPECT_EQ(a(1), std::numeric_limits<int>::min());
2061 EXPECT_EQ(a(4), std::numeric_limits<int>::max());
2062 EXPECT_EQ(a(5), std::numeric_limits<int>::max());
2063 for (size_t i = 1; i < a.size(); ++i)
2064 ASSERT_LE(a(i - 1), a(i));
2065}
2066
2068{
2070 for (unsigned int x : {std::numeric_limits<unsigned int>::max(),
2071 0u, 10u, 1u, 1024u, 10u})
2072 a.append(x);
2073
2074 radix_sort(a);
2075
2076 EXPECT_EQ(a(0), 0u);
2077 EXPECT_EQ(a(1), 1u);
2078 EXPECT_EQ(a(2), 10u);
2079 EXPECT_EQ(a(3), 10u);
2080 EXPECT_EQ(a(a.size() - 1), std::numeric_limits<unsigned int>::max());
2081 for (size_t i = 1; i < a.size(); ++i)
2082 ASSERT_LE(a(i - 1), a(i));
2083}
2084
2086{
2087 DynArray<int> d;
2088 radix_sort(d);
2089 EXPECT_EQ(d.size(), 0u);
2090
2091 Array<int> a;
2092 a.append(7);
2093 radix_sort(a);
2094 ASSERT_EQ(a.size(), 1u);
2095 EXPECT_EQ(a(0), 7);
2096}
2097
2099{
2100 DynArray<int> v = make_dynarray({9, 2, 4, 7, 3, 7, 10, 2, 7, 1, 8, 7, 7, 7, 7});
2101 std::vector<int> expected = {9, 2, 4, 7, 3, 7, 10, 2, 7, 1, 8, 7, 7, 7, 7};
2102 std::sort(expected.begin(), expected.end());
2103
2104 for (size_t i = 0; i < v.size(); ++i)
2105 {
2106 DynArray<int> copy = v;
2107 int res = Aleph::random_select(&copy(0), static_cast<long>(i), static_cast<long>(copy.size()), std::less<int>());
2108 EXPECT_EQ(res, expected[i]) << "Mismatch at index " << i;
2109 }
2110}
2111
2113{
2114 DynArray<int> v;
2115 for (int i = 0; i < 100; ++i)
2116 v.append(42);
2117
2118 for (size_t i = 0; i < v.size(); i += 10)
2119 {
2120 DynArray<int> copy = v;
2121 int res = Aleph::random_select(&copy(0), static_cast<long>(i), static_cast<long>(copy.size()), std::less<int>());
2122 EXPECT_EQ(res, 42) << "Mismatch at index " << i;
2123 }
2124}
2125
2127{
2128 DynArray<int> v;
2129 for (int i = 0; i < 50; ++i)
2130 v.append(i);
2131
2132 DynArray<int> rev;
2133 for (int i = 49; i >= 0; --i)
2134 rev.append(i);
2135
2136 for (size_t i = 0; i < v.size(); i += 5)
2137 {
2139 DynArray<int> copy_rev = rev;
2140
2141 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));
2142 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));
2143 }
2144}
2145
2147{
2148 std::mt19937 gen(42);
2149 for (int iter = 0; iter < 100; ++iter)
2150 {
2151 const size_t N = std::uniform_int_distribution<size_t>(1, 200)(gen);
2152 DynArray<int> a;
2153 std::vector<int> expected;
2154 for (size_t i = 0; i < N; ++i)
2155 {
2156 int val = std::uniform_int_distribution<int>(-1000, 1000)(gen);
2157 a.append(val);
2158 expected.push_back(val);
2159 }
2160 std::sort(expected.begin(), expected.end());
2161
2162 const long k = std::uniform_int_distribution<long>(0, static_cast<long>(N) - 1)(gen);
2163 DynArray<int> copy = a;
2164 int res = Aleph::random_select(&copy(0), k, static_cast<long>(N), std::less<int>());
2165 EXPECT_EQ(res, expected[k]) << "Mismatch at iter " << iter << " rank " << k << " N " << N;
2166 }
2167}
2168
2169// ================================================================
2170// Bucket Sort Tests
2171// ================================================================
2172
2174{
2175 constexpr size_t N = 500;
2177 a.reserve(N);
2178 std::mt19937 gen(42);
2179 std::uniform_real_distribution<float> dist(0.0f, 1.0f);
2180 for (size_t i = 0; i < N; ++i)
2181 a(i) = dist(gen);
2182
2183 bucket_sort(a);
2184 for (size_t i = 1; i < N; ++i)
2185 ASSERT_LE(a(i - 1), a(i));
2186}
2187
2189{
2190 constexpr size_t N = 300;
2192 a.reserve(N);
2193 std::mt19937 gen(123);
2194 std::uniform_real_distribution<float> dist(-100.0f, 100.0f);
2195 for (size_t i = 0; i < N; ++i)
2196 a(i) = dist(gen);
2197
2198 bucket_sort(a);
2199 for (size_t i = 1; i < N; ++i)
2200 ASSERT_LE(a(i - 1), a(i));
2201}
2202
2204{
2205 constexpr size_t N = 200;
2207 a.reserve(N);
2208 std::mt19937 gen(77);
2209 std::uniform_real_distribution<double> dist(-50.0, 50.0);
2210 for (size_t i = 0; i < N; ++i)
2211 a(i) = dist(gen);
2212
2213 bucket_sort(a);
2214 for (size_t i = 1; i < N; ++i)
2215 ASSERT_LE(a(i - 1), a(i));
2216}
2217
2219{
2220 constexpr size_t N = 100;
2222 a.reserve(N);
2223 std::mt19937 gen(99);
2224 std::uniform_real_distribution<double> dist(-10.0, 10.0);
2225 for (size_t i = 0; i < N; ++i)
2226 a(i) = dist(gen);
2227
2229 for (size_t i = 1; i < N; ++i)
2230 ASSERT_GE(a(i - 1), a(i)) << "Failed at index " << i << " values: " << a(i-1) << ", " << a(i);
2231}
2232
2234{
2235 int a[] = {95, 23, 67, 12, 45, 78, 34, 56, 89, 1};
2236 const size_t n = sizeof(a) / sizeof(a[0]);
2237 const size_t num_buckets = 10;
2238
2239 auto key = [](const int & val) -> size_t
2240 {
2241 return static_cast<size_t>(val / 10);
2242 };
2243
2244 bucket_sort(a, n, num_buckets, key);
2245 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2246}
2247
2249{
2250 struct MoveOnlyInt
2251 {
2252 int value = 0;
2253
2254 MoveOnlyInt() = default;
2255 explicit MoveOnlyInt(const int v) : value(v) {}
2256 MoveOnlyInt(const MoveOnlyInt &) = delete;
2257 MoveOnlyInt & operator = (const MoveOnlyInt &) = delete;
2260 };
2261
2264
2265 MoveOnlyInt a[] = {
2268 };
2269 const size_t n = sizeof(a) / sizeof(a[0]);
2270 const size_t num_buckets = 4;
2271 auto key = [](const MoveOnlyInt & x) -> size_t
2272 {
2273 return static_cast<size_t>(x.value / 2);
2274 };
2275 auto cmp = [](const MoveOnlyInt & lhs, const MoveOnlyInt & rhs)
2276 {
2277 return lhs.value < rhs.value;
2278 };
2279
2280 bucket_sort(a, n, num_buckets, key, cmp);
2281
2282 for (size_t i = 1; i < n; ++i)
2283 ASSERT_LE(a[i - 1].value, a[i].value);
2284}
2285
2287{
2288 constexpr size_t N = 100;
2290 a.reserve(N);
2291 std::mt19937 gen(55);
2292 std::uniform_real_distribution<double> dist(0.0, 1.0);
2293 for (size_t i = 0; i < N; ++i)
2294 a(i) = dist(gen);
2295
2296 bucket_sort(a);
2297 for (size_t i = 1; i < N; ++i)
2298 ASSERT_LE(a(i - 1), a(i));
2299}
2300
2302{
2303 Array<double> a;
2304 std::mt19937 gen(99);
2305 std::uniform_real_distribution<double> dist(-10.0, 10.0);
2306 for (size_t i = 0; i < 50; ++i)
2307 a.append(dist(gen));
2308
2309 bucket_sort(a);
2310 for (size_t i = 1; i < a.size(); ++i)
2311 ASSERT_LE(a(i - 1), a(i));
2312}
2313
2315{
2316 double a[] = {3.5, 1.2, 4.8, 0.3, 2.7, 1.9, 4.1, 0.1};
2317 bucket_sort(a);
2318 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2319}
2320
2322{
2324 l.append(3.5);
2325 l.append(1.2);
2326 l.append(4.8);
2327 l.append(0.3);
2328 l.append(2.7);
2329
2330 bucket_sort(l);
2331
2332 double prev = -std::numeric_limits<double>::infinity();
2333 for (DynList<double>::Iterator it(l); it.has_curr(); it.next())
2334 {
2335 EXPECT_GE(it.get_curr(), prev);
2336 prev = it.get_curr();
2337 }
2338}
2339
2341{
2343 bucket_sort(d);
2344 EXPECT_EQ(d.size(), 0u);
2345
2347 s.reserve(1);
2348 s(0) = 42.0f;
2349 bucket_sort(s);
2350 ASSERT_EQ(s.size(), 1u);
2351 EXPECT_FLOAT_EQ(s(0), 42.0f);
2352}
2353
2355{
2356 constexpr size_t N = 50;
2358 a.reserve(N);
2359 for (size_t i = 0; i < N; ++i)
2360 a(i) = 7.7f;
2361
2362 bucket_sort(a);
2363 for (size_t i = 0; i < N; ++i)
2364 EXPECT_FLOAT_EQ(a(i), 7.7f);
2365}
2366
2368{
2369 constexpr size_t N = 100;
2371 a.reserve(N);
2372 for (size_t i = 0; i < N; ++i)
2373 a(i) = static_cast<double>(N - i);
2374
2375 bucket_sort(a);
2376 for (size_t i = 1; i < N; ++i)
2377 ASSERT_LE(a(i - 1), a(i));
2378}
2379
2381{
2382 EXPECT_THROW((bucket_sort<float>(nullptr, 1)), std::invalid_argument);
2383 EXPECT_NO_THROW((bucket_sort<float>(nullptr, 0)));
2384}
2385
2387{
2388 // Records with same bucket should preserve relative order
2389 struct Record
2390 {
2391 int group;
2392 int seq;
2393 };
2394
2395 Record data[] = {{0, 0}, {2, 1}, {0, 2}, {1, 3}, {2, 4}, {1, 5}};
2396 const size_t n = sizeof(data) / sizeof(data[0]);
2397 const size_t num_buckets = 3;
2398
2399 auto key = [](const Record & r) -> size_t { return r.group; };
2400 auto cmp = [](const Record & a, const Record & b) { return a.group < b.group; };
2401
2402 bucket_sort(data, n, num_buckets, key, cmp);
2403
2404 // Verify sorted by group
2405 for (size_t i = 1; i < n; ++i)
2406 ASSERT_LE(data[i - 1].group, data[i].group);
2407
2408 // Verify stability: within same group, original order preserved
2409 // Group 0: seq 0, 2
2410 EXPECT_EQ(data[0].seq, 0);
2411 EXPECT_EQ(data[1].seq, 2);
2412 // Group 1: seq 3, 5
2413 EXPECT_EQ(data[2].seq, 3);
2414 EXPECT_EQ(data[3].seq, 5);
2415 // Group 2: seq 1, 4
2416 EXPECT_EQ(data[4].seq, 1);
2417 EXPECT_EQ(data[5].seq, 4);
2418}
2419
2420
2422{
2423 int a[] = {3, 1, 2};
2424 const size_t n = 3;
2425 const size_t num_buckets = 0;
2426 auto key = [](const int &) -> size_t { return 0; };
2427
2428 // Zero buckets with n >= 2 must throw domain_error
2429 EXPECT_THROW(bucket_sort(a, n, num_buckets, key), std::domain_error);
2430}
2431
2432// ================================================================
2433// Timsort Tests
2434// ================================================================
2435
2437{
2438 constexpr size_t N = 200;
2439 DynArray<int> a;
2440 a.reserve(N);
2441 for (size_t i = 0; i < N; ++i)
2442 a(i) = static_cast<int>(i);
2443
2444 timsort(a);
2445 for (size_t i = 1; i < N; ++i)
2446 ASSERT_LE(a(i - 1), a(i));
2447}
2448
2450{
2451 constexpr size_t N = 200;
2452 DynArray<int> a;
2453 a.reserve(N);
2454 for (size_t i = 0; i < N; ++i)
2455 a(i) = static_cast<int>(N - i);
2456
2457 timsort(a);
2458 for (size_t i = 1; i < N; ++i)
2459 ASSERT_LE(a(i - 1), a(i));
2460}
2461
2463{
2464 int a[] = {5, 3, 8, 1, 9, 2, 7, 4, 6, 0};
2465 timsort(static_cast<int*>(a), size_t{10});
2466 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2467}
2468
2470{
2471 constexpr size_t N = 10000;
2472 DynArray<int> a;
2473 a.reserve(N);
2474 std::mt19937 gen(42);
2475 std::uniform_int_distribution<int> dist(-1000000, 1000000);
2476 for (size_t i = 0; i < N; ++i)
2477 a(i) = dist(gen);
2478
2479 timsort(a);
2480 for (size_t i = 1; i < N; ++i)
2481 ASSERT_LE(a(i - 1), a(i));
2482}
2483
2485{
2486 if (not std::getenv("ENABLE_PERF_TESTS"))
2487 GTEST_SKIP() << "Skipping perf test (set ENABLE_PERF_TESTS to enable)";
2488
2489 constexpr size_t N = 100000;
2490 DynArray<int> a;
2491 a.reserve(N);
2492 std::mt19937 gen(42);
2493 std::uniform_int_distribution<int> dist(-1000000, 1000000);
2494 for (size_t i = 0; i < N; ++i)
2495 a(i) = dist(gen);
2496
2497 auto start = std::chrono::steady_clock::now();
2498 timsort(a);
2499 auto end = std::chrono::steady_clock::now();
2500
2501 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
2502
2503 long max_ms = 500;
2504 if (const char * env_ms = std::getenv("TIMSORT_MAX_MS"))
2505 max_ms = std::atol(env_ms);
2506
2507 EXPECT_LE(duration, max_ms) << "Timsort performance regression detected";
2508
2509 for (size_t i = 1; i < N; ++i)
2510 ASSERT_LE(a(i - 1), a(i));
2511}
2512
2514{
2515 constexpr size_t N = 100;
2516 DynArray<int> a;
2517 a.reserve(N);
2518 for (size_t i = 0; i < N; ++i)
2519 a(i) = 42;
2520
2521 timsort(a);
2522 for (size_t i = 0; i < N; ++i)
2523 EXPECT_EQ(a(i), 42);
2524}
2525
2527{
2528 constexpr size_t N = 200;
2529 DynArray<int> a;
2530 a.reserve(N);
2531 // First half: 0, 2, 4, ... 198
2532 for (size_t i = 0; i < N / 2; ++i)
2533 a(i) = static_cast<int>(i * 2);
2534 // Second half: 1, 3, 5, ... 199
2535 for (size_t i = N / 2; i < N; ++i)
2536 a(i) = static_cast<int>((i - N / 2) * 2 + 1);
2537
2538 timsort(a);
2539 for (size_t i = 1; i < N; ++i)
2540 ASSERT_LE(a(i - 1), a(i));
2541}
2542
2544{
2545 constexpr size_t N = 50;
2546 DynArray<int> a;
2547 a.reserve(N);
2548 std::mt19937 gen(99);
2549 for (size_t i = 0; i < N; ++i)
2550 a(i) = static_cast<int>(gen() % 1000);
2551
2553 for (size_t i = 1; i < N; ++i)
2554 ASSERT_GE(a(i - 1), a(i));
2555}
2556
2558{
2559 auto a = make_dynarray({9, 1, 8, 2, 7, 3, 6, 4, 5, 0});
2560 timsort(a);
2561 for (size_t i = 1; i < a.size(); ++i)
2562 ASSERT_LE(a(i - 1), a(i));
2563}
2564
2566{
2567 Array<int> a;
2568 for (int x : {9, 1, 8, 2, 7, 3, 6, 4, 5, 0})
2569 a.append(x);
2570
2571 timsort(a);
2572 for (size_t i = 1; i < a.size(); ++i)
2573 ASSERT_LE(a(i - 1), a(i));
2574}
2575
2577{
2578 int a[] = {5, 3, 8, 1, 9, 2, 7, 4, 6, 0};
2579 timsort(a);
2580 EXPECT_TRUE(std::is_sorted(std::begin(a), std::end(a)));
2581}
2582
2584{
2585 DynList<int> l = make_dynlist({5, 3, 8, 1, 9, 2, 7, 4, 6, 0});
2586 timsort(l);
2587
2588 int prev = std::numeric_limits<int>::min();
2589 for (DynList<int>::Iterator it(l); it.has_curr(); it.next())
2590 {
2591 EXPECT_GE(it.get_curr(), prev);
2592 prev = it.get_curr();
2593 }
2594}
2595
2597{
2598 DynArray<int> d;
2599 timsort(d);
2600 EXPECT_EQ(d.size(), 0u);
2601
2602 Array<int> a;
2603 a.append(7);
2604 timsort(a);
2605 ASSERT_EQ(a.size(), 1u);
2606 EXPECT_EQ(a(0), 7);
2607}
2608
2610{
2611 EXPECT_THROW((timsort<int>(nullptr, 1)), std::invalid_argument);
2612 EXPECT_NO_THROW((timsort<int>(nullptr, 0)));
2613}
2614
2616{
2617 struct Record
2618 {
2619 int key;
2620 int seq; // original order
2621 bool operator<(const Record & rhs) const { return key < rhs.key; }
2622 };
2623
2624 Record data[] = {
2625 {3, 0}, {1, 1}, {4, 2}, {1, 3}, {5, 4},
2626 {9, 5}, {2, 6}, {6, 7}, {5, 8}, {3, 9}
2627 };
2628 const size_t n = sizeof(data) / sizeof(data[0]);
2629
2630 auto cmp = [](const Record & a, const Record & b) { return a.key < b.key; };
2631 timsort(data, n, cmp);
2632
2633 // Verify sorted by key
2634 for (size_t i = 1; i < n; ++i)
2635 ASSERT_LE(data[i - 1].key, data[i].key);
2636
2637 // Verify stability: equal keys preserve original seq order
2638 for (size_t i = 1; i < n; ++i)
2639 if (data[i - 1].key == data[i].key)
2640 EXPECT_LT(data[i - 1].seq, data[i].seq)
2641 << "Stability violated at index " << i;
2642}
2643
2645{
2647 a.append("banana");
2648 a.append("apple");
2649 a.append("cherry");
2650 a.append("date");
2651 a.append("apricot");
2652
2654
2655 EXPECT_EQ(a(0), "apple");
2656 EXPECT_EQ(a(1), "apricot");
2657 EXPECT_EQ(a(2), "banana");
2658 EXPECT_EQ(a(3), "cherry");
2659 EXPECT_EQ(a(4), "date");
2660}
2661
2662TEST(Timsort, nearly_sorted)
2663{
2664 constexpr size_t N = 500;
2665 DynArray<int> a;
2666 a.reserve(N);
2667 for (size_t i = 0; i < N; ++i)
2668 a(i) = static_cast<int>(i);
2669
2670 // Introduce a few inversions
2671 std::mt19937 gen(12);
2672 for (int k = 0; k < 10; ++k)
2673 {
2674 size_t i = gen() % N;
2675 size_t j = gen() % N;
2676 std::swap(a(i), a(j));
2677 }
2678
2679 timsort(a);
2680 for (size_t i = 1; i < N; ++i)
2681 ASSERT_LE(a(i - 1), a(i));
2682}
2683
2685{
2686 int a[] = {9, 5, 3, 8, 1, 7, 2, 6, 4, 0};
2687 // Sort only the subrange [2, 7] (inclusive)
2688 timsort(a, 2L, 7L);
2689
2690 // a[2..7] should be sorted
2691 for (int i = 3; i <= 7; ++i)
2692 ASSERT_LE(a[i - 1], a[i]);
2693
2694 // Elements outside the range should be unchanged
2695 EXPECT_EQ(a[0], 9);
2696 EXPECT_EQ(a[1], 5);
2697 EXPECT_EQ(a[8], 4);
2698 EXPECT_EQ(a[9], 0);
2699}
2700
2701TEST(Timsort, compute_minrun)
2702{
2704
2705 // n < 64: minrun == n
2706 EXPECT_EQ(compute_minrun(1), 1u);
2707 EXPECT_EQ(compute_minrun(32), 32u);
2708 EXPECT_EQ(compute_minrun(63), 63u);
2709
2710 // n == 64: minrun == 32
2711 EXPECT_EQ(compute_minrun(64), 32u);
2712
2713 // minrun should always be in [32, 64] for n >= 64
2714 for (size_t n = 64; n < 10000; ++n)
2715 {
2716 const size_t mr = compute_minrun(n);
2717 EXPECT_GE(mr, 32u) << "n=" << n;
2718 EXPECT_LE(mr, 64u) << "n=" << n;
2719 }
2720}
2721
2722} // 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
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:359
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
Helper class to compare nodes of a linked list.
Iterator on a list of Dnode objects.
Definition tpl_dnode.H:260
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
Doubly-linked list (defined in tpl_dynList.H).
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
Minimal std::expected-style result type for C++20.
#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:4129
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
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
Array< const T * > build_index_ptr(const C< T > &a, const Compare &cmp=Compare())
Build an index array of pointers for indirect sorting (const version).
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.
Array< const T * > stable_build_index_ptr(const C< T > &a, const Compare &cmp=Compare())
Build a stable index array of pointers for indirect sorting (const version).
std::pair< bool, size_t > search_inversion(const Container< T > &cont, const Compare &cmp=Compare())
Find the first inversion in a container.
void heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Sort an array using the heapsort algorithm.
Dnode< T > * dlink_random_search(Dlink &list, const T &x, const Compare &cmp=Compare())
Random search for an element in a dlink list.
Array< size_t > stable_build_index(const C &a, const Compare &cmp=Compare())
Build a stable index array for indirect sorting.
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.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
T * bsearch(C< T > &a, const T &x, const Compare &cmp=Compare())
Search for a value in a sorted container returning a pointer.
Array< size_t > build_index(const C &a, const Compare &cmp=Compare())
Build an index array for indirect sorting.
std::string code(Node *root)
Compute a string with the Lukasiewicz`s word of a tree.
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 mergesort(T *a, const long l, const long r, Array< T > &buf, Compare cmp)
Sort an array using merge sort with a reusable buffer.
void shellsort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using Shell sort.
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