From 80061d3db8d9461c2a4024bcf18485068afecf48 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 4 Oct 2024 20:12:49 +0800 Subject: [PATCH 001/289] Add files via upload --- src/SortArray.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b9eec28df..bcb4b7ba6 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -110,6 +110,8 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Shuffled Cubic")); list.Add(_("Shuffled Quintic")); list.Add(_("Shuffled n-2 Equal")); + list.Add(_("Pipe Organ")); + list.Add(_("Mirrored Organ")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -180,6 +182,33 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::random_shuffle(m_array.begin(), m_array.end()); } + else if (schema == 6) // Pipe organ (1, 1, 2, 2, 1, 1) + { + int val = 1; + for (size_t i = 0; i < m_array.size() / 2; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + val = m_array.size() / 2; + for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) + { + m_array[i] = ArrayItem(val); --val; + } + } + else if (schema == 7) // Mirrored organ (3, 2, 1, 1, 2, 3) + { + int val = m_array.size() / 2; + for (size_t i = 0; i < m_array.size() / 2; ++i) + { + m_array[i] = ArrayItem(val); --val; + } + val = 1; + for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + + } else // fallback { return FillData(0, arraysize); From a71819bc0f53a5d63b73ebe1b804102756b66536 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 00:39:21 +0800 Subject: [PATCH 002/289] Add files via upload --- src/SortAlgo.cpp | 16 ++++++++++++++ src/SortAlgo.h | 1 + src/SortArray.cpp | 55 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 866702acc..bbf7c55a6 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -47,6 +47,8 @@ const struct AlgoEntry g_algolist[] = { { _("Selection Sort"), &SelectionSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, + wxEmptyString }, { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, @@ -153,6 +155,20 @@ void SelectionSort(SortArray& A) A.unwatch_all(); } +void SandpaperSort(SortArray& A) +{ + size_t n = A.size(); + for (size_t i = 0; i < n; ++i) + { + for (size_t j = i + 1; j < n; ++j) + { + if (A[i] > A[j]) { + A.swap(i, j); + } + } + } +} + // **************************************************************************** // *** Insertion Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 3d5636243..87d774eaa 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -53,6 +53,7 @@ extern const struct AlgoEntry* g_algolist_end; // *** Sorting Algorithms void SelectionSort(class SortArray& a); +void SandpaperSort(class SortArray& a); void InsertionSort(class SortArray& a); void BinaryInsertionSort(class SortArray& a); diff --git a/src/SortArray.cpp b/src/SortArray.cpp index bcb4b7ba6..83bee4a90 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -107,6 +107,10 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Random Shuffle")); list.Add(_("Ascending")); list.Add(_("Descending")); + list.Add(_("Near Sorted")); + list.Add(_("25% Sorted")); + list.Add(_("50% Sorted")); + list.Add(_("75% Sorted")); list.Add(_("Shuffled Cubic")); list.Add(_("Shuffled Quintic")); list.Add(_("Shuffled n-2 Equal")); @@ -132,12 +136,50 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) m_array[i] = ArrayItem(i+1); } - else if (schema == 2) // Descending [1,n] + else if (schema == 2) // Descending { for (size_t i = 0; i < m_array.size(); ++i) m_array[i] = ArrayItem(m_array.size() - i); } - else if (schema == 3) // Cubic skew of [1,n] + else if (schema == 3) // Near Sorted + { + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + } + ArrayItem temp = m_array[0]; + m_array[0] = m_array[m_array.size() - 1]; + m_array[m_array.size() - 1] = temp; + } + else if (schema == 4) // 25% Sorted + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i <= (m_array.size() / 4) - 1; ++i) + { + m_array[i] = ArrayItem(i + 1); ++it; + } + std::random_shuffle(it, m_array.end()); + } + else if (schema == 5) // 50% Sorted + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i <= (m_array.size() / 2) - 1; ++i) + { + m_array[i] = ArrayItem(i + 1); ++it; + } + std::random_shuffle(it, m_array.end()); + } + else if (schema == 6) // 75% Sorted + { + std::vector::iterator it = m_array.begin(); + size_t half = m_array.size() / 2; + for (size_t i = 0; i < half + (half / 2); ++i) + { + m_array[i] = ArrayItem(i + 1); ++it; + } + std::random_shuffle(it, m_array.end()); + } + else if (schema == 7) // Cubic skew of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { @@ -154,7 +196,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::random_shuffle(m_array.begin(), m_array.end()); } - else if (schema == 4) // Quintic skew of [1,n] + else if (schema == 8) // Quintic skew of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { @@ -171,7 +213,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::random_shuffle(m_array.begin(), m_array.end()); } - else if (schema == 5) // shuffled n-2 equal values in [1,n] + else if (schema == 9) // shuffled n-2 equal values in [1,n] { m_array[0] = ArrayItem(1); for (size_t i = 1; i < m_array.size()-1; ++i) @@ -182,7 +224,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::random_shuffle(m_array.begin(), m_array.end()); } - else if (schema == 6) // Pipe organ (1, 1, 2, 2, 1, 1) + else if (schema == 10) // Pipe organ (1, 1, 2, 2, 1, 1) { int val = 1; for (size_t i = 0; i < m_array.size() / 2; ++i) @@ -195,7 +237,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val); --val; } } - else if (schema == 7) // Mirrored organ (3, 2, 1, 1, 2, 3) + else if (schema == 11) // Mirrored organ (3, 2, 1, 1, 2, 3) { int val = m_array.size() / 2; for (size_t i = 0; i < m_array.size() / 2; ++i) @@ -207,7 +249,6 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(val); ++val; } - } else // fallback { From f4e031244821144c1212d9dfd39e3729971c6372 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 00:59:38 +0800 Subject: [PATCH 003/289] Improved accuracy of n% sorted input data This change should now make the n% sorted input data more accurate and realistic, before this change, the shuffled data after the sorted portion is wrong. --- src/SortArray.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 83bee4a90..34c31a2b2 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -154,18 +154,22 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) else if (schema == 4) // 25% Sorted { std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i <= (m_array.size() / 4) - 1; ++i) + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(i + 1); ++it; + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4) - 1) + { ++it; } } std::random_shuffle(it, m_array.end()); } else if (schema == 5) // 50% Sorted { std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i <= (m_array.size() / 2) - 1; ++i) + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(i + 1); ++it; + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { ++it; } } std::random_shuffle(it, m_array.end()); } @@ -173,9 +177,11 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { std::vector::iterator it = m_array.begin(); size_t half = m_array.size() / 2; - for (size_t i = 0; i < half + (half / 2); ++i) + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(i + 1); ++it; + m_array[i] = ArrayItem(i + 1); + if (i < half + (half / 2)) + { ++it; } } std::random_shuffle(it, m_array.end()); } From 8817832241f66c9f780074d3bc9606807de26d8f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 12:36:49 +0800 Subject: [PATCH 004/289] Introduced Pancake Sort This Pancake Sort uses an optimized find_max function, allowing to search for the biggest element in n/2 time --- src/SortAlgo.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 1 + 2 files changed, 48 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index bbf7c55a6..7052355fa 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -112,6 +112,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, _("An O(1) place O(n log n) time stable merge sort.") }, + { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, + _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, wxEmptyString }, { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, @@ -1142,6 +1144,51 @@ void BozoSort(SortArray& A) } } +void flip(SortArray& A, size_t high) +{ + size_t low = 0; + while (low < high) + { + A.mark_swap(low, high); + A.swap(low, high); + ++low; --high; + } +} + +size_t find_max(SortArray& A, size_t n) // Optimized find_max method, the original method performs the search in linear time +{ + size_t max = 0; + size_t low = 1; + size_t hi = n; + while (low <= hi) + { + if (A[low] > A[max]) + { + max = low; + } + if (A[hi] > A[max]) + { + max = hi; + } + ++low; --hi; + } + return max; +} + +void PancakeSort(SortArray& A) +{ + size_t n = A.size() - 1; + for (size_t cur_size = n; cur_size >= 1; --cur_size) + { + size_t max_idx = find_max(A, cur_size); + if (max_idx != cur_size) + { + if (max_idx > 0) { flip(A, max_idx); } + flip(A, cur_size); + } + } +} + // **************************************************************************** // *** Bitonic Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 87d774eaa..0227a1af6 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -99,6 +99,7 @@ void BogoSort(class SortArray& a); void BozoSort(class SortArray& a); void StoogeSort(class SortArray& a); void SlowSort(class SortArray& a); +void PancakeSort(class SortArray& a); void CycleSort(class SortArray& a); From 213b5f4cb31e37f4fc05a27312b3cc5ccf8f4f14 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 14:52:58 +0800 Subject: [PATCH 005/289] Changed random_shuffle to shuffle The shuffle algorithm for both array generation and BogoSort/BozoSort now uses shuffle instead, I also changed the check sort function for both Bogo and Bozo Sort so that it is a little more simplified --- SortAlgo.cpp | 1749 +++++++++++++++++++++++++++++++++++++++++++++++++ SortAlgo.h | 195 ++++++ SortArray.cpp | 490 ++++++++++++++ SortArray.h | 450 +++++++++++++ 4 files changed, 2884 insertions(+) create mode 100644 SortAlgo.cpp create mode 100644 SortAlgo.h create mode 100644 SortArray.cpp create mode 100644 SortArray.h diff --git a/SortAlgo.cpp b/SortAlgo.cpp new file mode 100644 index 000000000..d467b56e3 --- /dev/null +++ b/SortAlgo.cpp @@ -0,0 +1,1749 @@ +/****************************************************************************** + * src/SortAlgo.cpp + * + * Implementations is many sorting algorithms. + * + * Note that these implementations may not be as good/fast as possible. Some + * are modified so that the visualization is more instructive. + * + * Futhermore, some algorithms are annotated using the mark() and watch() + * functions from SortArray. These functions add colors to the illustratation + * and thereby makes the algorithm's visualization easier to explain. + * + ****************************************************************************** + * The algorithms in this file are copyrighted by the original authors. All + * code is freely available. + * + * The source code added by myself (Timo Bingmann) and all modifications are + * copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#include "SortAlgo.h" + +#include +#include +#include +#include +#include + +typedef ArrayItem value_type; + +// inversion count limit for iterator instrumented algorithms +const unsigned int inversion_count_instrumented = 512; + +const struct AlgoEntry g_algolist[] = +{ + { _("Selection Sort"), &SelectionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Merge Sort"), &MergeSort, UINT_MAX, 512, + _("Merge sort which merges two sorted sequences into a shadow array," + "and then copies it back to the shown array.") }, + { _("Merge Sort (iterative)"), &MergeSortIterative, UINT_MAX, 512, + _("Merge sort variant which iteratively merges " + "subarrays of sizes of powers of two.") }, + { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, + _("Quick sort variant with left and right pointers.") }, + { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, + _("Quick sort variant from 3rd edition of CLRS: two pointers on left.") }, + { _("Quick Sort (ternary, LR ptrs)"), &QuickSortTernaryLR, UINT_MAX, UINT_MAX, + _("Ternary-split quick sort variant, adapted from multikey quicksort by " + "Bentley & Sedgewick: partitions \"==\" using two pairs of pointers " + "at left and right, then copied to middle.") }, + { _("Quick Sort (ternary, LL ptrs)"), &QuickSortTernaryLL, UINT_MAX, UINT_MAX, + _("Ternary-split quick sort variant: partitions \"<>?=\" using two " + "pointers at left and one at right. Afterwards copies the \"=\" to middle.") }, + { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, + _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " + "two at left and one at right.") }, + { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Comb Sort"), &CombSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Shell Sort"), &ShellSort, UINT_MAX, 1024, + wxEmptyString }, + { _("Heap Sort"), &HeapSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Smooth Sort"), &SmoothSort, UINT_MAX, 1024, + wxEmptyString }, + { _("Odd-Even Sort"), &OddEvenSort, UINT_MAX, 1024, + wxEmptyString }, + // older sequential implementation, which really makes little sense to do + //{ _("Bitonic Sort"), &BitonicSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Batcher's Bitonic Sort"), &BitonicSortNetwork, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Batcher's Odd-Even Merge Sort"), &BatcherSortNetwork, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Cycle Sort"), &CycleSort, 512, UINT_MAX, + wxEmptyString }, + { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, + _("Least significant digit radix sort, which copies item into a shadow " + "array during counting.") }, + { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, + _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, + { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("std::stable_sort (gcc)"), &StlStableSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("std::sort_heap (gcc)"), &StlHeapSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("Tim Sort"), &TimSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, + _("An O(1) place O(n log n) time stable merge sort.") }, + { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, + _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, + { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, + wxEmptyString }, + { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, + wxEmptyString }, + { _("Stooge Sort"), &StoogeSort, 256, inversion_count_instrumented, + wxEmptyString }, + { _("Slow Sort"), &SlowSort, 128, inversion_count_instrumented, + wxEmptyString } +}; + +const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); + +const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; + +// **************************************************************************** +// *** Selection Sort + +void SelectionSort(SortArray& A) +{ + volatile ssize_t jMin = 0; + A.watch(&jMin, 3); + + for (size_t i = 0; i < A.size()-1; ++i) + { + jMin = i; + + for (size_t j = i+1; j < A.size(); ++j) + { + if (A[j] < A[jMin]) { + A.mark_swap(j, jMin); + jMin = j; + } + } + + A.swap(i, jMin); + + // mark the last good element + if (i > 0) A.unmark(i-1); + A.mark(i); + } + A.unwatch_all(); +} + +void SandpaperSort(SortArray& A) +{ + size_t n = A.size(); + for (size_t i = 0; i < n; ++i) + { + for (size_t j = i + 1; j < n; ++j) + { + if (A[i] > A[j]) { + A.swap(i, j); + } + } + } +} + +// **************************************************************************** +// *** Insertion Sort + +// swaps every time (keeps all values visible) +void InsertionSort(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ++i) + { + value_type key = A[i]; + A.mark(i); + + ssize_t j = i - 1; + while (j >= 0 && A[j] > key) + { + A.swap(j, j+1); + j--; + } + + A.unmark(i); + } +} + +// with extra item on stack +void InsertionSort2(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ++i) + { + value_type tmp, key = A[i]; + A.mark(i); + + ssize_t j = i - 1; + while (j >= 0 && (tmp = A[j]) > key) + { + A.set(j + 1, tmp); + j--; + } + A.set(j + 1, key); + + A.unmark(i); + } +} + +// swaps every time (keeps all values visible) +void BinaryInsertionSort(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ++i) + { + value_type key = A[i]; + A.mark(i); + + int lo = 0, hi = i; + while (lo < hi) { + int mid = (lo + hi) / 2; + if (key <= A[mid]) + hi = mid; + else + lo = mid + 1; + } + + // item has to go into position lo + + ssize_t j = i - 1; + while (j >= lo) + { + A.swap(j, j+1); + j--; + } + + A.unmark(i); + } +} + +// **************************************************************************** +// *** Merge Sort (out-of-place with sentinels) + +// by myself (Timo Bingmann) + +void Merge(SortArray& A, size_t lo, size_t mid, size_t hi) +{ + // mark merge boundaries + A.mark(lo); + A.mark(mid,3); + A.mark(hi-1); + + // allocate output + std::vector out(hi-lo); + + // merge + size_t i = lo, j = mid, o = 0; // first and second halves + while (i < mid && j < hi) + { + // copy out for fewer time steps + value_type ai = A[i], aj = A[j]; + + out[o++] = (ai < aj ? (++i, ai) : (++j, aj)); + } + + // copy rest + while (i < mid) out[o++] = A[i++]; + while (j < hi) out[o++] = A[j++]; + + ASSERT(o == hi-lo); + + A.unmark(mid); + + // copy back + for (i = 0; i < hi-lo; ++i) + A.set(lo + i, out[i]); + + A.unmark(lo); + A.unmark(hi-1); +} + +void MergeSort(SortArray& A, size_t lo, size_t hi) +{ + if (lo + 1 < hi) + { + size_t mid = (lo + hi) / 2; + + MergeSort(A, lo, mid); + MergeSort(A, mid, hi); + + Merge(A, lo, mid, hi); + } +} + +void MergeSort(SortArray& A) +{ + return MergeSort(A, 0, A.size()); +} + +void MergeSortIterative(SortArray& A) +{ + for (size_t s = 1; s < A.size(); s *= 2) + { + for (size_t i = 0; i + s < A.size(); i += 2 * s) + { + Merge(A, i, i + s, + std::min(i + 2 * s, A.size())); + } + } +} + +// **************************************************************************** +// *** Quick Sort Pivot Selection + +QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST; + +// some quicksort variants use hi inclusive and some exclusive, we require it +// to be _exclusive_. hi == array.end()! +ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (g_quicksort_pivot == PIVOT_FIRST) + return lo; + + if (g_quicksort_pivot == PIVOT_LAST) + return hi-1; + + if (g_quicksort_pivot == PIVOT_MID) + return (lo + hi) / 2; + + if (g_quicksort_pivot == PIVOT_RANDOM) + return lo + (rand() % (hi - lo)); + + if (g_quicksort_pivot == PIVOT_MEDIAN3) + { + ssize_t mid = (lo + hi) / 2; + + // cases if two are equal + if (A[lo] == A[mid]) return lo; + if (A[lo] == A[hi-1] || A[mid] == A[hi-1]) return hi-1; + + // cases if three are different + return A[lo] < A[mid] + ? (A[mid] < A[hi-1] ? mid : (A[lo] < A[hi-1] ? hi-1 : lo)) + : (A[mid] > A[hi-1] ? mid : (A[lo] < A[hi-1] ? lo : hi-1)); + } + + return lo; +} + +wxArrayString QuickSortPivotText() +{ + wxArrayString sl; + + sl.Add( _("First Item") ); + sl.Add( _("Last Item") ); + sl.Add( _("Middle Item") ); + sl.Add( _("Random Item") ); + sl.Add( _("Median of Three") ); + + return sl; +} + +// **************************************************************************** +// *** Quick Sort LR (in-place, pointers at left and right, pivot is middle element) + +// by myself (Timo Bingmann), based on Hoare's original code + +void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) +{ + // pick pivot and watch + volatile ssize_t p = QuickSortSelectPivot(A, lo, hi+1); + + value_type pivot = A[p]; + A.watch(&p, 2); + + volatile ssize_t i = lo, j = hi; + A.watch(&i, 3); + A.watch(&j, 3); + + while (i <= j) + { + while (A[i] < pivot) + i++; + + while (A[j] > pivot) + j--; + + if (i <= j) + { + A.swap(i,j); + + // follow pivot if it is swapped + if (p == i) p = j; + else if (p == j) p = i; + + i++, j--; + } + } + + A.unwatch_all(); + + if (lo < j) + QuickSortLR(A, lo, j); + + if (i < hi) + QuickSortLR(A, i, hi); +} + +void QuickSortLR(SortArray& A) +{ + return QuickSortLR(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) + +// by myself (Timo Bingmann), based on CLRS' 3rd edition + +size_t PartitionLL(SortArray& A, size_t lo, size_t hi) +{ + // pick pivot and move to back + size_t p = QuickSortSelectPivot(A, lo, hi); + + value_type pivot = A[p]; + A.swap(p, hi-1); + A.mark(hi-1); + + volatile ssize_t i = lo; + A.watch(&i, 3); + + for (size_t j = lo; j < hi-1; ++j) + { + if (A[j] <= pivot) { + A.swap(i, j); + ++i; + } + } + + A.swap(i, hi-1); + A.unmark(hi-1); + A.unwatch_all(); + + return i; +} + +void QuickSortLL(SortArray& A, size_t lo, size_t hi) +{ + if (lo + 1 < hi) + { + size_t mid = PartitionLL(A, lo, hi); + + QuickSortLL(A, lo, mid); + QuickSortLL(A, mid+1, hi); + } +} + +void QuickSortLL(SortArray& A) +{ + return QuickSortLL(A, 0, A.size()); +} + +// **************************************************************************** +// *** Quick Sort Ternary (in-place, two pointers at left, pivot is first element and moved to right) + +// by myself (Timo Bingmann), loosely based on multikey quicksort by B&S + +void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi <= lo) return; + + int cmp; + + // pick pivot and swap to back + ssize_t piv = QuickSortSelectPivot(A, lo, hi+1); + A.swap(piv, hi); + A.mark(hi); + + const value_type& pivot = A[hi]; + + // schema: |p === |i <<< | ??? |j >>> |q === |piv + volatile ssize_t i = lo, j = hi-1; + volatile ssize_t p = lo, q = hi-1; + + A.watch(&i, 3); + A.watch(&j, 3); + + for (;;) + { + // partition on left + while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) + { + if (cmp == 0) { + A.mark(p,4); + A.swap(i, p++); + } + ++i; + } + + // partition on right + while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) + { + if (cmp == 0) { + A.mark(q,4); + A.swap(j, q--); + } + --j; + } + + if (i > j) break; + + // swap item between < > regions + A.swap(i++, j--); + } + + // swap pivot to right place + A.swap(i,hi); + A.mark_swap(i,hi); + + ssize_t num_less = i - p; + ssize_t num_greater = q - j; + + // swap equal ranges into center, but avoid swapping equal elements + j = i-1; i = i+1; + + ssize_t pe = lo + std::min(p-lo, num_less); + for (ssize_t k = lo; k < pe; k++, j--) { + A.swap(k,j); + A.mark_swap(k,j); + } + + ssize_t qe = hi-1 - std::min(hi-1-q, num_greater-1); // one already greater at end + for (ssize_t k = hi-1; k > qe; k--, i++) { + A.swap(i,k); + A.mark_swap(i,k); + } + + A.unwatch_all(); + A.unmark_all(); + + QuickSortTernaryLR(A, lo, lo + num_less - 1); + QuickSortTernaryLR(A, hi - num_greater + 1, hi); +} + +void QuickSortTernaryLR(SortArray& A) +{ + return QuickSortTernaryLR(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) + +// by myself (Timo Bingmann) + +std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) +{ + // pick pivot and swap to back + ssize_t p = QuickSortSelectPivot(A, lo, hi); + + value_type pivot = A[p]; + A.swap(p, hi-1); + A.mark(hi-1); + + volatile ssize_t i = lo, k = hi-1; + A.watch(&i, 3); + + for (ssize_t j = lo; j < k; ++j) + { + int cmp = A[j].cmp(pivot); // ternary comparison + if (cmp == 0) { + A.swap(--k, j); + --j; // reclassify A[j] + A.mark(k,4); + } + else if (cmp < 0) { + A.swap(i++, j); + } + } + + // unwatch i, because the pivot is swapped there + // in the first step of the following swap loop. + A.unwatch_all(); + + ssize_t j = i + (hi-k); + + for (ssize_t s = 0; s < hi-k; ++s) { + A.swap(i+s, hi-1-s); + A.mark_swap(i+s, hi-1-s); + } + A.unmark_all(); + + return std::make_pair(i,j); +} + +void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) +{ + if (lo + 1 < hi) + { + std::pair mid = PartitionTernaryLL(A, lo, hi); + + QuickSortTernaryLL(A, lo, mid.first); + QuickSortTernaryLL(A, mid.second, hi); + } +} + +void QuickSortTernaryLL(SortArray& A) +{ + return QuickSortTernaryLL(A, 0, A.size()); +} + +// **************************************************************************** +// *** Dual-Pivot Quick Sort + +// by Sebastian Wild + +void dualPivotYaroslavskiy(class SortArray& a, int left, int right) +{ + if (right > left) + { + if (a[left] > a[right]) { + a.swap(left, right); + } + + const value_type p = a[left]; + const value_type q = a[right]; + + a.mark(left); + a.mark(right); + + volatile ssize_t l = left + 1; + volatile ssize_t g = right - 1; + volatile ssize_t k = l; + + a.watch(&l, 3); + a.watch(&g, 3); + a.watch(&k, 3); + + while (k <= g) + { + if (a[k] < p) { + a.swap(k, l); + ++l; + } + else if (a[k] >= q) { + while (a[g] > q && k < g) --g; + a.swap(k, g); + --g; + + if (a[k] < p) { + a.swap(k, l); + ++l; + } + } + ++k; + } + --l; + ++g; + a.swap(left, l); + a.swap(right, g); + + a.unmark_all(); + a.unwatch_all(); + + dualPivotYaroslavskiy(a, left, l - 1); + dualPivotYaroslavskiy(a, l + 1, g - 1); + dualPivotYaroslavskiy(a, g + 1, right); + } +} + +void QuickSortDualPivot(class SortArray& a) +{ + return dualPivotYaroslavskiy(a, 0, a.size()-1); +} + +// **************************************************************************** +// *** Bubble Sort + +void BubbleSort(SortArray& A) +{ + for (size_t i = 0; i < A.size()-1; ++i) + { + for (size_t j = 0; j < A.size()-1 - i; ++j) + { + if (A[j] > A[j + 1]) + { + A.swap(j, j+1); + } + } + } +} + +// **************************************************************************** +// *** Cocktail Shaker Sort + +// from http://de.wikibooks.org/wiki/Algorithmen_und_Datenstrukturen_in_C/_Shakersort + +void CocktailShakerSort(SortArray& A) +{ + size_t lo = 0, hi = A.size()-1, mov = lo; + + while (lo < hi) + { + for (size_t i = hi; i > lo; --i) + { + if (A[i-1] > A[i]) + { + A.swap(i-1, i); + mov = i; + } + } + + lo = mov; + + for (size_t i = lo; i < hi; ++i) + { + if (A[i] > A[i+1]) + { + A.swap(i, i+1); + mov = i; + } + } + + hi = mov; + } +} + +// **************************************************************************** +// *** Gnome Sort + +// from http://en.wikipediA.org/wiki/Gnome_sort + +void GnomeSort(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ) + { + if (A[i] >= A[i-1]) + { + ++i; + } + else + { + A.swap(i, i-1); + if (i > 1) --i; + } + } +} + +// **************************************************************************** +// *** Comb Sort + +// from http://en.wikipediA.org/wiki/Comb_sort + +void CombSort(SortArray& A) +{ + const double shrink = 1.3; + + bool swapped = false; + size_t gap = A.size(); + + while ((gap > 1) || swapped) + { + if (gap > 1) { + gap = (size_t)((float)gap / shrink); + } + + swapped = false; + + for (size_t i = 0; gap + i < A.size(); ++i) + { + if (A[i] > A[i + gap]) + { + A.swap(i, i+gap); + swapped = true; + } + } + } +} + +// **************************************************************************** +// *** Odd-Even Sort + +// from http://en.wikipediA.org/wiki/Odd%E2%80%93even_sort + +void OddEvenSort(SortArray& A) +{ + bool sorted = false; + + while (!sorted) + { + sorted = true; + + for (size_t i = 1; i < A.size()-1; i += 2) + { + if(A[i] > A[i+1]) + { + A.swap(i, i+1); + sorted = false; + } + } + + for (size_t i = 0; i < A.size()-1; i += 2) + { + if(A[i] > A[i+1]) + { + A.swap(i, i+1); + sorted = false; + } + } + } +} + +// **************************************************************************** +// *** Shell Sort + +// with gaps by Robert Sedgewick from http://www.cs.princeton.edu/~rs/shell/shell.c + +void ShellSort(SortArray& A) +{ + size_t incs[16] = { 1391376, 463792, 198768, 86961, 33936, + 13776, 4592, 1968, 861, 336, + 112, 48, 21, 7, 3, 1 }; + + for (size_t k = 0; k < 16; k++) + { + for (size_t h = incs[k], i = h; i < A.size(); i++) + { + value_type v = A[i]; + size_t j = i; + + while (j >= h && A[j-h] > v) + { + A.set(j, A[j-h]); + j -= h; + } + + A.set(j, v); + } + } +} + +// **************************************************************************** +// *** Heap Sort + +// heavily adapted from http://www.codecodex.com/wiki/Heapsort + +bool isPowerOfTwo(size_t x) +{ + return ((x != 0) && !(x & (x - 1))); +} + +uint32_t prevPowerOfTwo(uint32_t x) +{ + x |= x >> 1; x |= x >> 2; x |= x >> 4; + x |= x >> 8; x |= x >> 16; + return x - (x >> 1); +} + +int largestPowerOfTwoLessThan(int n) +{ + int k = 1; + while (k < n) k = k << 1; + return k >> 1; +} + +void HeapSort(SortArray& A) +{ + size_t n = A.size(), i = n / 2; + + // mark heap levels with different colors + for (size_t j = i; j < n; ++j) + A.mark(j, log(prevPowerOfTwo(j+1)) / log(2) + 4); + + while (1) + { + if (i > 0) { + // build heap, sift A[i] down the heap + i--; + } + else { + // pop largest element from heap: swap front to back, and sift + // front A[0] down the heap + n--; + if (n == 0) return; + A.swap(0,n); + + A.mark(n); + if (n+1 < A.size()) A.unmark(n+1); + } + + size_t parent = i; + size_t child = i*2 + 1; + + // sift operation - push the value of A[i] down the heap + while (child < n) + { + if (child + 1 < n && A[child + 1] > A[child]) { + child++; + } + if (A[child] > A[parent]) { + A.swap(parent, child); + parent = child; + child = parent*2+1; + } + else { + break; + } + } + + // mark heap levels with different colors + A.mark(i, log(prevPowerOfTwo(i+1)) / log(2) + 4); + } + +} + +// **************************************************************************** +// *** Radix Sort (counting sort, most significant digit (MSD) first, in-place redistribute) + +// by myself (Timo Bingmann) + +void RadixSortMSD(SortArray& A, size_t lo, size_t hi, size_t depth) +{ + A.mark(lo); A.mark(hi-1); + + // radix and base calculations + const unsigned int RADIX = 4; + + unsigned int pmax = floor( log(A.array_max()+1) / log(RADIX) ); + ASSERT(depth <= pmax); + + size_t base = pow(RADIX, pmax - depth); + + // count digits + std::vector count(RADIX, 0); + + for (size_t i = lo; i < hi; ++i) + { + size_t r = A[i].get() / base % RADIX; + ASSERT(r < RADIX); + count[r]++; + } + + // inclusive prefix sum + std::vector bkt(RADIX, 0); + std::partial_sum(count.begin(), count.end(), bkt.begin()); + + // mark bucket boundaries + for (size_t i = 0; i < bkt.size(); ++i) { + if (bkt[i] == 0) continue; + A.mark(lo + bkt[i]-1, 3); + } + + // reorder items in-place by walking cycles + for (size_t i=0, j; i < (hi-lo); ) + { + while ( (j = --bkt[ (A[lo+i].get() / base % RADIX) ]) > i ) + { + A.swap(lo + i, lo + j); + } + i += count[ (A[lo+i].get() / base % RADIX) ]; + } + + A.unmark_all(); + + // no more depth to sort? + if (depth+1 > pmax) return; + + // recurse on buckets + size_t sum = lo; + for (size_t i = 0; i < RADIX; ++i) + { + if (count[i] > 1) + RadixSortMSD(A, sum, sum+count[i], depth+1); + sum += count[i]; + } +} + +void RadixSortMSD(SortArray& A) +{ + return RadixSortMSD(A, 0, A.size(), 0); +} + +// **************************************************************************** +// *** Radix Sort (counting sort, least significant digit (LSD) first, out-of-place redistribute) + +// by myself (Timo Bingmann) + +void RadixSortLSD(SortArray& A) +{ + // radix and base calculations + const unsigned int RADIX = 4; + + unsigned int pmax = ceil( log(A.array_max()+1) / log(RADIX) ); + + for (unsigned int p = 0; p < pmax; ++p) + { + size_t base = pow(RADIX, p); + + // count digits and copy data + std::vector count(RADIX, 0); + std::vector copy(A.size()); + + for (size_t i = 0; i < A.size(); ++i) + { + size_t r = (copy[i] = A[i]).get() / base % RADIX; + ASSERT(r < RADIX); + count[r]++; + } + + // exclusive prefix sum + std::vector bkt(RADIX+1, 0); + std::partial_sum(count.begin(), count.end(), bkt.begin()+1); + + // mark bucket boundaries + for (size_t i = 0; i < bkt.size()-1; ++i) { + if (bkt[i] >= A.size()) continue; + A.mark(bkt[i], 3); + } + + // redistribute items back into array (stable) + for (size_t i=0; i < A.size(); ++i) + { + size_t r = copy[i].get() / base % RADIX; + A.set( bkt[r]++, copy[i] ); + } + + A.unmark_all(); + } +} + +// **************************************************************************** +// *** Use STL Sorts via Iterator Adapters + +void StlSort(SortArray& A) +{ + std::sort(MyIterator(&A,0), MyIterator(&A,A.size())); +} + +void StlStableSort(SortArray& A) +{ + std::stable_sort(MyIterator(&A,0), MyIterator(&A,A.size())); +} + +void StlHeapSort(SortArray& A) +{ + std::make_heap(MyIterator(&A,0), MyIterator(&A,A.size())); + std::sort_heap(MyIterator(&A,0), MyIterator(&A,A.size())); +} + +// **************************************************************************** +// *** BogoSort and more slow sorts + +// by myself (Timo Bingmann) + +bool BogoCheckSorted(SortArray& A) +{ + size_t i; + A.mark(0); + for (i = 1; i < A.size(); ++i) + { + value_type val = A[i]; + if (A[i - 1] > A[i]) break; + A.mark(i); + } + + if (i == A.size()) { + // this is amazing. + return true; + } + + // unmark + while (i > 0) A.unmark(i--); + A.unmark(0); + + return false; +} + +void BogoSort(SortArray& A) +{ + // keep a permutation of [0,size) + std::vector perm(A.size()); + + for (size_t i = 0; i < A.size(); ++i) + perm[i] = i; + + while (1) + { + // check if array is sorted + if (BogoCheckSorted(A)) break; + + // pick a random permutation of indexes + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(perm.begin(), perm.end(), g); + + // permute array in-place + std::vector pmark(A.size(), 0); + + for (size_t i = 0; i < A.size(); ++i) + { + if (pmark[i]) continue; + + // walk a cycle + size_t j = i; + + //std::cout << "cycle start " << j << " -> " << perm[j] << "\n"; + + while ( perm[j] != i ) + { + ASSERT(!pmark[j]); + A.swap(j, perm[j]); + pmark[j] = 1; + + j = perm[j]; + //std::cout << "cycle step " << j << " -> " << perm[j] << "\n"; + } + //std::cout << "cycle end\n"; + + ASSERT(!pmark[j]); + pmark[j] = 1; + } + + //std::cout << "permute end\n"; + + for (size_t i = 0; i < A.size(); ++i) + ASSERT(pmark[i]); + } +} + +void BozoSort(SortArray& A) +{ + srand(time(NULL)); + + while (1) + { + // check if array is sorted + if (BogoCheckSorted(A)) break; + + // swap two random items + A.swap(rand() % A.size(), rand() % A.size()); + } +} + +void flip(SortArray& A, size_t high) +{ + size_t low = 0; + while (low < high) + { + A.mark_swap(low, high); + A.swap(low, high); + ++low; --high; + } +} + +size_t find_max(SortArray& A, size_t n) // Optimized find_max method, the original method performs the search in linear time +{ + size_t max = 0; + size_t low = 1; + size_t hi = n; + while (low <= hi) + { + if (A[low] > A[max]) + { + max = low; + } + if (A[hi] > A[max]) + { + max = hi; + } + ++low; --hi; + } + return max; +} + +void PancakeSort(SortArray& A) +{ + size_t n = A.size() - 1; + for (size_t cur_size = n; cur_size >= 1; --cur_size) + { + size_t max_idx = find_max(A, cur_size); + if (max_idx != cur_size) + { + if (max_idx > 0) { flip(A, max_idx); } + flip(A, cur_size); + } + } +} + +// **************************************************************************** +// *** Bitonic Sort + +// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm + +namespace BitonicSortNS { + +static const bool ASCENDING = true; // sorting direction + +static void compare(SortArray& A, int i, int j, bool dir) +{ + if (dir == (A[i] > A[j])) + A.swap(i, j); +} + +static void bitonicMerge(SortArray& A, int lo, int n, bool dir) +{ + if (n > 1) + { + int m = largestPowerOfTwoLessThan(n); + + for (int i = lo; i < lo + n - m; i++) + compare(A, i, i+m, dir); + + bitonicMerge(A, lo, m, dir); + bitonicMerge(A, lo + m, n - m, dir); + } +} + +static void bitonicSort(SortArray& A, int lo, int n, bool dir) +{ + if (n > 1) + { + int m = n / 2; + bitonicSort(A, lo, m, !dir); + bitonicSort(A, lo + m, n - m, dir); + bitonicMerge(A, lo, n, dir); + } +} + +} // namespace BitonicSortNS + +void BitonicSort(SortArray& A) +{ + BitonicSortNS::bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING); +} + +// **************************************************************************** +// *** Bitonic Sort as "Parallel" Sorting Network + +// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm + +// modified to first record the recursively generated swap sequence, and then +// sort it back into the order a parallel sorting network would perform the +// swaps in + +namespace BitonicSortNetworkNS { + +struct swappair_type +{ + // swapped positions + unsigned int i,j; + + // depth of recursions: sort / merge + unsigned int sort_depth, merge_depth; + + swappair_type(unsigned int _i, unsigned int _j, + unsigned int _sort_depth, unsigned int _merge_depth) + : i(_i), j(_j), + sort_depth(_sort_depth), merge_depth(_merge_depth) + { } + + // order relation for sorting swaps + bool operator < (const swappair_type& b) const + { + if (sort_depth != b.sort_depth) + return sort_depth > b.sort_depth; + + if (merge_depth != b.merge_depth) + return merge_depth < b.merge_depth; + + return i < b.i; + } +}; + +typedef std::vector sequence_type; +std::vector sequence; + +void replay(SortArray& A) +{ + for (sequence_type::const_iterator si = sequence.begin(); + si != sequence.end(); ++si) + { + if (A[si->i] > A[si->j]) + A.swap(si->i, si->j); + } +} + +static const bool ASCENDING = true; // sorting direction + +static void compare(SortArray& /* A */, unsigned int i, unsigned int j, bool dir, + unsigned int sort_depth, unsigned int merge_depth) +{ + // if (dir == (A[i] > A[j])) A.swap(i, j); + + if (dir) + sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); + else + sequence.push_back( swappair_type(j,i, sort_depth, merge_depth) ); +} + +static void bitonicMerge(SortArray& A, unsigned int lo, unsigned int n, bool dir, + unsigned int sort_depth, unsigned int merge_depth) +{ + if (n > 1) + { + unsigned int m = largestPowerOfTwoLessThan(n); + + for (unsigned int i = lo; i < lo + n - m; i++) + compare(A, i, i + m, dir, sort_depth, merge_depth); + + bitonicMerge(A, lo, m, dir, sort_depth, merge_depth+1); + bitonicMerge(A, lo + m, n - m, dir, sort_depth, merge_depth+1); + } +} + +static void bitonicSort(SortArray& A, unsigned int lo, unsigned int n, bool dir, + unsigned int sort_depth) +{ + if (n > 1) + { + unsigned int m = n / 2; + bitonicSort(A, lo, m, !dir, sort_depth+1); + bitonicSort(A, lo + m, n - m, dir, sort_depth+1); + bitonicMerge(A, lo, n, dir, sort_depth, 0); + } +} + +void sort(SortArray& A) +{ + sequence.clear(); + bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING, 0); + std::sort(sequence.begin(), sequence.end()); + replay(A); + sequence.clear(); +} + +} // namespace BitonicSortNS + +void BitonicSortNetwork(SortArray& A) +{ + BitonicSortNetworkNS::sort(A); +} + +// **************************************************************************** +// *** Batcher's Odd-Even Merge Sort as "Parallel" Sorting Network + +// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/oemen.htm + +// modified to first record the recursively generated swap sequence, and then +// sort it back into the order a parallel sorting network would perform the +// swaps in + +namespace BatcherSortNetworkNS { + +struct swappair_type +{ + // swapped positions + unsigned int i,j; + + // depth of recursions: sort / merge + unsigned int sort_depth, merge_depth; + + swappair_type(unsigned int _i, unsigned int _j, + unsigned int _sort_depth, unsigned int _merge_depth) + : i(_i), j(_j), + sort_depth(_sort_depth), merge_depth(_merge_depth) + { } + + // order relation for sorting swaps + bool operator < (const swappair_type& b) const + { + if (sort_depth != b.sort_depth) + return sort_depth > b.sort_depth; + + if (merge_depth != b.merge_depth) + return merge_depth > b.merge_depth; + + return i < b.i; + } +}; + +typedef std::vector sequence_type; +std::vector sequence; + +void replay(SortArray& A) +{ + for (sequence_type::const_iterator si = sequence.begin(); + si != sequence.end(); ++si) + { + if (A[si->i] > A[si->j]) + A.swap(si->i, si->j); + } +} + +static void compare(SortArray& A, unsigned int i, unsigned int j, + unsigned int sort_depth, unsigned int merge_depth) +{ + // skip all swaps beyond end of array + ASSERT(i < j); + if (j >= A.size()) return; + + sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); + + //if (A[i] > A[j]) A.swap(i, j); +} + +// lo is the starting position and n is the length of the piece to be merged, r +// is the distance of the elements to be compared +static void oddEvenMerge(SortArray& A, unsigned int lo, unsigned int n, unsigned int r, + unsigned int sort_depth, unsigned int merge_depth) +{ + unsigned int m = r * 2; + if (m < n) + { + // even subsequence + oddEvenMerge(A, lo, n, m, sort_depth, merge_depth+1); + // odd subsequence + oddEvenMerge(A, lo + r, n, m, sort_depth, merge_depth+1); + + for (unsigned int i = lo + r; i + r < lo + n; i += m) + compare(A, i, i + r, sort_depth, merge_depth); + } + else { + compare(A, lo, lo + r, sort_depth, merge_depth); + } +} + +// sorts a piece of length n of the array starting at position lo +static void oddEvenMergeSort(SortArray& A, unsigned int lo, unsigned int n, + unsigned int sort_depth) +{ + if (n > 1) + { + unsigned int m = n / 2; + oddEvenMergeSort(A, lo, m, sort_depth+1); + oddEvenMergeSort(A, lo + m, m, sort_depth+1); + oddEvenMerge(A, lo, n, 1, sort_depth, 0); + } +} + +void sort(SortArray& A) +{ + sequence.clear(); + + unsigned int n = largestPowerOfTwoLessThan(A.size()); + if (n != A.size()) n *= 2; + + oddEvenMergeSort(A, 0, n, 0); + std::sort(sequence.begin(), sequence.end()); + replay(A); + sequence.clear(); +} + +} // namespace BatcherSortNetworkNS + +void BatcherSortNetwork(SortArray& A) +{ + BatcherSortNetworkNS::sort(A); +} + +// **************************************************************************** +// *** Smooth Sort + +// from http://en.wikipediA.org/wiki/Smoothsort + +namespace SmoothSortNS { + +static const int LP[] = { + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, + 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, + 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, + 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, + 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, + 866988873 // the next number is > 31 bits. +}; + +static void sift(SortArray& A, int pshift, int head) +{ + // we do not use Floyd's improvements to the heapsort sift, because we + // are not doing what heapsort does - always moving nodes from near + // the bottom of the tree to the root. + + value_type val = A[head]; + + while (pshift > 1) + { + int rt = head - 1; + int lf = head - 1 - LP[pshift - 2]; + + if (val.cmp(A[lf]) >= 0 && val.cmp(A[rt]) >= 0) + break; + + if (A[lf].cmp(A[rt]) >= 0) { + A.set(head, A[lf]); + head = lf; + pshift -= 1; + } + else { + A.set(head, A[rt]); + head = rt; + pshift -= 2; + } + } + + A.set(head, val); +} + +static void trinkle(SortArray& A, int p, int pshift, int head, bool isTrusty) +{ + value_type val = A[head]; + + while (p != 1) + { + int stepson = head - LP[pshift]; + + if (A[stepson].cmp(val) <= 0) + break; // current node is greater than head. sift. + + // no need to check this if we know the current node is trusty, + // because we just checked the head (which is val, in the first + // iteration) + if (!isTrusty && pshift > 1) { + int rt = head - 1; + int lf = head - 1 - LP[pshift - 2]; + if (A[rt].cmp(A[stepson]) >= 0 || + A[lf].cmp(A[stepson]) >= 0) + break; + } + + A.set(head, A[stepson]); + + head = stepson; + //int trail = Integer.numberOfTrailingZeros(p & ~1); + int trail = __builtin_ctz(p & ~1); + p >>= trail; + pshift += trail; + isTrusty = false; + } + + if (!isTrusty) { + A.set(head, val); + sift(A, pshift, head); + } +} + +void sort(SortArray& A, int lo, int hi) +{ + int head = lo; // the offset of the first element of the prefix into m + + // These variables need a little explaining. If our string of heaps + // is of length 38, then the heaps will be of size 25+9+3+1, which are + // Leonardo numbers 6, 4, 2, 1. + // Turning this into a binary number, we get b01010110 = 0x56. We represent + // this number as a pair of numbers by right-shifting all the zeros and + // storing the mantissa and exponent as "p" and "pshift". + // This is handy, because the exponent is the index into L[] giving the + // size of the rightmost heap, and because we can instantly find out if + // the rightmost two heaps are consecutive Leonardo numbers by checking + // (p&3)==3 + + int p = 1; // the bitmap of the current standard concatenation >> pshift + int pshift = 1; + + while (head < hi) + { + if ((p & 3) == 3) { + // Add 1 by merging the first two blocks into a larger one. + // The next Leonardo number is one bigger. + sift(A, pshift, head); + p >>= 2; + pshift += 2; + } + else { + // adding a new block of length 1 + if (LP[pshift - 1] >= hi - head) { + // this block is its final size. + trinkle(A, p, pshift, head, false); + } else { + // this block will get merged. Just make it trusty. + sift(A, pshift, head); + } + + if (pshift == 1) { + // LP[1] is being used, so we add use LP[0] + p <<= 1; + pshift--; + } else { + // shift out to position 1, add LP[1] + p <<= (pshift - 1); + pshift = 1; + } + } + p |= 1; + head++; + } + + trinkle(A, p, pshift, head, false); + + while (pshift != 1 || p != 1) + { + if (pshift <= 1) { + // block of length 1. No fiddling needed + //int trail = Integer.numberOfTrailingZeros(p & ~1); + int trail = __builtin_ctz(p & ~1); + p >>= trail; + pshift += trail; + } + else { + p <<= 2; + p ^= 7; + pshift -= 2; + + // This block gets broken into three bits. The rightmost bit is a + // block of length 1. The left hand part is split into two, a block + // of length LP[pshift+1] and one of LP[pshift]. Both these two + // are appropriately heapified, but the root nodes are not + // necessarily in order. We therefore semitrinkle both of them + + trinkle(A, p >> 1, pshift + 1, head - LP[pshift] - 1, true); + trinkle(A, p, pshift, head - 1, true); + } + + head--; + } +} + +} // namespace SmoothSortNS + +void SmoothSort(SortArray& A) +{ + return SmoothSortNS::sort(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Stooge Sort + +void StoogeSort(SortArray& A, int i, int j) +{ + if (A[i] > A[j]) + { + A.swap(i, j); + } + + if (j - i + 1 >= 3) + { + int t = (j - i + 1) / 3; + + A.mark(i, 3); + A.mark(j, 3); + + StoogeSort(A, i, j-t); + StoogeSort(A, i+t, j); + StoogeSort(A, i, j-t); + + A.unmark(i); + A.unmark(j); + } +} + +void StoogeSort(SortArray& A) +{ + StoogeSort(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Slow Sort + +void SlowSort(SortArray& A, int i, int j) +{ + if (i >= j) return; + + int m = (i + j) / 2; + + SlowSort(A, i, m); + SlowSort(A, m+1, j); + + if (A[m] > A[j]) + A.swap(m, j); + + A.mark(j, 2); + + SlowSort(A, i, j-1); + + A.unmark(j); +} + +void SlowSort(SortArray& A) +{ + SlowSort(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Cycle Sort + +// Adapted from http://en.wikipedia.org/wiki/Cycle_sort + +void CycleSort(SortArray& array, ssize_t n) +{ + volatile ssize_t cycleStart = 0; + array.watch(&cycleStart, 16); + + volatile ssize_t rank = 0; + array.watch(&rank, 3); + + // Loop through the array to find cycles to rotate. + for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) + { + value_type& item = array.get_mutable(cycleStart); + + do { + // Find where to put the item. + rank = cycleStart; + for (ssize_t i = cycleStart + 1; i < n; ++i) + { + if (array[i] < item) + rank++; + } + + // If the item is already there, this is a 1-cycle. + if (rank == cycleStart) { + array.mark(rank, 2); + break; + } + + // Otherwise, put the item after any duplicates. + while (item == array[rank]) + rank++; + + // Put item into right place and colorize + std::swap(array.get_mutable(rank), item); + array.mark(rank, 2); + + // Continue for rest of the cycle. + } + while (rank != cycleStart); + } + + array.unwatch_all(); +} + +void CycleSort(SortArray& A) +{ + CycleSort(A, A.size()); +} + +// **************************************************************************** diff --git a/SortAlgo.h b/SortAlgo.h new file mode 100644 index 000000000..0227a1af6 --- /dev/null +++ b/SortAlgo.h @@ -0,0 +1,195 @@ +/****************************************************************************** + * src/SortAlgo.h + * + * Implementations of many sorting algorithms. + * + * Note that these implementations may not be as good/fast as possible. Some + * are modified so that the visualization is more instructive. + * + * Futhermore, some algorithms are annotated using the mark() and watch() + * functions from SortArray. These functions add colors to the illustratation + * and thereby makes the algorithm's visualization easier to explain. + * + ****************************************************************************** + * Copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#ifndef SORTALGO_H +#define SORTALGO_H + +#include +#include "SortArray.h" + +// *** List of Sorting Algorithms + +struct AlgoEntry +{ + wxString name; + void (*func)(class SortArray&); + // maximum item count for test runs + unsigned int max_testsize; + // count inversions if n <= limit + unsigned int inversion_count_limit; + wxString text; +}; + +extern const struct AlgoEntry g_algolist[]; +extern const size_t g_algolist_size; +extern const struct AlgoEntry* g_algolist_end; + +// *** Sorting Algorithms + +void SelectionSort(class SortArray& a); +void SandpaperSort(class SortArray& a); +void InsertionSort(class SortArray& a); +void BinaryInsertionSort(class SortArray& a); + +void MergeSort(class SortArray& a); +void MergeSortIterative(class SortArray& a); + +wxArrayString QuickSortPivotText(); + +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3 }; +extern QuickSortPivotType g_quicksort_pivot; + +void QuickSortLR(class SortArray& a); +void QuickSortLL(class SortArray& a); +void QuickSortTernaryLR(class SortArray& a); +void QuickSortTernaryLL(class SortArray& a); +void QuickSortDualPivot(class SortArray& a); + +void BubbleSort(class SortArray& a); +void CocktailShakerSort(class SortArray& a); +void CombSort(class SortArray& a); +void GnomeSort(class SortArray& a); +void OddEvenSort(class SortArray& a); + +void ShellSort(SortArray& a); +void HeapSort(class SortArray& a); +void SmoothSort(class SortArray& a); + +void BitonicSort(SortArray& a); +void BitonicSortNetwork(SortArray& a); +void BatcherSortNetwork(SortArray& a); + +void RadixSortLSD(class SortArray& a); +void RadixSortMSD(class SortArray& a); + +void StlSort(class SortArray& a); +void StlStableSort(class SortArray& a); +void StlHeapSort(class SortArray& a); + +void TimSort(class SortArray& a); +void WikiSort(class SortArray& a); + +void BogoSort(class SortArray& a); +void BozoSort(class SortArray& a); +void StoogeSort(class SortArray& a); +void SlowSort(class SortArray& a); +void PancakeSort(class SortArray& a); + +void CycleSort(class SortArray& a); + +// **************************************************************************** +// *** Iterator Adapter + +// iterator based on http://zotu.blogspot.de/2010/01/creating-random-access-iterator.html + +class MyIterator : public std::iterator +{ +protected: + SortArray* m_array; + size_t m_pos; + +public: + typedef std::iterator base_type; + + typedef std::random_access_iterator_tag iterator_category; + + typedef base_type::value_type value_type; + typedef base_type::difference_type difference_type; + typedef base_type::reference reference; + typedef base_type::pointer pointer; + + MyIterator() : m_array(NULL), m_pos(0) {} + + MyIterator(SortArray* A, size_t p) : m_array(A), m_pos(p) {} + + MyIterator(const MyIterator& r) : m_array(r.m_array), m_pos(r.m_pos) {} + + MyIterator& operator=(const MyIterator& r) + { m_array = r.m_array, m_pos = r.m_pos; return *this; } + + MyIterator& operator++() + { ++m_pos; return *this; } + + MyIterator& operator--() + { --m_pos; return *this; } + + MyIterator operator++(int) + { return MyIterator(m_array, m_pos++); } + + MyIterator operator--(int) + { return MyIterator(m_array, m_pos--); } + + MyIterator operator+(const difference_type& n) const + { return MyIterator(m_array, m_pos + n); } + + MyIterator& operator+=(const difference_type& n) + { m_pos += n; return *this; } + + MyIterator operator-(const difference_type& n) const + { return MyIterator(m_array, m_pos - n); } + + MyIterator& operator-=(const difference_type& n) + { m_pos -= n; return *this; } + + reference operator*() const + { return m_array->get_mutable(m_pos); } + + pointer operator->() const + { return &(m_array->get_mutable(m_pos)); } + + reference operator[](const difference_type& n) const + { return m_array->get_mutable(m_pos + n); } + + bool operator==(const MyIterator& r) + { return (m_array == r.m_array) && (m_pos == r.m_pos); } + + bool operator!=(const MyIterator& r) + { return (m_array != r.m_array) || (m_pos != r.m_pos); } + + bool operator<(const MyIterator& r) + { return (m_array == r.m_array ? (m_pos < r.m_pos) : (m_array < r.m_array)); } + + bool operator>(const MyIterator& r) + { return (m_array == r.m_array ? (m_pos > r.m_pos) : (m_array > r.m_array)); } + + bool operator<=(const MyIterator& r) + { return (m_array == r.m_array ? (m_pos <= r.m_pos) : (m_array <= r.m_array)); } + + bool operator>=(const MyIterator& r) + { return (m_array == r.m_array ? (m_pos >= r.m_pos) : (m_array >= r.m_array)); } + + difference_type operator+(const MyIterator& r2) const + { ASSERT(m_array == r2.m_array); return (m_pos + r2.m_pos); } + + difference_type operator-(const MyIterator& r2) const + { ASSERT(m_array == r2.m_array); return (m_pos - r2.m_pos); } +}; + + +#endif // SORTALGO_H diff --git a/SortArray.cpp b/SortArray.cpp new file mode 100644 index 000000000..ac9489820 --- /dev/null +++ b/SortArray.cpp @@ -0,0 +1,490 @@ +/******************************************************************************* + * src/SortArray.cpp + * + * SortArray represents a simple array, which is displayed by WSortView to the + * user is real-time. + * + ******************************************************************************* + * Copyright (C) 2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + ******************************************************************************/ + +#include "SortArray.h" +#include "SortAlgo.h" + +#include +#include + +extern void SoundAccess(size_t i); + +// ***************************************************************************** +// *** Comparisons of ArrayItems + +size_t g_compare_count = 0; + +size_t g_access_count = 0; + +void ArrayItem::OnAccess(const ArrayItem& a) +{ + SoundAccess(a.get_direct()); +} + +void ArrayItem::OnComparison(const ArrayItem& a, const ArrayItem& b) +{ + ++g_compare_count; + + SoundAccess(a.get_direct()); + SoundAccess(b.get_direct()); +} + +// ***************************************************************************** +// *** SortArray + +SortArray::SortArray() + : m_calc_inversions(false), + m_delay(NULL) +{ +} + +void SortArray::OnAlgoLaunch(const AlgoEntry& ae) +{ + if (size() <= ae.inversion_count_limit) + { + m_calc_inversions = true; + RecalcInversions(); + } + else + { + m_calc_inversions = false; + m_inversions = -1; + } +} + +void SortArray::ResetArray(size_t size) +{ + m_array.resize(size, ArrayItem(0)); + m_mark.resize(size); +} + +void SortArray::FinishFill() +{ + ASSERT(m_array.size() > 0); + + // calculate max value in array + m_array_max = m_array[0].get_direct(); + for (size_t i = 1; i < size(); ++i) + { + if (m_array_max < m_array[i].get_direct()) + m_array_max = m_array[i].get_direct(); + } + + // reset access markers + unmark_all(); + unwatch_all(); + + // reset counters and info + m_is_sorted = false; + g_access_count = 0; + g_compare_count = 0; + m_calc_inversions = true; + + RecalcInversions(); +} + +void SortArray::FillInputlist(wxArrayString& list) +{ + list.Add(_("Random Shuffle")); + list.Add(_("Ascending")); + list.Add(_("Descending")); + list.Add(_("Near Sorted")); + list.Add(_("25% Sorted")); + list.Add(_("50% Sorted")); + list.Add(_("75% Sorted")); + list.Add(_("Shuffled Cubic")); + list.Add(_("Shuffled Quintic")); + list.Add(_("Shuffled n-2 Equal")); + list.Add(_("Pipe Organ")); + list.Add(_("Mirrored Organ")); +} + +void SortArray::FillData(unsigned int schema, size_t arraysize) +{ + if (arraysize == 0) arraysize = 1; + { ResetArray(arraysize); } + std::random_device rd; + std::mt19937 g(rd()); + if (schema == 0) // Shuffle of [1,n] + { + for (size_t i = 0; i < m_array.size(); ++i) + m_array[i] = ArrayItem(i+1); + + std::shuffle(m_array.begin(), m_array.end(), g); + } + else if (schema == 1) // Ascending [1,n] + { + for (size_t i = 0; i < m_array.size(); ++i) + m_array[i] = ArrayItem(i+1); + } + else if (schema == 2) // Descending + { + for (size_t i = 0; i < m_array.size(); ++i) + m_array[i] = ArrayItem(m_array.size() - i); + } + else if (schema == 3) // Near Sorted + { + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + } + ArrayItem temp = m_array[0]; + m_array[0] = m_array[m_array.size() - 1]; + m_array[m_array.size() - 1] = temp; + } + else if (schema == 4) // 25% Sorted + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4) - 1) + { ++it; } + } + std::shuffle(it, m_array.end(), g); + } + else if (schema == 5) // 50% Sorted + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { ++it; } + } + std::shuffle(it, m_array.end(), g); + } + else if (schema == 6) // 75% Sorted + { + std::vector::iterator it = m_array.begin(); + size_t half = m_array.size() / 2; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i < half + (half / 2)) + { ++it; } + } + std::shuffle(it, m_array.end(), g); + } + else if (schema == 7) // Cubic skew of [1,n] + { + for (size_t i = 0; i < m_array.size(); ++i) + { + // normalize to [-1,+1] + double x = (2.0 * (double)i / m_array.size()) - 1.0; + // calculate x^3 + double v = x * x * x; + // normalize to array size + double w = (v + 1.0) / 2.0 * arraysize + 1; + // decrease resolution for more equal values + w /= 3.0; + m_array[i] = ArrayItem(w + 1); + } + + std::shuffle(m_array.begin(), m_array.end(), g); + } + else if (schema == 8) // Quintic skew of [1,n] + { + for (size_t i = 0; i < m_array.size(); ++i) + { + // normalize to [-1,+1] + double x = (2.0 * (double)i / m_array.size()) - 1.0; + // calculate x^5 + double v = x * x * x * x * x; + // normalize to array size + double w = (v + 1.0) / 2.0 * arraysize + 1; + // decrease resolution for more equal values + w /= 3.0; + m_array[i] = ArrayItem(w + 1); + } + + std::shuffle(m_array.begin(), m_array.end(), g); + } + else if (schema == 9) // shuffled n-2 equal values in [1,n] + { + m_array[0] = ArrayItem(1); + for (size_t i = 1; i < m_array.size()-1; ++i) + { + m_array[i] = ArrayItem( arraysize / 2 + 1 ); + } + m_array[m_array.size()-1] = ArrayItem(arraysize); + + std::shuffle(m_array.begin(), m_array.end(), g); + } + else if (schema == 10) // Pipe organ (1, 1, 2, 2, 1, 1) + { + int val = 1; + for (size_t i = 0; i < m_array.size() / 2; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + val = m_array.size() / 2; + for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) + { + m_array[i] = ArrayItem(val); --val; + } + } + else if (schema == 11) // Mirrored organ (3, 2, 1, 1, 2, 3) + { + int val = m_array.size() / 2; + for (size_t i = 0; i < m_array.size() / 2; ++i) + { + m_array[i] = ArrayItem(val); --val; + } + val = 1; + for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + } + else // fallback + { + return FillData(0, arraysize); + } + + FinishFill(); +} + +void SortArray::OnAccess() +{ + ++g_access_count; + + if (m_delay) + m_delay->OnAccess(); +} + +bool SortArray::CheckSorted() +{ + unmark_all(); + // needed because iterator instrumentated algorithms may have changed the array + RecalcInversions(); + + ArrayItem prev = get_nocount(0); + mark(0); + + bool is_sorted = true; + + for (size_t i = 1; i < size(); ++i) + { + ArrayItem key = get_nocount(i); + g_compare_count--; // dont count the following comparison + if (!(prev <= key)) { + wxLogError(_T("Result of sorting algorithm is incorrect!")); + is_sorted = false; + break; + } + mark(i); + prev = key; + } + + unmark_all(); + + return (m_is_sorted = is_sorted); +} + +void SortArray::SetCalcInversions(bool on) +{ + // toggle boolean + m_calc_inversions = on; + + if (!m_calc_inversions) + m_inversions = -1; +} + +void SortArray::ToggleCalcInversions() +{ + // toggle boolean + SetCalcInversions(!m_calc_inversions); +} + +void SortArray::RecalcInversions() +{ + if (!m_calc_inversions) { + m_inversions = -1; + return; + } + + unsigned int inversions = 0; + + for (size_t i = 0; i < size(); ++i) + { + const ArrayItem& a = direct(i); + + for (size_t j = i+1; j < size(); ++j) + { + const ArrayItem& b = direct(j); + + if ( a.greater_direct(b) ) + { + inversions++; + } + } + } + + m_inversions = inversions; +} + +void SortArray::UpdateInversions(size_t i, size_t j) +{ + if (!m_calc_inversions) { + m_inversions = -1; + return; + } + if (m_inversions < 0) return RecalcInversions(); + + if (i == j) return; + + unsigned int lo = i, hi = j; + if (lo > hi) std::swap(lo, hi); + + const ArrayItem& ilo = m_array[lo]; + const ArrayItem& ihi = m_array[hi]; + int invdelta = 0; + + for (size_t k = lo + 1; k < hi; ++k) + { + if (m_array[k].less_direct(ilo)) + invdelta--; + if (m_array[k].greater_direct(ilo)) + invdelta++; + + if (m_array[k].less_direct(ihi)) + invdelta++; + if (m_array[k].greater_direct(ihi)) + invdelta--; + } + + if (ilo.less_direct(ihi)) + invdelta++; + if (ilo.greater_direct(ihi)) + invdelta--; + + m_inversions += invdelta; +} + +size_t SortArray::GetRuns() const +{ + unsigned int runs = 1; + + for (size_t i = 1; i < size(); ++i) + { + const ArrayItem& a = direct(i-1); + const ArrayItem& b = direct(i); + + if ( a.greater_direct(b) ) + { + runs++; + } + } + + return runs; +} + +short SortArray::InAccessList(ssize_t idx) +{ + if (idx < 0) return -1; + + signed color = -1; + signed priority = -1; + + for (std::vector::iterator it = m_access_list.begin(); + it != m_access_list.end(); ) + { + if (it->index != (size_t)idx) { + ++it; + continue; + } + + if (it->priority >= priority) + { + priority = it->priority; + color = it->color; + } + + if (it->sustain == 0) { + if (it->index == m_access1.index || + it->index == m_access2.index) + { + ++it; + } + else + { + it = m_access_list.erase(it); + } + } + else { + it->sustain--; + ++it; + } + } + + return color; +} + +unsigned short SortArray::InWatchList(ssize_t idx) const +{ + for (size_t i = 0; i < m_watch.size(); ++i) + { + if (m_watch[i].first == NULL) continue; + + // compare watched value + if (*m_watch[i].first != idx) continue; + + return m_watch[i].second; + } + return 0; +} + +int SortArray::GetIndexColor(size_t idx) +{ + int clr; + + // select color + if (idx == m_access1.index) + { + clr = m_access1.color; + } + else if (idx == m_access2.index) + { + clr = m_access2.color; + } + else if ( (clr = InWatchList(idx)) != 0 ) + { + // clr already set + } + else if (m_mark[idx] != 0) + { + clr = m_mark[idx]; + } + else if ( (clr = InAccessList(idx)) >= 0 ) + { + } + else + { + clr = 0; + } + + return clr; +} + +// ***************************************************************************** diff --git a/SortArray.h b/SortArray.h new file mode 100644 index 000000000..7a1874d24 --- /dev/null +++ b/SortArray.h @@ -0,0 +1,450 @@ +/******************************************************************************* + * src/SortArray.h + * + * SortArray represents a simple array, which is displayed by WSortView to the + * user is real-time. + * + ******************************************************************************* + * Copyright (C) 2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + ******************************************************************************/ + +#ifndef SORT_ARRAY_HEADER +#define SORT_ARRAY_HEADER + +#include +#include +#include + +#include +#include +#include + +// ---------------------------------------------------------------------------- + +/// custom assertion (also active in release mode) +#define ASSERT(cond) do { if (!(cond)) { \ + wxLogError(_("Assertion failed:\n%s in %s:%d"), \ + _T(#cond), _T(__FILE__), __LINE__); \ + wxLog::FlushActive(); \ + abort(); \ +} } while(0) + +// ---------------------------------------------------------------------------- + +/// globally count the number of comparisons done on value_type +extern size_t g_compare_count; + +/// globally count the number of array access +extern size_t g_access_count; + +// custom struct for array items, which allows detailed counting of comparisons. +class ArrayItem +{ +public: + typedef int value_type; + +protected: + value_type value; + +public: + ArrayItem() {} + + explicit ArrayItem(const value_type& d) : value(d) {} + + ArrayItem(const ArrayItem& v) : value(v.value) {} + + // ArrayItem has no implicit data cast, because most sorting algorithms use + // comparisons. However, radix sort and similar use the following data + // accessor. To add sound for these, we use a separate callback. + const value_type& get() const + { OnAccess(*this); return value; } + + static void OnAccess(const ArrayItem& a); + + // for direct data access by visualizer + const value_type& get_direct() const + { return value; } + + // *** comparisons + + bool operator== (const ArrayItem& v) const + { OnComparison(*this,v); return (value == v.value); } + + bool operator!= (const ArrayItem& v) const + { OnComparison(*this,v); return (value != v.value); } + + bool operator< (const ArrayItem& v) const + { OnComparison(*this,v); return (value < v.value); } + + bool operator<= (const ArrayItem& v) const + { OnComparison(*this,v); return (value <= v.value); } + + bool operator> (const ArrayItem& v) const + { OnComparison(*this,v); return (value > v.value); } + + bool operator>= (const ArrayItem& v) const + { OnComparison(*this,v); return (value >= v.value); } + + // ternary comparison which counts just one + int cmp(const ArrayItem& v) const + { + OnComparison(*this,v); + return (value == v.value ? 0 : value < v.value ? -1 : +1); + } + + // *** comparisons without sound, counting or delay + + bool equal_direct(const ArrayItem& v) const + { return (value == v.value); } + + bool less_direct(const ArrayItem& v) const + { return (value < v.value); } + + bool greater_direct(const ArrayItem& v) const + { return (value > v.value); } + + static void OnComparison(const ArrayItem& a, const ArrayItem& b); +}; + +// ---------------------------------------------------------------------------- + +class SortDelay +{ +public: + + /// central access function called by each array access of the algorithms + virtual void OnAccess() = 0; +}; + +// ---------------------------------------------------------------------------- + +class SortArray +{ +protected: + // *** Displayed Array Data + + /// the array data + std::vector m_array; + + /// maximum value in array for scaling display + ArrayItem::value_type m_array_max; + + /// disable calculating of inversions + bool m_calc_inversions; + + /// the number of inversions in the array order + ssize_t m_inversions; + + /// access touch color + struct Access + { + unsigned int index; + unsigned short color; + unsigned short sustain; + unsigned short priority; + + Access(size_t i=0, unsigned short c=1, + unsigned short s=0, unsigned short p=0) + : index(i), color(c), sustain(s), priority(p) { } + }; + + /// position of very last get/set accesses (two for swaps) + Access m_access1, m_access2; + + /// array of get/set accesses since last paint event + std::vector m_access_list; + + /// custom markers in the array, set by algorithm + std::vector m_mark; + + /// custom watched index pointers in the array, set by algorithm + std::vector< std::pair > m_watch; + + /// flag for sorted array + bool m_is_sorted; + + /// pointer to delay function + SortDelay* m_delay; + +public: + /// mutex for accesses and watch items + wxMutex m_mutex; + + // *** Array Functions + +public: + /// constructor + SortArray(); + + /// Set pointer to delay functional + void SetSortDelay(SortDelay* delay) { m_delay = delay; } + + /// called by main when an algorithm starts + void OnAlgoLaunch(const struct AlgoEntry& ae); + + /// turn on/off calculation of inversions + void SetCalcInversions(bool on); + + /// toggle boolean to calculate inversions + void ToggleCalcInversions(); + + /// fill the array with one of the predefined data templates + void FillData(unsigned int schema, size_t arraysize); + + /// fill an array of strings with the list of predefined data templates + static void FillInputlist(wxArrayString& list); + + /// return whether the array was sorted + bool IsSorted() const { return m_is_sorted; } + + /// central access function called by each array access of the algorithms + void OnAccess(); + + /// check array after sorting algorithm + bool CheckSorted(); + + /// return the number of inversions in the array + ssize_t GetInversions() const + { return m_inversions; } + + /// calculate the number of runs in the array + size_t GetRuns() const; + +public: + /// reset the array to the given size + void ResetArray(size_t size); + + /// called when the data fill function is finished + void FinishFill(); + + /// save access to array, forwards to sound system + void SaveAccess(size_t i); + + /// check if index matches one of the watched pointers + short InAccessList(ssize_t idx); + + /// check if index matches one of the watched pointers + unsigned short InWatchList(ssize_t idx) const; + + /// Calculate the current color of the index i + int GetIndexColor(size_t idx); + + /// recalculate the number of inversions (in quadratic time) + void RecalcInversions(); + + // update inversion count by calculating delta linearly for a swap + void UpdateInversions(size_t i, size_t j); + +public: + /// return array size + size_t size() const { return m_array.size(); } + + /// return highest element value in array + const ArrayItem::value_type& array_max() const + { return m_array_max; } + + /// Return an item of the array (bypassing sound, counting and delay) + const ArrayItem& direct(size_t i) const + { + ASSERT(i < m_array.size()); + return m_array[i]; + } + + /// Return an item of the array (yields counting and delay) + const ArrayItem& operator[](size_t i) + { + ASSERT(i < m_array.size()); + + if (m_access1.index != i) + { + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_access1 = i; + m_access_list.push_back(i); + } + + // skip wait for duplicate accesses + OnAccess(); + } + + return m_array[i]; + } + + /// Return a mutable item of the array (yields counting and delay) + ArrayItem& get_mutable(size_t i) + { + ASSERT(i < m_array.size()); + + if (m_access1.index != i) + { + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_access1 = i; + m_access_list.push_back(i); + } + + // skip wait for duplicate accesses + OnAccess(); + } + + RecalcInversions(); + return m_array[i]; + } + + /// Return an item of the array (yields delay, but no counting) + const ArrayItem& get_nocount(size_t i) + { + ASSERT(i < m_array.size()); + + if (m_access1.index != i) + { + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_access1 = i; + m_access_list.push_back(i); + } + + // skip wait for duplicate accesses + --g_access_count; + OnAccess(); + } + + return m_array[i]; + } + + /// Set an item of the array: first set then yield sound, counting and delay. + void set(size_t i, const ArrayItem& v) + { + ASSERT(i < m_array.size()); + + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_access1 = i; + m_access_list.push_back(i); + + m_array[i] = v; + } + + RecalcInversions(); + OnAccess(); + } + + /// Special function to swap the value in the array, this method provides a + /// special visualization for this operation. + void swap(size_t i, size_t j) + { + ASSERT(i < m_array.size()); + ASSERT(j < m_array.size()); + + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_access1 = i; + m_access2 = j; + + m_access_list.push_back(i); + m_access_list.push_back(j); + } + + UpdateInversions(i, j); // update inversion count + + OnAccess(); + std::swap(m_array[i], m_array[j]); + OnAccess(); + m_access2 = -1; + } + + /// Touch an item of the array: set color till next frame is outputted. + void touch(size_t i, int color = 2, + unsigned short sustain = 0, unsigned short priority = 0) + { + ASSERT(i < m_array.size()); + + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_access1 = Access(i, color, sustain, priority); + m_access_list.push_back( Access(i, color, sustain, priority) ); + } + } + + /// Mark an array index with a color. + void mark(size_t i, int color = 2) + { + ASSERT(i < m_array.size()); + m_mark[i] = color; + } + + /// Swap color for two array indexes. + void mark_swap(size_t i, size_t j) + { + ASSERT(i < m_array.size()); + ASSERT(j < m_array.size()); + + std::swap(m_mark[i], m_mark[j]); + } + + /// Unmark an array index. + void unmark(size_t i) + { + ASSERT(i < m_array.size()); + m_mark[i] = 0; + } + + /// Unmark all array indexes. + void unmark_all() + { + m_access1 = m_access2 = -1; + std::fill(m_mark.begin(), m_mark.end(), 0); + + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + m_access_list.clear(); + } + + /// Highly experimental method to _track_ array live indexes. For this, the + /// index must be marked volatile!. + void watch(volatile ssize_t* idxptr, unsigned char color = 2) + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_watch.push_back( std::make_pair(idxptr,color) ); + } + + /// Release all tracked live array indexes. + void unwatch_all() + { + wxMutexLocker lock(m_mutex); + ASSERT(lock.IsOk()); + + m_watch.clear(); + } +}; + +// ---------------------------------------------------------------------------- + +#endif // SORT_ARRAY_HEADER From f30d2dc736e732f37f4bfc6c8fe5ff1da57620f5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 14:55:31 +0800 Subject: [PATCH 006/289] Delete SortAlgo.cpp --- SortAlgo.cpp | 1749 -------------------------------------------------- 1 file changed, 1749 deletions(-) delete mode 100644 SortAlgo.cpp diff --git a/SortAlgo.cpp b/SortAlgo.cpp deleted file mode 100644 index d467b56e3..000000000 --- a/SortAlgo.cpp +++ /dev/null @@ -1,1749 +0,0 @@ -/****************************************************************************** - * src/SortAlgo.cpp - * - * Implementations is many sorting algorithms. - * - * Note that these implementations may not be as good/fast as possible. Some - * are modified so that the visualization is more instructive. - * - * Futhermore, some algorithms are annotated using the mark() and watch() - * functions from SortArray. These functions add colors to the illustratation - * and thereby makes the algorithm's visualization easier to explain. - * - ****************************************************************************** - * The algorithms in this file are copyrighted by the original authors. All - * code is freely available. - * - * The source code added by myself (Timo Bingmann) and all modifications are - * copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#include "SortAlgo.h" - -#include -#include -#include -#include -#include - -typedef ArrayItem value_type; - -// inversion count limit for iterator instrumented algorithms -const unsigned int inversion_count_instrumented = 512; - -const struct AlgoEntry g_algolist[] = -{ - { _("Selection Sort"), &SelectionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Merge Sort"), &MergeSort, UINT_MAX, 512, - _("Merge sort which merges two sorted sequences into a shadow array," - "and then copies it back to the shown array.") }, - { _("Merge Sort (iterative)"), &MergeSortIterative, UINT_MAX, 512, - _("Merge sort variant which iteratively merges " - "subarrays of sizes of powers of two.") }, - { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, - _("Quick sort variant with left and right pointers.") }, - { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, - _("Quick sort variant from 3rd edition of CLRS: two pointers on left.") }, - { _("Quick Sort (ternary, LR ptrs)"), &QuickSortTernaryLR, UINT_MAX, UINT_MAX, - _("Ternary-split quick sort variant, adapted from multikey quicksort by " - "Bentley & Sedgewick: partitions \"==\" using two pairs of pointers " - "at left and right, then copied to middle.") }, - { _("Quick Sort (ternary, LL ptrs)"), &QuickSortTernaryLL, UINT_MAX, UINT_MAX, - _("Ternary-split quick sort variant: partitions \"<>?=\" using two " - "pointers at left and one at right. Afterwards copies the \"=\" to middle.") }, - { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, - _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " - "two at left and one at right.") }, - { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Comb Sort"), &CombSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Shell Sort"), &ShellSort, UINT_MAX, 1024, - wxEmptyString }, - { _("Heap Sort"), &HeapSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Smooth Sort"), &SmoothSort, UINT_MAX, 1024, - wxEmptyString }, - { _("Odd-Even Sort"), &OddEvenSort, UINT_MAX, 1024, - wxEmptyString }, - // older sequential implementation, which really makes little sense to do - //{ _("Bitonic Sort"), &BitonicSort, UINT_MAX, UINT_MAX, wxEmptyString }, - { _("Batcher's Bitonic Sort"), &BitonicSortNetwork, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Batcher's Odd-Even Merge Sort"), &BatcherSortNetwork, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Cycle Sort"), &CycleSort, 512, UINT_MAX, - wxEmptyString }, - { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, - _("Least significant digit radix sort, which copies item into a shadow " - "array during counting.") }, - { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, - _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, - { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("std::stable_sort (gcc)"), &StlStableSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("std::sort_heap (gcc)"), &StlHeapSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("Tim Sort"), &TimSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, - _("An O(1) place O(n log n) time stable merge sort.") }, - { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, - _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, - { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, - wxEmptyString }, - { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, - wxEmptyString }, - { _("Stooge Sort"), &StoogeSort, 256, inversion_count_instrumented, - wxEmptyString }, - { _("Slow Sort"), &SlowSort, 128, inversion_count_instrumented, - wxEmptyString } -}; - -const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); - -const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; - -// **************************************************************************** -// *** Selection Sort - -void SelectionSort(SortArray& A) -{ - volatile ssize_t jMin = 0; - A.watch(&jMin, 3); - - for (size_t i = 0; i < A.size()-1; ++i) - { - jMin = i; - - for (size_t j = i+1; j < A.size(); ++j) - { - if (A[j] < A[jMin]) { - A.mark_swap(j, jMin); - jMin = j; - } - } - - A.swap(i, jMin); - - // mark the last good element - if (i > 0) A.unmark(i-1); - A.mark(i); - } - A.unwatch_all(); -} - -void SandpaperSort(SortArray& A) -{ - size_t n = A.size(); - for (size_t i = 0; i < n; ++i) - { - for (size_t j = i + 1; j < n; ++j) - { - if (A[i] > A[j]) { - A.swap(i, j); - } - } - } -} - -// **************************************************************************** -// *** Insertion Sort - -// swaps every time (keeps all values visible) -void InsertionSort(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ++i) - { - value_type key = A[i]; - A.mark(i); - - ssize_t j = i - 1; - while (j >= 0 && A[j] > key) - { - A.swap(j, j+1); - j--; - } - - A.unmark(i); - } -} - -// with extra item on stack -void InsertionSort2(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ++i) - { - value_type tmp, key = A[i]; - A.mark(i); - - ssize_t j = i - 1; - while (j >= 0 && (tmp = A[j]) > key) - { - A.set(j + 1, tmp); - j--; - } - A.set(j + 1, key); - - A.unmark(i); - } -} - -// swaps every time (keeps all values visible) -void BinaryInsertionSort(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ++i) - { - value_type key = A[i]; - A.mark(i); - - int lo = 0, hi = i; - while (lo < hi) { - int mid = (lo + hi) / 2; - if (key <= A[mid]) - hi = mid; - else - lo = mid + 1; - } - - // item has to go into position lo - - ssize_t j = i - 1; - while (j >= lo) - { - A.swap(j, j+1); - j--; - } - - A.unmark(i); - } -} - -// **************************************************************************** -// *** Merge Sort (out-of-place with sentinels) - -// by myself (Timo Bingmann) - -void Merge(SortArray& A, size_t lo, size_t mid, size_t hi) -{ - // mark merge boundaries - A.mark(lo); - A.mark(mid,3); - A.mark(hi-1); - - // allocate output - std::vector out(hi-lo); - - // merge - size_t i = lo, j = mid, o = 0; // first and second halves - while (i < mid && j < hi) - { - // copy out for fewer time steps - value_type ai = A[i], aj = A[j]; - - out[o++] = (ai < aj ? (++i, ai) : (++j, aj)); - } - - // copy rest - while (i < mid) out[o++] = A[i++]; - while (j < hi) out[o++] = A[j++]; - - ASSERT(o == hi-lo); - - A.unmark(mid); - - // copy back - for (i = 0; i < hi-lo; ++i) - A.set(lo + i, out[i]); - - A.unmark(lo); - A.unmark(hi-1); -} - -void MergeSort(SortArray& A, size_t lo, size_t hi) -{ - if (lo + 1 < hi) - { - size_t mid = (lo + hi) / 2; - - MergeSort(A, lo, mid); - MergeSort(A, mid, hi); - - Merge(A, lo, mid, hi); - } -} - -void MergeSort(SortArray& A) -{ - return MergeSort(A, 0, A.size()); -} - -void MergeSortIterative(SortArray& A) -{ - for (size_t s = 1; s < A.size(); s *= 2) - { - for (size_t i = 0; i + s < A.size(); i += 2 * s) - { - Merge(A, i, i + s, - std::min(i + 2 * s, A.size())); - } - } -} - -// **************************************************************************** -// *** Quick Sort Pivot Selection - -QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST; - -// some quicksort variants use hi inclusive and some exclusive, we require it -// to be _exclusive_. hi == array.end()! -ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) -{ - if (g_quicksort_pivot == PIVOT_FIRST) - return lo; - - if (g_quicksort_pivot == PIVOT_LAST) - return hi-1; - - if (g_quicksort_pivot == PIVOT_MID) - return (lo + hi) / 2; - - if (g_quicksort_pivot == PIVOT_RANDOM) - return lo + (rand() % (hi - lo)); - - if (g_quicksort_pivot == PIVOT_MEDIAN3) - { - ssize_t mid = (lo + hi) / 2; - - // cases if two are equal - if (A[lo] == A[mid]) return lo; - if (A[lo] == A[hi-1] || A[mid] == A[hi-1]) return hi-1; - - // cases if three are different - return A[lo] < A[mid] - ? (A[mid] < A[hi-1] ? mid : (A[lo] < A[hi-1] ? hi-1 : lo)) - : (A[mid] > A[hi-1] ? mid : (A[lo] < A[hi-1] ? lo : hi-1)); - } - - return lo; -} - -wxArrayString QuickSortPivotText() -{ - wxArrayString sl; - - sl.Add( _("First Item") ); - sl.Add( _("Last Item") ); - sl.Add( _("Middle Item") ); - sl.Add( _("Random Item") ); - sl.Add( _("Median of Three") ); - - return sl; -} - -// **************************************************************************** -// *** Quick Sort LR (in-place, pointers at left and right, pivot is middle element) - -// by myself (Timo Bingmann), based on Hoare's original code - -void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) -{ - // pick pivot and watch - volatile ssize_t p = QuickSortSelectPivot(A, lo, hi+1); - - value_type pivot = A[p]; - A.watch(&p, 2); - - volatile ssize_t i = lo, j = hi; - A.watch(&i, 3); - A.watch(&j, 3); - - while (i <= j) - { - while (A[i] < pivot) - i++; - - while (A[j] > pivot) - j--; - - if (i <= j) - { - A.swap(i,j); - - // follow pivot if it is swapped - if (p == i) p = j; - else if (p == j) p = i; - - i++, j--; - } - } - - A.unwatch_all(); - - if (lo < j) - QuickSortLR(A, lo, j); - - if (i < hi) - QuickSortLR(A, i, hi); -} - -void QuickSortLR(SortArray& A) -{ - return QuickSortLR(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) - -// by myself (Timo Bingmann), based on CLRS' 3rd edition - -size_t PartitionLL(SortArray& A, size_t lo, size_t hi) -{ - // pick pivot and move to back - size_t p = QuickSortSelectPivot(A, lo, hi); - - value_type pivot = A[p]; - A.swap(p, hi-1); - A.mark(hi-1); - - volatile ssize_t i = lo; - A.watch(&i, 3); - - for (size_t j = lo; j < hi-1; ++j) - { - if (A[j] <= pivot) { - A.swap(i, j); - ++i; - } - } - - A.swap(i, hi-1); - A.unmark(hi-1); - A.unwatch_all(); - - return i; -} - -void QuickSortLL(SortArray& A, size_t lo, size_t hi) -{ - if (lo + 1 < hi) - { - size_t mid = PartitionLL(A, lo, hi); - - QuickSortLL(A, lo, mid); - QuickSortLL(A, mid+1, hi); - } -} - -void QuickSortLL(SortArray& A) -{ - return QuickSortLL(A, 0, A.size()); -} - -// **************************************************************************** -// *** Quick Sort Ternary (in-place, two pointers at left, pivot is first element and moved to right) - -// by myself (Timo Bingmann), loosely based on multikey quicksort by B&S - -void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) -{ - if (hi <= lo) return; - - int cmp; - - // pick pivot and swap to back - ssize_t piv = QuickSortSelectPivot(A, lo, hi+1); - A.swap(piv, hi); - A.mark(hi); - - const value_type& pivot = A[hi]; - - // schema: |p === |i <<< | ??? |j >>> |q === |piv - volatile ssize_t i = lo, j = hi-1; - volatile ssize_t p = lo, q = hi-1; - - A.watch(&i, 3); - A.watch(&j, 3); - - for (;;) - { - // partition on left - while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) - { - if (cmp == 0) { - A.mark(p,4); - A.swap(i, p++); - } - ++i; - } - - // partition on right - while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) - { - if (cmp == 0) { - A.mark(q,4); - A.swap(j, q--); - } - --j; - } - - if (i > j) break; - - // swap item between < > regions - A.swap(i++, j--); - } - - // swap pivot to right place - A.swap(i,hi); - A.mark_swap(i,hi); - - ssize_t num_less = i - p; - ssize_t num_greater = q - j; - - // swap equal ranges into center, but avoid swapping equal elements - j = i-1; i = i+1; - - ssize_t pe = lo + std::min(p-lo, num_less); - for (ssize_t k = lo; k < pe; k++, j--) { - A.swap(k,j); - A.mark_swap(k,j); - } - - ssize_t qe = hi-1 - std::min(hi-1-q, num_greater-1); // one already greater at end - for (ssize_t k = hi-1; k > qe; k--, i++) { - A.swap(i,k); - A.mark_swap(i,k); - } - - A.unwatch_all(); - A.unmark_all(); - - QuickSortTernaryLR(A, lo, lo + num_less - 1); - QuickSortTernaryLR(A, hi - num_greater + 1, hi); -} - -void QuickSortTernaryLR(SortArray& A) -{ - return QuickSortTernaryLR(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) - -// by myself (Timo Bingmann) - -std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) -{ - // pick pivot and swap to back - ssize_t p = QuickSortSelectPivot(A, lo, hi); - - value_type pivot = A[p]; - A.swap(p, hi-1); - A.mark(hi-1); - - volatile ssize_t i = lo, k = hi-1; - A.watch(&i, 3); - - for (ssize_t j = lo; j < k; ++j) - { - int cmp = A[j].cmp(pivot); // ternary comparison - if (cmp == 0) { - A.swap(--k, j); - --j; // reclassify A[j] - A.mark(k,4); - } - else if (cmp < 0) { - A.swap(i++, j); - } - } - - // unwatch i, because the pivot is swapped there - // in the first step of the following swap loop. - A.unwatch_all(); - - ssize_t j = i + (hi-k); - - for (ssize_t s = 0; s < hi-k; ++s) { - A.swap(i+s, hi-1-s); - A.mark_swap(i+s, hi-1-s); - } - A.unmark_all(); - - return std::make_pair(i,j); -} - -void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) -{ - if (lo + 1 < hi) - { - std::pair mid = PartitionTernaryLL(A, lo, hi); - - QuickSortTernaryLL(A, lo, mid.first); - QuickSortTernaryLL(A, mid.second, hi); - } -} - -void QuickSortTernaryLL(SortArray& A) -{ - return QuickSortTernaryLL(A, 0, A.size()); -} - -// **************************************************************************** -// *** Dual-Pivot Quick Sort - -// by Sebastian Wild - -void dualPivotYaroslavskiy(class SortArray& a, int left, int right) -{ - if (right > left) - { - if (a[left] > a[right]) { - a.swap(left, right); - } - - const value_type p = a[left]; - const value_type q = a[right]; - - a.mark(left); - a.mark(right); - - volatile ssize_t l = left + 1; - volatile ssize_t g = right - 1; - volatile ssize_t k = l; - - a.watch(&l, 3); - a.watch(&g, 3); - a.watch(&k, 3); - - while (k <= g) - { - if (a[k] < p) { - a.swap(k, l); - ++l; - } - else if (a[k] >= q) { - while (a[g] > q && k < g) --g; - a.swap(k, g); - --g; - - if (a[k] < p) { - a.swap(k, l); - ++l; - } - } - ++k; - } - --l; - ++g; - a.swap(left, l); - a.swap(right, g); - - a.unmark_all(); - a.unwatch_all(); - - dualPivotYaroslavskiy(a, left, l - 1); - dualPivotYaroslavskiy(a, l + 1, g - 1); - dualPivotYaroslavskiy(a, g + 1, right); - } -} - -void QuickSortDualPivot(class SortArray& a) -{ - return dualPivotYaroslavskiy(a, 0, a.size()-1); -} - -// **************************************************************************** -// *** Bubble Sort - -void BubbleSort(SortArray& A) -{ - for (size_t i = 0; i < A.size()-1; ++i) - { - for (size_t j = 0; j < A.size()-1 - i; ++j) - { - if (A[j] > A[j + 1]) - { - A.swap(j, j+1); - } - } - } -} - -// **************************************************************************** -// *** Cocktail Shaker Sort - -// from http://de.wikibooks.org/wiki/Algorithmen_und_Datenstrukturen_in_C/_Shakersort - -void CocktailShakerSort(SortArray& A) -{ - size_t lo = 0, hi = A.size()-1, mov = lo; - - while (lo < hi) - { - for (size_t i = hi; i > lo; --i) - { - if (A[i-1] > A[i]) - { - A.swap(i-1, i); - mov = i; - } - } - - lo = mov; - - for (size_t i = lo; i < hi; ++i) - { - if (A[i] > A[i+1]) - { - A.swap(i, i+1); - mov = i; - } - } - - hi = mov; - } -} - -// **************************************************************************** -// *** Gnome Sort - -// from http://en.wikipediA.org/wiki/Gnome_sort - -void GnomeSort(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ) - { - if (A[i] >= A[i-1]) - { - ++i; - } - else - { - A.swap(i, i-1); - if (i > 1) --i; - } - } -} - -// **************************************************************************** -// *** Comb Sort - -// from http://en.wikipediA.org/wiki/Comb_sort - -void CombSort(SortArray& A) -{ - const double shrink = 1.3; - - bool swapped = false; - size_t gap = A.size(); - - while ((gap > 1) || swapped) - { - if (gap > 1) { - gap = (size_t)((float)gap / shrink); - } - - swapped = false; - - for (size_t i = 0; gap + i < A.size(); ++i) - { - if (A[i] > A[i + gap]) - { - A.swap(i, i+gap); - swapped = true; - } - } - } -} - -// **************************************************************************** -// *** Odd-Even Sort - -// from http://en.wikipediA.org/wiki/Odd%E2%80%93even_sort - -void OddEvenSort(SortArray& A) -{ - bool sorted = false; - - while (!sorted) - { - sorted = true; - - for (size_t i = 1; i < A.size()-1; i += 2) - { - if(A[i] > A[i+1]) - { - A.swap(i, i+1); - sorted = false; - } - } - - for (size_t i = 0; i < A.size()-1; i += 2) - { - if(A[i] > A[i+1]) - { - A.swap(i, i+1); - sorted = false; - } - } - } -} - -// **************************************************************************** -// *** Shell Sort - -// with gaps by Robert Sedgewick from http://www.cs.princeton.edu/~rs/shell/shell.c - -void ShellSort(SortArray& A) -{ - size_t incs[16] = { 1391376, 463792, 198768, 86961, 33936, - 13776, 4592, 1968, 861, 336, - 112, 48, 21, 7, 3, 1 }; - - for (size_t k = 0; k < 16; k++) - { - for (size_t h = incs[k], i = h; i < A.size(); i++) - { - value_type v = A[i]; - size_t j = i; - - while (j >= h && A[j-h] > v) - { - A.set(j, A[j-h]); - j -= h; - } - - A.set(j, v); - } - } -} - -// **************************************************************************** -// *** Heap Sort - -// heavily adapted from http://www.codecodex.com/wiki/Heapsort - -bool isPowerOfTwo(size_t x) -{ - return ((x != 0) && !(x & (x - 1))); -} - -uint32_t prevPowerOfTwo(uint32_t x) -{ - x |= x >> 1; x |= x >> 2; x |= x >> 4; - x |= x >> 8; x |= x >> 16; - return x - (x >> 1); -} - -int largestPowerOfTwoLessThan(int n) -{ - int k = 1; - while (k < n) k = k << 1; - return k >> 1; -} - -void HeapSort(SortArray& A) -{ - size_t n = A.size(), i = n / 2; - - // mark heap levels with different colors - for (size_t j = i; j < n; ++j) - A.mark(j, log(prevPowerOfTwo(j+1)) / log(2) + 4); - - while (1) - { - if (i > 0) { - // build heap, sift A[i] down the heap - i--; - } - else { - // pop largest element from heap: swap front to back, and sift - // front A[0] down the heap - n--; - if (n == 0) return; - A.swap(0,n); - - A.mark(n); - if (n+1 < A.size()) A.unmark(n+1); - } - - size_t parent = i; - size_t child = i*2 + 1; - - // sift operation - push the value of A[i] down the heap - while (child < n) - { - if (child + 1 < n && A[child + 1] > A[child]) { - child++; - } - if (A[child] > A[parent]) { - A.swap(parent, child); - parent = child; - child = parent*2+1; - } - else { - break; - } - } - - // mark heap levels with different colors - A.mark(i, log(prevPowerOfTwo(i+1)) / log(2) + 4); - } - -} - -// **************************************************************************** -// *** Radix Sort (counting sort, most significant digit (MSD) first, in-place redistribute) - -// by myself (Timo Bingmann) - -void RadixSortMSD(SortArray& A, size_t lo, size_t hi, size_t depth) -{ - A.mark(lo); A.mark(hi-1); - - // radix and base calculations - const unsigned int RADIX = 4; - - unsigned int pmax = floor( log(A.array_max()+1) / log(RADIX) ); - ASSERT(depth <= pmax); - - size_t base = pow(RADIX, pmax - depth); - - // count digits - std::vector count(RADIX, 0); - - for (size_t i = lo; i < hi; ++i) - { - size_t r = A[i].get() / base % RADIX; - ASSERT(r < RADIX); - count[r]++; - } - - // inclusive prefix sum - std::vector bkt(RADIX, 0); - std::partial_sum(count.begin(), count.end(), bkt.begin()); - - // mark bucket boundaries - for (size_t i = 0; i < bkt.size(); ++i) { - if (bkt[i] == 0) continue; - A.mark(lo + bkt[i]-1, 3); - } - - // reorder items in-place by walking cycles - for (size_t i=0, j; i < (hi-lo); ) - { - while ( (j = --bkt[ (A[lo+i].get() / base % RADIX) ]) > i ) - { - A.swap(lo + i, lo + j); - } - i += count[ (A[lo+i].get() / base % RADIX) ]; - } - - A.unmark_all(); - - // no more depth to sort? - if (depth+1 > pmax) return; - - // recurse on buckets - size_t sum = lo; - for (size_t i = 0; i < RADIX; ++i) - { - if (count[i] > 1) - RadixSortMSD(A, sum, sum+count[i], depth+1); - sum += count[i]; - } -} - -void RadixSortMSD(SortArray& A) -{ - return RadixSortMSD(A, 0, A.size(), 0); -} - -// **************************************************************************** -// *** Radix Sort (counting sort, least significant digit (LSD) first, out-of-place redistribute) - -// by myself (Timo Bingmann) - -void RadixSortLSD(SortArray& A) -{ - // radix and base calculations - const unsigned int RADIX = 4; - - unsigned int pmax = ceil( log(A.array_max()+1) / log(RADIX) ); - - for (unsigned int p = 0; p < pmax; ++p) - { - size_t base = pow(RADIX, p); - - // count digits and copy data - std::vector count(RADIX, 0); - std::vector copy(A.size()); - - for (size_t i = 0; i < A.size(); ++i) - { - size_t r = (copy[i] = A[i]).get() / base % RADIX; - ASSERT(r < RADIX); - count[r]++; - } - - // exclusive prefix sum - std::vector bkt(RADIX+1, 0); - std::partial_sum(count.begin(), count.end(), bkt.begin()+1); - - // mark bucket boundaries - for (size_t i = 0; i < bkt.size()-1; ++i) { - if (bkt[i] >= A.size()) continue; - A.mark(bkt[i], 3); - } - - // redistribute items back into array (stable) - for (size_t i=0; i < A.size(); ++i) - { - size_t r = copy[i].get() / base % RADIX; - A.set( bkt[r]++, copy[i] ); - } - - A.unmark_all(); - } -} - -// **************************************************************************** -// *** Use STL Sorts via Iterator Adapters - -void StlSort(SortArray& A) -{ - std::sort(MyIterator(&A,0), MyIterator(&A,A.size())); -} - -void StlStableSort(SortArray& A) -{ - std::stable_sort(MyIterator(&A,0), MyIterator(&A,A.size())); -} - -void StlHeapSort(SortArray& A) -{ - std::make_heap(MyIterator(&A,0), MyIterator(&A,A.size())); - std::sort_heap(MyIterator(&A,0), MyIterator(&A,A.size())); -} - -// **************************************************************************** -// *** BogoSort and more slow sorts - -// by myself (Timo Bingmann) - -bool BogoCheckSorted(SortArray& A) -{ - size_t i; - A.mark(0); - for (i = 1; i < A.size(); ++i) - { - value_type val = A[i]; - if (A[i - 1] > A[i]) break; - A.mark(i); - } - - if (i == A.size()) { - // this is amazing. - return true; - } - - // unmark - while (i > 0) A.unmark(i--); - A.unmark(0); - - return false; -} - -void BogoSort(SortArray& A) -{ - // keep a permutation of [0,size) - std::vector perm(A.size()); - - for (size_t i = 0; i < A.size(); ++i) - perm[i] = i; - - while (1) - { - // check if array is sorted - if (BogoCheckSorted(A)) break; - - // pick a random permutation of indexes - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(perm.begin(), perm.end(), g); - - // permute array in-place - std::vector pmark(A.size(), 0); - - for (size_t i = 0; i < A.size(); ++i) - { - if (pmark[i]) continue; - - // walk a cycle - size_t j = i; - - //std::cout << "cycle start " << j << " -> " << perm[j] << "\n"; - - while ( perm[j] != i ) - { - ASSERT(!pmark[j]); - A.swap(j, perm[j]); - pmark[j] = 1; - - j = perm[j]; - //std::cout << "cycle step " << j << " -> " << perm[j] << "\n"; - } - //std::cout << "cycle end\n"; - - ASSERT(!pmark[j]); - pmark[j] = 1; - } - - //std::cout << "permute end\n"; - - for (size_t i = 0; i < A.size(); ++i) - ASSERT(pmark[i]); - } -} - -void BozoSort(SortArray& A) -{ - srand(time(NULL)); - - while (1) - { - // check if array is sorted - if (BogoCheckSorted(A)) break; - - // swap two random items - A.swap(rand() % A.size(), rand() % A.size()); - } -} - -void flip(SortArray& A, size_t high) -{ - size_t low = 0; - while (low < high) - { - A.mark_swap(low, high); - A.swap(low, high); - ++low; --high; - } -} - -size_t find_max(SortArray& A, size_t n) // Optimized find_max method, the original method performs the search in linear time -{ - size_t max = 0; - size_t low = 1; - size_t hi = n; - while (low <= hi) - { - if (A[low] > A[max]) - { - max = low; - } - if (A[hi] > A[max]) - { - max = hi; - } - ++low; --hi; - } - return max; -} - -void PancakeSort(SortArray& A) -{ - size_t n = A.size() - 1; - for (size_t cur_size = n; cur_size >= 1; --cur_size) - { - size_t max_idx = find_max(A, cur_size); - if (max_idx != cur_size) - { - if (max_idx > 0) { flip(A, max_idx); } - flip(A, cur_size); - } - } -} - -// **************************************************************************** -// *** Bitonic Sort - -// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm - -namespace BitonicSortNS { - -static const bool ASCENDING = true; // sorting direction - -static void compare(SortArray& A, int i, int j, bool dir) -{ - if (dir == (A[i] > A[j])) - A.swap(i, j); -} - -static void bitonicMerge(SortArray& A, int lo, int n, bool dir) -{ - if (n > 1) - { - int m = largestPowerOfTwoLessThan(n); - - for (int i = lo; i < lo + n - m; i++) - compare(A, i, i+m, dir); - - bitonicMerge(A, lo, m, dir); - bitonicMerge(A, lo + m, n - m, dir); - } -} - -static void bitonicSort(SortArray& A, int lo, int n, bool dir) -{ - if (n > 1) - { - int m = n / 2; - bitonicSort(A, lo, m, !dir); - bitonicSort(A, lo + m, n - m, dir); - bitonicMerge(A, lo, n, dir); - } -} - -} // namespace BitonicSortNS - -void BitonicSort(SortArray& A) -{ - BitonicSortNS::bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING); -} - -// **************************************************************************** -// *** Bitonic Sort as "Parallel" Sorting Network - -// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm - -// modified to first record the recursively generated swap sequence, and then -// sort it back into the order a parallel sorting network would perform the -// swaps in - -namespace BitonicSortNetworkNS { - -struct swappair_type -{ - // swapped positions - unsigned int i,j; - - // depth of recursions: sort / merge - unsigned int sort_depth, merge_depth; - - swappair_type(unsigned int _i, unsigned int _j, - unsigned int _sort_depth, unsigned int _merge_depth) - : i(_i), j(_j), - sort_depth(_sort_depth), merge_depth(_merge_depth) - { } - - // order relation for sorting swaps - bool operator < (const swappair_type& b) const - { - if (sort_depth != b.sort_depth) - return sort_depth > b.sort_depth; - - if (merge_depth != b.merge_depth) - return merge_depth < b.merge_depth; - - return i < b.i; - } -}; - -typedef std::vector sequence_type; -std::vector sequence; - -void replay(SortArray& A) -{ - for (sequence_type::const_iterator si = sequence.begin(); - si != sequence.end(); ++si) - { - if (A[si->i] > A[si->j]) - A.swap(si->i, si->j); - } -} - -static const bool ASCENDING = true; // sorting direction - -static void compare(SortArray& /* A */, unsigned int i, unsigned int j, bool dir, - unsigned int sort_depth, unsigned int merge_depth) -{ - // if (dir == (A[i] > A[j])) A.swap(i, j); - - if (dir) - sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); - else - sequence.push_back( swappair_type(j,i, sort_depth, merge_depth) ); -} - -static void bitonicMerge(SortArray& A, unsigned int lo, unsigned int n, bool dir, - unsigned int sort_depth, unsigned int merge_depth) -{ - if (n > 1) - { - unsigned int m = largestPowerOfTwoLessThan(n); - - for (unsigned int i = lo; i < lo + n - m; i++) - compare(A, i, i + m, dir, sort_depth, merge_depth); - - bitonicMerge(A, lo, m, dir, sort_depth, merge_depth+1); - bitonicMerge(A, lo + m, n - m, dir, sort_depth, merge_depth+1); - } -} - -static void bitonicSort(SortArray& A, unsigned int lo, unsigned int n, bool dir, - unsigned int sort_depth) -{ - if (n > 1) - { - unsigned int m = n / 2; - bitonicSort(A, lo, m, !dir, sort_depth+1); - bitonicSort(A, lo + m, n - m, dir, sort_depth+1); - bitonicMerge(A, lo, n, dir, sort_depth, 0); - } -} - -void sort(SortArray& A) -{ - sequence.clear(); - bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING, 0); - std::sort(sequence.begin(), sequence.end()); - replay(A); - sequence.clear(); -} - -} // namespace BitonicSortNS - -void BitonicSortNetwork(SortArray& A) -{ - BitonicSortNetworkNS::sort(A); -} - -// **************************************************************************** -// *** Batcher's Odd-Even Merge Sort as "Parallel" Sorting Network - -// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/oemen.htm - -// modified to first record the recursively generated swap sequence, and then -// sort it back into the order a parallel sorting network would perform the -// swaps in - -namespace BatcherSortNetworkNS { - -struct swappair_type -{ - // swapped positions - unsigned int i,j; - - // depth of recursions: sort / merge - unsigned int sort_depth, merge_depth; - - swappair_type(unsigned int _i, unsigned int _j, - unsigned int _sort_depth, unsigned int _merge_depth) - : i(_i), j(_j), - sort_depth(_sort_depth), merge_depth(_merge_depth) - { } - - // order relation for sorting swaps - bool operator < (const swappair_type& b) const - { - if (sort_depth != b.sort_depth) - return sort_depth > b.sort_depth; - - if (merge_depth != b.merge_depth) - return merge_depth > b.merge_depth; - - return i < b.i; - } -}; - -typedef std::vector sequence_type; -std::vector sequence; - -void replay(SortArray& A) -{ - for (sequence_type::const_iterator si = sequence.begin(); - si != sequence.end(); ++si) - { - if (A[si->i] > A[si->j]) - A.swap(si->i, si->j); - } -} - -static void compare(SortArray& A, unsigned int i, unsigned int j, - unsigned int sort_depth, unsigned int merge_depth) -{ - // skip all swaps beyond end of array - ASSERT(i < j); - if (j >= A.size()) return; - - sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); - - //if (A[i] > A[j]) A.swap(i, j); -} - -// lo is the starting position and n is the length of the piece to be merged, r -// is the distance of the elements to be compared -static void oddEvenMerge(SortArray& A, unsigned int lo, unsigned int n, unsigned int r, - unsigned int sort_depth, unsigned int merge_depth) -{ - unsigned int m = r * 2; - if (m < n) - { - // even subsequence - oddEvenMerge(A, lo, n, m, sort_depth, merge_depth+1); - // odd subsequence - oddEvenMerge(A, lo + r, n, m, sort_depth, merge_depth+1); - - for (unsigned int i = lo + r; i + r < lo + n; i += m) - compare(A, i, i + r, sort_depth, merge_depth); - } - else { - compare(A, lo, lo + r, sort_depth, merge_depth); - } -} - -// sorts a piece of length n of the array starting at position lo -static void oddEvenMergeSort(SortArray& A, unsigned int lo, unsigned int n, - unsigned int sort_depth) -{ - if (n > 1) - { - unsigned int m = n / 2; - oddEvenMergeSort(A, lo, m, sort_depth+1); - oddEvenMergeSort(A, lo + m, m, sort_depth+1); - oddEvenMerge(A, lo, n, 1, sort_depth, 0); - } -} - -void sort(SortArray& A) -{ - sequence.clear(); - - unsigned int n = largestPowerOfTwoLessThan(A.size()); - if (n != A.size()) n *= 2; - - oddEvenMergeSort(A, 0, n, 0); - std::sort(sequence.begin(), sequence.end()); - replay(A); - sequence.clear(); -} - -} // namespace BatcherSortNetworkNS - -void BatcherSortNetwork(SortArray& A) -{ - BatcherSortNetworkNS::sort(A); -} - -// **************************************************************************** -// *** Smooth Sort - -// from http://en.wikipediA.org/wiki/Smoothsort - -namespace SmoothSortNS { - -static const int LP[] = { - 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, - 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, - 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, - 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, - 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, - 866988873 // the next number is > 31 bits. -}; - -static void sift(SortArray& A, int pshift, int head) -{ - // we do not use Floyd's improvements to the heapsort sift, because we - // are not doing what heapsort does - always moving nodes from near - // the bottom of the tree to the root. - - value_type val = A[head]; - - while (pshift > 1) - { - int rt = head - 1; - int lf = head - 1 - LP[pshift - 2]; - - if (val.cmp(A[lf]) >= 0 && val.cmp(A[rt]) >= 0) - break; - - if (A[lf].cmp(A[rt]) >= 0) { - A.set(head, A[lf]); - head = lf; - pshift -= 1; - } - else { - A.set(head, A[rt]); - head = rt; - pshift -= 2; - } - } - - A.set(head, val); -} - -static void trinkle(SortArray& A, int p, int pshift, int head, bool isTrusty) -{ - value_type val = A[head]; - - while (p != 1) - { - int stepson = head - LP[pshift]; - - if (A[stepson].cmp(val) <= 0) - break; // current node is greater than head. sift. - - // no need to check this if we know the current node is trusty, - // because we just checked the head (which is val, in the first - // iteration) - if (!isTrusty && pshift > 1) { - int rt = head - 1; - int lf = head - 1 - LP[pshift - 2]; - if (A[rt].cmp(A[stepson]) >= 0 || - A[lf].cmp(A[stepson]) >= 0) - break; - } - - A.set(head, A[stepson]); - - head = stepson; - //int trail = Integer.numberOfTrailingZeros(p & ~1); - int trail = __builtin_ctz(p & ~1); - p >>= trail; - pshift += trail; - isTrusty = false; - } - - if (!isTrusty) { - A.set(head, val); - sift(A, pshift, head); - } -} - -void sort(SortArray& A, int lo, int hi) -{ - int head = lo; // the offset of the first element of the prefix into m - - // These variables need a little explaining. If our string of heaps - // is of length 38, then the heaps will be of size 25+9+3+1, which are - // Leonardo numbers 6, 4, 2, 1. - // Turning this into a binary number, we get b01010110 = 0x56. We represent - // this number as a pair of numbers by right-shifting all the zeros and - // storing the mantissa and exponent as "p" and "pshift". - // This is handy, because the exponent is the index into L[] giving the - // size of the rightmost heap, and because we can instantly find out if - // the rightmost two heaps are consecutive Leonardo numbers by checking - // (p&3)==3 - - int p = 1; // the bitmap of the current standard concatenation >> pshift - int pshift = 1; - - while (head < hi) - { - if ((p & 3) == 3) { - // Add 1 by merging the first two blocks into a larger one. - // The next Leonardo number is one bigger. - sift(A, pshift, head); - p >>= 2; - pshift += 2; - } - else { - // adding a new block of length 1 - if (LP[pshift - 1] >= hi - head) { - // this block is its final size. - trinkle(A, p, pshift, head, false); - } else { - // this block will get merged. Just make it trusty. - sift(A, pshift, head); - } - - if (pshift == 1) { - // LP[1] is being used, so we add use LP[0] - p <<= 1; - pshift--; - } else { - // shift out to position 1, add LP[1] - p <<= (pshift - 1); - pshift = 1; - } - } - p |= 1; - head++; - } - - trinkle(A, p, pshift, head, false); - - while (pshift != 1 || p != 1) - { - if (pshift <= 1) { - // block of length 1. No fiddling needed - //int trail = Integer.numberOfTrailingZeros(p & ~1); - int trail = __builtin_ctz(p & ~1); - p >>= trail; - pshift += trail; - } - else { - p <<= 2; - p ^= 7; - pshift -= 2; - - // This block gets broken into three bits. The rightmost bit is a - // block of length 1. The left hand part is split into two, a block - // of length LP[pshift+1] and one of LP[pshift]. Both these two - // are appropriately heapified, but the root nodes are not - // necessarily in order. We therefore semitrinkle both of them - - trinkle(A, p >> 1, pshift + 1, head - LP[pshift] - 1, true); - trinkle(A, p, pshift, head - 1, true); - } - - head--; - } -} - -} // namespace SmoothSortNS - -void SmoothSort(SortArray& A) -{ - return SmoothSortNS::sort(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Stooge Sort - -void StoogeSort(SortArray& A, int i, int j) -{ - if (A[i] > A[j]) - { - A.swap(i, j); - } - - if (j - i + 1 >= 3) - { - int t = (j - i + 1) / 3; - - A.mark(i, 3); - A.mark(j, 3); - - StoogeSort(A, i, j-t); - StoogeSort(A, i+t, j); - StoogeSort(A, i, j-t); - - A.unmark(i); - A.unmark(j); - } -} - -void StoogeSort(SortArray& A) -{ - StoogeSort(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Slow Sort - -void SlowSort(SortArray& A, int i, int j) -{ - if (i >= j) return; - - int m = (i + j) / 2; - - SlowSort(A, i, m); - SlowSort(A, m+1, j); - - if (A[m] > A[j]) - A.swap(m, j); - - A.mark(j, 2); - - SlowSort(A, i, j-1); - - A.unmark(j); -} - -void SlowSort(SortArray& A) -{ - SlowSort(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Cycle Sort - -// Adapted from http://en.wikipedia.org/wiki/Cycle_sort - -void CycleSort(SortArray& array, ssize_t n) -{ - volatile ssize_t cycleStart = 0; - array.watch(&cycleStart, 16); - - volatile ssize_t rank = 0; - array.watch(&rank, 3); - - // Loop through the array to find cycles to rotate. - for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) - { - value_type& item = array.get_mutable(cycleStart); - - do { - // Find where to put the item. - rank = cycleStart; - for (ssize_t i = cycleStart + 1; i < n; ++i) - { - if (array[i] < item) - rank++; - } - - // If the item is already there, this is a 1-cycle. - if (rank == cycleStart) { - array.mark(rank, 2); - break; - } - - // Otherwise, put the item after any duplicates. - while (item == array[rank]) - rank++; - - // Put item into right place and colorize - std::swap(array.get_mutable(rank), item); - array.mark(rank, 2); - - // Continue for rest of the cycle. - } - while (rank != cycleStart); - } - - array.unwatch_all(); -} - -void CycleSort(SortArray& A) -{ - CycleSort(A, A.size()); -} - -// **************************************************************************** From 0f33cad674bcbf17e2331486ccc88b1e94b0c22b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 14:55:45 +0800 Subject: [PATCH 007/289] Delete SortAlgo.h --- SortAlgo.h | 195 ----------------------------------------------------- 1 file changed, 195 deletions(-) delete mode 100644 SortAlgo.h diff --git a/SortAlgo.h b/SortAlgo.h deleted file mode 100644 index 0227a1af6..000000000 --- a/SortAlgo.h +++ /dev/null @@ -1,195 +0,0 @@ -/****************************************************************************** - * src/SortAlgo.h - * - * Implementations of many sorting algorithms. - * - * Note that these implementations may not be as good/fast as possible. Some - * are modified so that the visualization is more instructive. - * - * Futhermore, some algorithms are annotated using the mark() and watch() - * functions from SortArray. These functions add colors to the illustratation - * and thereby makes the algorithm's visualization easier to explain. - * - ****************************************************************************** - * Copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#ifndef SORTALGO_H -#define SORTALGO_H - -#include -#include "SortArray.h" - -// *** List of Sorting Algorithms - -struct AlgoEntry -{ - wxString name; - void (*func)(class SortArray&); - // maximum item count for test runs - unsigned int max_testsize; - // count inversions if n <= limit - unsigned int inversion_count_limit; - wxString text; -}; - -extern const struct AlgoEntry g_algolist[]; -extern const size_t g_algolist_size; -extern const struct AlgoEntry* g_algolist_end; - -// *** Sorting Algorithms - -void SelectionSort(class SortArray& a); -void SandpaperSort(class SortArray& a); -void InsertionSort(class SortArray& a); -void BinaryInsertionSort(class SortArray& a); - -void MergeSort(class SortArray& a); -void MergeSortIterative(class SortArray& a); - -wxArrayString QuickSortPivotText(); - -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3 }; -extern QuickSortPivotType g_quicksort_pivot; - -void QuickSortLR(class SortArray& a); -void QuickSortLL(class SortArray& a); -void QuickSortTernaryLR(class SortArray& a); -void QuickSortTernaryLL(class SortArray& a); -void QuickSortDualPivot(class SortArray& a); - -void BubbleSort(class SortArray& a); -void CocktailShakerSort(class SortArray& a); -void CombSort(class SortArray& a); -void GnomeSort(class SortArray& a); -void OddEvenSort(class SortArray& a); - -void ShellSort(SortArray& a); -void HeapSort(class SortArray& a); -void SmoothSort(class SortArray& a); - -void BitonicSort(SortArray& a); -void BitonicSortNetwork(SortArray& a); -void BatcherSortNetwork(SortArray& a); - -void RadixSortLSD(class SortArray& a); -void RadixSortMSD(class SortArray& a); - -void StlSort(class SortArray& a); -void StlStableSort(class SortArray& a); -void StlHeapSort(class SortArray& a); - -void TimSort(class SortArray& a); -void WikiSort(class SortArray& a); - -void BogoSort(class SortArray& a); -void BozoSort(class SortArray& a); -void StoogeSort(class SortArray& a); -void SlowSort(class SortArray& a); -void PancakeSort(class SortArray& a); - -void CycleSort(class SortArray& a); - -// **************************************************************************** -// *** Iterator Adapter - -// iterator based on http://zotu.blogspot.de/2010/01/creating-random-access-iterator.html - -class MyIterator : public std::iterator -{ -protected: - SortArray* m_array; - size_t m_pos; - -public: - typedef std::iterator base_type; - - typedef std::random_access_iterator_tag iterator_category; - - typedef base_type::value_type value_type; - typedef base_type::difference_type difference_type; - typedef base_type::reference reference; - typedef base_type::pointer pointer; - - MyIterator() : m_array(NULL), m_pos(0) {} - - MyIterator(SortArray* A, size_t p) : m_array(A), m_pos(p) {} - - MyIterator(const MyIterator& r) : m_array(r.m_array), m_pos(r.m_pos) {} - - MyIterator& operator=(const MyIterator& r) - { m_array = r.m_array, m_pos = r.m_pos; return *this; } - - MyIterator& operator++() - { ++m_pos; return *this; } - - MyIterator& operator--() - { --m_pos; return *this; } - - MyIterator operator++(int) - { return MyIterator(m_array, m_pos++); } - - MyIterator operator--(int) - { return MyIterator(m_array, m_pos--); } - - MyIterator operator+(const difference_type& n) const - { return MyIterator(m_array, m_pos + n); } - - MyIterator& operator+=(const difference_type& n) - { m_pos += n; return *this; } - - MyIterator operator-(const difference_type& n) const - { return MyIterator(m_array, m_pos - n); } - - MyIterator& operator-=(const difference_type& n) - { m_pos -= n; return *this; } - - reference operator*() const - { return m_array->get_mutable(m_pos); } - - pointer operator->() const - { return &(m_array->get_mutable(m_pos)); } - - reference operator[](const difference_type& n) const - { return m_array->get_mutable(m_pos + n); } - - bool operator==(const MyIterator& r) - { return (m_array == r.m_array) && (m_pos == r.m_pos); } - - bool operator!=(const MyIterator& r) - { return (m_array != r.m_array) || (m_pos != r.m_pos); } - - bool operator<(const MyIterator& r) - { return (m_array == r.m_array ? (m_pos < r.m_pos) : (m_array < r.m_array)); } - - bool operator>(const MyIterator& r) - { return (m_array == r.m_array ? (m_pos > r.m_pos) : (m_array > r.m_array)); } - - bool operator<=(const MyIterator& r) - { return (m_array == r.m_array ? (m_pos <= r.m_pos) : (m_array <= r.m_array)); } - - bool operator>=(const MyIterator& r) - { return (m_array == r.m_array ? (m_pos >= r.m_pos) : (m_array >= r.m_array)); } - - difference_type operator+(const MyIterator& r2) const - { ASSERT(m_array == r2.m_array); return (m_pos + r2.m_pos); } - - difference_type operator-(const MyIterator& r2) const - { ASSERT(m_array == r2.m_array); return (m_pos - r2.m_pos); } -}; - - -#endif // SORTALGO_H From 6f61cec5e9511fcfdf0ceb7dc8a8db7f99d77874 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 14:55:53 +0800 Subject: [PATCH 008/289] Delete SortArray.cpp --- SortArray.cpp | 490 -------------------------------------------------- 1 file changed, 490 deletions(-) delete mode 100644 SortArray.cpp diff --git a/SortArray.cpp b/SortArray.cpp deleted file mode 100644 index ac9489820..000000000 --- a/SortArray.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/******************************************************************************* - * src/SortArray.cpp - * - * SortArray represents a simple array, which is displayed by WSortView to the - * user is real-time. - * - ******************************************************************************* - * Copyright (C) 2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - ******************************************************************************/ - -#include "SortArray.h" -#include "SortAlgo.h" - -#include -#include - -extern void SoundAccess(size_t i); - -// ***************************************************************************** -// *** Comparisons of ArrayItems - -size_t g_compare_count = 0; - -size_t g_access_count = 0; - -void ArrayItem::OnAccess(const ArrayItem& a) -{ - SoundAccess(a.get_direct()); -} - -void ArrayItem::OnComparison(const ArrayItem& a, const ArrayItem& b) -{ - ++g_compare_count; - - SoundAccess(a.get_direct()); - SoundAccess(b.get_direct()); -} - -// ***************************************************************************** -// *** SortArray - -SortArray::SortArray() - : m_calc_inversions(false), - m_delay(NULL) -{ -} - -void SortArray::OnAlgoLaunch(const AlgoEntry& ae) -{ - if (size() <= ae.inversion_count_limit) - { - m_calc_inversions = true; - RecalcInversions(); - } - else - { - m_calc_inversions = false; - m_inversions = -1; - } -} - -void SortArray::ResetArray(size_t size) -{ - m_array.resize(size, ArrayItem(0)); - m_mark.resize(size); -} - -void SortArray::FinishFill() -{ - ASSERT(m_array.size() > 0); - - // calculate max value in array - m_array_max = m_array[0].get_direct(); - for (size_t i = 1; i < size(); ++i) - { - if (m_array_max < m_array[i].get_direct()) - m_array_max = m_array[i].get_direct(); - } - - // reset access markers - unmark_all(); - unwatch_all(); - - // reset counters and info - m_is_sorted = false; - g_access_count = 0; - g_compare_count = 0; - m_calc_inversions = true; - - RecalcInversions(); -} - -void SortArray::FillInputlist(wxArrayString& list) -{ - list.Add(_("Random Shuffle")); - list.Add(_("Ascending")); - list.Add(_("Descending")); - list.Add(_("Near Sorted")); - list.Add(_("25% Sorted")); - list.Add(_("50% Sorted")); - list.Add(_("75% Sorted")); - list.Add(_("Shuffled Cubic")); - list.Add(_("Shuffled Quintic")); - list.Add(_("Shuffled n-2 Equal")); - list.Add(_("Pipe Organ")); - list.Add(_("Mirrored Organ")); -} - -void SortArray::FillData(unsigned int schema, size_t arraysize) -{ - if (arraysize == 0) arraysize = 1; - { ResetArray(arraysize); } - std::random_device rd; - std::mt19937 g(rd()); - if (schema == 0) // Shuffle of [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - m_array[i] = ArrayItem(i+1); - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 1) // Ascending [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - m_array[i] = ArrayItem(i+1); - } - else if (schema == 2) // Descending - { - for (size_t i = 0; i < m_array.size(); ++i) - m_array[i] = ArrayItem(m_array.size() - i); - } - else if (schema == 3) // Near Sorted - { - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - } - ArrayItem temp = m_array[0]; - m_array[0] = m_array[m_array.size() - 1]; - m_array[m_array.size() - 1] = temp; - } - else if (schema == 4) // 25% Sorted - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4) - 1) - { ++it; } - } - std::shuffle(it, m_array.end(), g); - } - else if (schema == 5) // 50% Sorted - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) - { ++it; } - } - std::shuffle(it, m_array.end(), g); - } - else if (schema == 6) // 75% Sorted - { - std::vector::iterator it = m_array.begin(); - size_t half = m_array.size() / 2; - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i < half + (half / 2)) - { ++it; } - } - std::shuffle(it, m_array.end(), g); - } - else if (schema == 7) // Cubic skew of [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - { - // normalize to [-1,+1] - double x = (2.0 * (double)i / m_array.size()) - 1.0; - // calculate x^3 - double v = x * x * x; - // normalize to array size - double w = (v + 1.0) / 2.0 * arraysize + 1; - // decrease resolution for more equal values - w /= 3.0; - m_array[i] = ArrayItem(w + 1); - } - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 8) // Quintic skew of [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - { - // normalize to [-1,+1] - double x = (2.0 * (double)i / m_array.size()) - 1.0; - // calculate x^5 - double v = x * x * x * x * x; - // normalize to array size - double w = (v + 1.0) / 2.0 * arraysize + 1; - // decrease resolution for more equal values - w /= 3.0; - m_array[i] = ArrayItem(w + 1); - } - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 9) // shuffled n-2 equal values in [1,n] - { - m_array[0] = ArrayItem(1); - for (size_t i = 1; i < m_array.size()-1; ++i) - { - m_array[i] = ArrayItem( arraysize / 2 + 1 ); - } - m_array[m_array.size()-1] = ArrayItem(arraysize); - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 10) // Pipe organ (1, 1, 2, 2, 1, 1) - { - int val = 1; - for (size_t i = 0; i < m_array.size() / 2; ++i) - { - m_array[i] = ArrayItem(val); ++val; - } - val = m_array.size() / 2; - for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) - { - m_array[i] = ArrayItem(val); --val; - } - } - else if (schema == 11) // Mirrored organ (3, 2, 1, 1, 2, 3) - { - int val = m_array.size() / 2; - for (size_t i = 0; i < m_array.size() / 2; ++i) - { - m_array[i] = ArrayItem(val); --val; - } - val = 1; - for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) - { - m_array[i] = ArrayItem(val); ++val; - } - } - else // fallback - { - return FillData(0, arraysize); - } - - FinishFill(); -} - -void SortArray::OnAccess() -{ - ++g_access_count; - - if (m_delay) - m_delay->OnAccess(); -} - -bool SortArray::CheckSorted() -{ - unmark_all(); - // needed because iterator instrumentated algorithms may have changed the array - RecalcInversions(); - - ArrayItem prev = get_nocount(0); - mark(0); - - bool is_sorted = true; - - for (size_t i = 1; i < size(); ++i) - { - ArrayItem key = get_nocount(i); - g_compare_count--; // dont count the following comparison - if (!(prev <= key)) { - wxLogError(_T("Result of sorting algorithm is incorrect!")); - is_sorted = false; - break; - } - mark(i); - prev = key; - } - - unmark_all(); - - return (m_is_sorted = is_sorted); -} - -void SortArray::SetCalcInversions(bool on) -{ - // toggle boolean - m_calc_inversions = on; - - if (!m_calc_inversions) - m_inversions = -1; -} - -void SortArray::ToggleCalcInversions() -{ - // toggle boolean - SetCalcInversions(!m_calc_inversions); -} - -void SortArray::RecalcInversions() -{ - if (!m_calc_inversions) { - m_inversions = -1; - return; - } - - unsigned int inversions = 0; - - for (size_t i = 0; i < size(); ++i) - { - const ArrayItem& a = direct(i); - - for (size_t j = i+1; j < size(); ++j) - { - const ArrayItem& b = direct(j); - - if ( a.greater_direct(b) ) - { - inversions++; - } - } - } - - m_inversions = inversions; -} - -void SortArray::UpdateInversions(size_t i, size_t j) -{ - if (!m_calc_inversions) { - m_inversions = -1; - return; - } - if (m_inversions < 0) return RecalcInversions(); - - if (i == j) return; - - unsigned int lo = i, hi = j; - if (lo > hi) std::swap(lo, hi); - - const ArrayItem& ilo = m_array[lo]; - const ArrayItem& ihi = m_array[hi]; - int invdelta = 0; - - for (size_t k = lo + 1; k < hi; ++k) - { - if (m_array[k].less_direct(ilo)) - invdelta--; - if (m_array[k].greater_direct(ilo)) - invdelta++; - - if (m_array[k].less_direct(ihi)) - invdelta++; - if (m_array[k].greater_direct(ihi)) - invdelta--; - } - - if (ilo.less_direct(ihi)) - invdelta++; - if (ilo.greater_direct(ihi)) - invdelta--; - - m_inversions += invdelta; -} - -size_t SortArray::GetRuns() const -{ - unsigned int runs = 1; - - for (size_t i = 1; i < size(); ++i) - { - const ArrayItem& a = direct(i-1); - const ArrayItem& b = direct(i); - - if ( a.greater_direct(b) ) - { - runs++; - } - } - - return runs; -} - -short SortArray::InAccessList(ssize_t idx) -{ - if (idx < 0) return -1; - - signed color = -1; - signed priority = -1; - - for (std::vector::iterator it = m_access_list.begin(); - it != m_access_list.end(); ) - { - if (it->index != (size_t)idx) { - ++it; - continue; - } - - if (it->priority >= priority) - { - priority = it->priority; - color = it->color; - } - - if (it->sustain == 0) { - if (it->index == m_access1.index || - it->index == m_access2.index) - { - ++it; - } - else - { - it = m_access_list.erase(it); - } - } - else { - it->sustain--; - ++it; - } - } - - return color; -} - -unsigned short SortArray::InWatchList(ssize_t idx) const -{ - for (size_t i = 0; i < m_watch.size(); ++i) - { - if (m_watch[i].first == NULL) continue; - - // compare watched value - if (*m_watch[i].first != idx) continue; - - return m_watch[i].second; - } - return 0; -} - -int SortArray::GetIndexColor(size_t idx) -{ - int clr; - - // select color - if (idx == m_access1.index) - { - clr = m_access1.color; - } - else if (idx == m_access2.index) - { - clr = m_access2.color; - } - else if ( (clr = InWatchList(idx)) != 0 ) - { - // clr already set - } - else if (m_mark[idx] != 0) - { - clr = m_mark[idx]; - } - else if ( (clr = InAccessList(idx)) >= 0 ) - { - } - else - { - clr = 0; - } - - return clr; -} - -// ***************************************************************************** From c3551ac232fd578960bab4e2e50433109d5f9a99 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 14:56:01 +0800 Subject: [PATCH 009/289] Delete SortArray.h --- SortArray.h | 450 ---------------------------------------------------- 1 file changed, 450 deletions(-) delete mode 100644 SortArray.h diff --git a/SortArray.h b/SortArray.h deleted file mode 100644 index 7a1874d24..000000000 --- a/SortArray.h +++ /dev/null @@ -1,450 +0,0 @@ -/******************************************************************************* - * src/SortArray.h - * - * SortArray represents a simple array, which is displayed by WSortView to the - * user is real-time. - * - ******************************************************************************* - * Copyright (C) 2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - ******************************************************************************/ - -#ifndef SORT_ARRAY_HEADER -#define SORT_ARRAY_HEADER - -#include -#include -#include - -#include -#include -#include - -// ---------------------------------------------------------------------------- - -/// custom assertion (also active in release mode) -#define ASSERT(cond) do { if (!(cond)) { \ - wxLogError(_("Assertion failed:\n%s in %s:%d"), \ - _T(#cond), _T(__FILE__), __LINE__); \ - wxLog::FlushActive(); \ - abort(); \ -} } while(0) - -// ---------------------------------------------------------------------------- - -/// globally count the number of comparisons done on value_type -extern size_t g_compare_count; - -/// globally count the number of array access -extern size_t g_access_count; - -// custom struct for array items, which allows detailed counting of comparisons. -class ArrayItem -{ -public: - typedef int value_type; - -protected: - value_type value; - -public: - ArrayItem() {} - - explicit ArrayItem(const value_type& d) : value(d) {} - - ArrayItem(const ArrayItem& v) : value(v.value) {} - - // ArrayItem has no implicit data cast, because most sorting algorithms use - // comparisons. However, radix sort and similar use the following data - // accessor. To add sound for these, we use a separate callback. - const value_type& get() const - { OnAccess(*this); return value; } - - static void OnAccess(const ArrayItem& a); - - // for direct data access by visualizer - const value_type& get_direct() const - { return value; } - - // *** comparisons - - bool operator== (const ArrayItem& v) const - { OnComparison(*this,v); return (value == v.value); } - - bool operator!= (const ArrayItem& v) const - { OnComparison(*this,v); return (value != v.value); } - - bool operator< (const ArrayItem& v) const - { OnComparison(*this,v); return (value < v.value); } - - bool operator<= (const ArrayItem& v) const - { OnComparison(*this,v); return (value <= v.value); } - - bool operator> (const ArrayItem& v) const - { OnComparison(*this,v); return (value > v.value); } - - bool operator>= (const ArrayItem& v) const - { OnComparison(*this,v); return (value >= v.value); } - - // ternary comparison which counts just one - int cmp(const ArrayItem& v) const - { - OnComparison(*this,v); - return (value == v.value ? 0 : value < v.value ? -1 : +1); - } - - // *** comparisons without sound, counting or delay - - bool equal_direct(const ArrayItem& v) const - { return (value == v.value); } - - bool less_direct(const ArrayItem& v) const - { return (value < v.value); } - - bool greater_direct(const ArrayItem& v) const - { return (value > v.value); } - - static void OnComparison(const ArrayItem& a, const ArrayItem& b); -}; - -// ---------------------------------------------------------------------------- - -class SortDelay -{ -public: - - /// central access function called by each array access of the algorithms - virtual void OnAccess() = 0; -}; - -// ---------------------------------------------------------------------------- - -class SortArray -{ -protected: - // *** Displayed Array Data - - /// the array data - std::vector m_array; - - /// maximum value in array for scaling display - ArrayItem::value_type m_array_max; - - /// disable calculating of inversions - bool m_calc_inversions; - - /// the number of inversions in the array order - ssize_t m_inversions; - - /// access touch color - struct Access - { - unsigned int index; - unsigned short color; - unsigned short sustain; - unsigned short priority; - - Access(size_t i=0, unsigned short c=1, - unsigned short s=0, unsigned short p=0) - : index(i), color(c), sustain(s), priority(p) { } - }; - - /// position of very last get/set accesses (two for swaps) - Access m_access1, m_access2; - - /// array of get/set accesses since last paint event - std::vector m_access_list; - - /// custom markers in the array, set by algorithm - std::vector m_mark; - - /// custom watched index pointers in the array, set by algorithm - std::vector< std::pair > m_watch; - - /// flag for sorted array - bool m_is_sorted; - - /// pointer to delay function - SortDelay* m_delay; - -public: - /// mutex for accesses and watch items - wxMutex m_mutex; - - // *** Array Functions - -public: - /// constructor - SortArray(); - - /// Set pointer to delay functional - void SetSortDelay(SortDelay* delay) { m_delay = delay; } - - /// called by main when an algorithm starts - void OnAlgoLaunch(const struct AlgoEntry& ae); - - /// turn on/off calculation of inversions - void SetCalcInversions(bool on); - - /// toggle boolean to calculate inversions - void ToggleCalcInversions(); - - /// fill the array with one of the predefined data templates - void FillData(unsigned int schema, size_t arraysize); - - /// fill an array of strings with the list of predefined data templates - static void FillInputlist(wxArrayString& list); - - /// return whether the array was sorted - bool IsSorted() const { return m_is_sorted; } - - /// central access function called by each array access of the algorithms - void OnAccess(); - - /// check array after sorting algorithm - bool CheckSorted(); - - /// return the number of inversions in the array - ssize_t GetInversions() const - { return m_inversions; } - - /// calculate the number of runs in the array - size_t GetRuns() const; - -public: - /// reset the array to the given size - void ResetArray(size_t size); - - /// called when the data fill function is finished - void FinishFill(); - - /// save access to array, forwards to sound system - void SaveAccess(size_t i); - - /// check if index matches one of the watched pointers - short InAccessList(ssize_t idx); - - /// check if index matches one of the watched pointers - unsigned short InWatchList(ssize_t idx) const; - - /// Calculate the current color of the index i - int GetIndexColor(size_t idx); - - /// recalculate the number of inversions (in quadratic time) - void RecalcInversions(); - - // update inversion count by calculating delta linearly for a swap - void UpdateInversions(size_t i, size_t j); - -public: - /// return array size - size_t size() const { return m_array.size(); } - - /// return highest element value in array - const ArrayItem::value_type& array_max() const - { return m_array_max; } - - /// Return an item of the array (bypassing sound, counting and delay) - const ArrayItem& direct(size_t i) const - { - ASSERT(i < m_array.size()); - return m_array[i]; - } - - /// Return an item of the array (yields counting and delay) - const ArrayItem& operator[](size_t i) - { - ASSERT(i < m_array.size()); - - if (m_access1.index != i) - { - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_access1 = i; - m_access_list.push_back(i); - } - - // skip wait for duplicate accesses - OnAccess(); - } - - return m_array[i]; - } - - /// Return a mutable item of the array (yields counting and delay) - ArrayItem& get_mutable(size_t i) - { - ASSERT(i < m_array.size()); - - if (m_access1.index != i) - { - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_access1 = i; - m_access_list.push_back(i); - } - - // skip wait for duplicate accesses - OnAccess(); - } - - RecalcInversions(); - return m_array[i]; - } - - /// Return an item of the array (yields delay, but no counting) - const ArrayItem& get_nocount(size_t i) - { - ASSERT(i < m_array.size()); - - if (m_access1.index != i) - { - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_access1 = i; - m_access_list.push_back(i); - } - - // skip wait for duplicate accesses - --g_access_count; - OnAccess(); - } - - return m_array[i]; - } - - /// Set an item of the array: first set then yield sound, counting and delay. - void set(size_t i, const ArrayItem& v) - { - ASSERT(i < m_array.size()); - - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_access1 = i; - m_access_list.push_back(i); - - m_array[i] = v; - } - - RecalcInversions(); - OnAccess(); - } - - /// Special function to swap the value in the array, this method provides a - /// special visualization for this operation. - void swap(size_t i, size_t j) - { - ASSERT(i < m_array.size()); - ASSERT(j < m_array.size()); - - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_access1 = i; - m_access2 = j; - - m_access_list.push_back(i); - m_access_list.push_back(j); - } - - UpdateInversions(i, j); // update inversion count - - OnAccess(); - std::swap(m_array[i], m_array[j]); - OnAccess(); - m_access2 = -1; - } - - /// Touch an item of the array: set color till next frame is outputted. - void touch(size_t i, int color = 2, - unsigned short sustain = 0, unsigned short priority = 0) - { - ASSERT(i < m_array.size()); - - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_access1 = Access(i, color, sustain, priority); - m_access_list.push_back( Access(i, color, sustain, priority) ); - } - } - - /// Mark an array index with a color. - void mark(size_t i, int color = 2) - { - ASSERT(i < m_array.size()); - m_mark[i] = color; - } - - /// Swap color for two array indexes. - void mark_swap(size_t i, size_t j) - { - ASSERT(i < m_array.size()); - ASSERT(j < m_array.size()); - - std::swap(m_mark[i], m_mark[j]); - } - - /// Unmark an array index. - void unmark(size_t i) - { - ASSERT(i < m_array.size()); - m_mark[i] = 0; - } - - /// Unmark all array indexes. - void unmark_all() - { - m_access1 = m_access2 = -1; - std::fill(m_mark.begin(), m_mark.end(), 0); - - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - m_access_list.clear(); - } - - /// Highly experimental method to _track_ array live indexes. For this, the - /// index must be marked volatile!. - void watch(volatile ssize_t* idxptr, unsigned char color = 2) - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_watch.push_back( std::make_pair(idxptr,color) ); - } - - /// Release all tracked live array indexes. - void unwatch_all() - { - wxMutexLocker lock(m_mutex); - ASSERT(lock.IsOk()); - - m_watch.clear(); - } -}; - -// ---------------------------------------------------------------------------- - -#endif // SORT_ARRAY_HEADER From d21d7a148d3ea6e4f8ddb6a59007b2d6bd86914b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 14:57:05 +0800 Subject: [PATCH 010/289] Changed random_shuffle to shuffle This should slightly reduce warnings, as well as improving the randomization of the application for all input types and Bogo/Bozo Sort --- src/SortAlgo.cpp | 9 +++++---- src/SortArray.cpp | 23 ++++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 7052355fa..d467b56e3 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -37,6 +37,7 @@ #include #include #include +#include typedef ArrayItem value_type; @@ -1058,13 +1059,11 @@ void StlHeapSort(SortArray& A) bool BogoCheckSorted(SortArray& A) { size_t i; - value_type prev = A[0]; A.mark(0); for (i = 1; i < A.size(); ++i) { value_type val = A[i]; - if (prev > val) break; - prev = val; + if (A[i - 1] > A[i]) break; A.mark(i); } @@ -1094,7 +1093,9 @@ void BogoSort(SortArray& A) if (BogoCheckSorted(A)) break; // pick a random permutation of indexes - std::random_shuffle(perm.begin(), perm.end()); + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(perm.begin(), perm.end(), g); // permute array in-place std::vector pmark(A.size(), 0); diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 34c31a2b2..ac9489820 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -25,6 +25,7 @@ #include "SortAlgo.h" #include +#include extern void SoundAccess(size_t i); @@ -121,15 +122,15 @@ void SortArray::FillInputlist(wxArrayString& list) void SortArray::FillData(unsigned int schema, size_t arraysize) { if (arraysize == 0) arraysize = 1; - - ResetArray(arraysize); - + { ResetArray(arraysize); } + std::random_device rd; + std::mt19937 g(rd()); if (schema == 0) // Shuffle of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) m_array[i] = ArrayItem(i+1); - - std::random_shuffle(m_array.begin(), m_array.end()); + + std::shuffle(m_array.begin(), m_array.end(), g); } else if (schema == 1) // Ascending [1,n] { @@ -160,7 +161,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) if (i <= (m_array.size() / 4) - 1) { ++it; } } - std::random_shuffle(it, m_array.end()); + std::shuffle(it, m_array.end(), g); } else if (schema == 5) // 50% Sorted { @@ -171,7 +172,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) if (i <= (m_array.size() / 2) - 1) { ++it; } } - std::random_shuffle(it, m_array.end()); + std::shuffle(it, m_array.end(), g); } else if (schema == 6) // 75% Sorted { @@ -183,7 +184,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) if (i < half + (half / 2)) { ++it; } } - std::random_shuffle(it, m_array.end()); + std::shuffle(it, m_array.end(), g); } else if (schema == 7) // Cubic skew of [1,n] { @@ -200,7 +201,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(w + 1); } - std::random_shuffle(m_array.begin(), m_array.end()); + std::shuffle(m_array.begin(), m_array.end(), g); } else if (schema == 8) // Quintic skew of [1,n] { @@ -217,7 +218,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(w + 1); } - std::random_shuffle(m_array.begin(), m_array.end()); + std::shuffle(m_array.begin(), m_array.end(), g); } else if (schema == 9) // shuffled n-2 equal values in [1,n] { @@ -228,7 +229,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } m_array[m_array.size()-1] = ArrayItem(arraysize); - std::random_shuffle(m_array.begin(), m_array.end()); + std::shuffle(m_array.begin(), m_array.end(), g); } else if (schema == 10) // Pipe organ (1, 1, 2, 2, 1, 1) { From 5c676de91fe3e42043f7fd01ffa620fd89018d6d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 15:33:38 +0800 Subject: [PATCH 011/289] Update SortAlgo.cpp --- src/SortAlgo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d467b56e3..fd67a6807 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1062,7 +1062,6 @@ bool BogoCheckSorted(SortArray& A) A.mark(0); for (i = 1; i < A.size(); ++i) { - value_type val = A[i]; if (A[i - 1] > A[i]) break; A.mark(i); } From b921f03b9266b261e86ffc70cec7f329e820d80c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 15:51:15 +0800 Subject: [PATCH 012/289] Removed InsertionSort2 warning --- src/SortAlgo.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index fd67a6807..627791fd4 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -199,11 +199,10 @@ void InsertionSort2(SortArray& A) { for (size_t i = 1; i < A.size(); ++i) { - value_type tmp, key = A[i]; A.mark(i); - ssize_t j = i - 1; - while (j >= 0 && (tmp = A[j]) > key) + value_type tmp = A[j], key = A[i]; + while (j >= 0 && tmp > key) { A.set(j + 1, tmp); j--; From c11df95a58f981dfcb5038449ea637aca7a6991b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 15:57:41 +0800 Subject: [PATCH 013/289] Quick Sort LL volatile long fix --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 627791fd4..f2f2e79df 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -593,7 +593,7 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t } A.unmark_all(); - return std::make_pair(i,j); + return std::make_pair((ssize_t)i,j); } void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) From 6205abc9e0c5a54b97104d3ce5efc2654183577a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 16:49:39 +0800 Subject: [PATCH 014/289] Introduce 4 new sorting algorithms Introduced 4 new sorting algorithms: - Optimized Gnome Sort - Dual Cocktail Shaker Sort - Double Selection Sort - Double Exchange Sort --- src/SortAlgo.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++- src/SortAlgo.h | 4 ++ 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f2f2e79df..fbb78b62d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -48,8 +48,12 @@ const struct AlgoEntry g_algolist[] = { { _("Selection Sort"), &SelectionSort, UINT_MAX, UINT_MAX, wxEmptyString }, - { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, + { _("Double Selection Sort"), &DoubleSelectionSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, + _("Also known as Exchange Sort.") }, + { _("Double Sandpaper Sort"), &DoubleSandpaperSort, UINT_MAX, UINT_MAX, + _("A variant of Exchange Sort that sorts the array bidirectionally.") }, { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, @@ -78,8 +82,12 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, + _("This variant sorts from both directions of the array simultaneously.") }, { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Optimized Gnome Sort"), &OptimizedGnomeSort, UINT_MAX, UINT_MAX, + _("This variant avoids scanning through sorted portions of the array after a number has been placed in its correct spot") }, { _("Comb Sort"), &CombSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Shell Sort"), &ShellSort, UINT_MAX, 1024, @@ -132,6 +140,36 @@ const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; // **************************************************************************** // *** Selection Sort +void DoubleSelectionSort(SortArray& A) +{ + size_t left = 0; + size_t right = A.size() - 1; + volatile size_t max_idx = 0; + volatile size_t low_idx = 0; + while (left < right) + { + max_idx = right; + low_idx = left; + for (size_t i = left; i <= right; ++i) + { + if (A[i] < A[low_idx]) + { + A.mark_swap(i, low_idx); + low_idx = i; + } + else if (A[i] > A[max_idx]) + { + A.mark_swap(i, max_idx); + max_idx = i; + } + } + A.swap(left, low_idx); + if (max_idx == left) { max_idx = low_idx; } + A.swap(right, max_idx); + ++left; --right; + } +} + void SelectionSort(SortArray& A) { volatile ssize_t jMin = 0; @@ -158,6 +196,24 @@ void SelectionSort(SortArray& A) A.unwatch_all(); } +void DoubleSandpaperSort(SortArray& A) +{ + for (size_t left = 0, right = A.size() - 1; left < right; ++left, --right) + { + for (size_t i = left + 1, j = right; i <= right; ++i, --j) + { + if (A[left] > A[i]) + { + A.swap(i, left); + } + if (A[right] < A[j]) + { + A.swap(j, right); + } + } + } +} + void SandpaperSort(SortArray& A) { size_t n = A.size(); @@ -728,6 +784,31 @@ void CocktailShakerSort(SortArray& A) } } +void DualCocktailShakerSort(SortArray& A) +{ + size_t lo = 0, hi = A.size() - 1; + bool swapped = true; + while (swapped) + { + swapped = false; + for (size_t i = lo, j = hi; i < hi; ++i, --j) + { + if (A[i] > A[i + 1]) + { + A.swap(i + 1, i); + swapped = true; + } + if (A[j] < A[j - 1]) + { + A.swap(j - 1, j); + swapped = true; + } + } + ++lo; + --hi; + } +} + // **************************************************************************** // *** Gnome Sort @@ -749,6 +830,24 @@ void GnomeSort(SortArray& A) } } +void OptimizedGnomeSort(SortArray& A) +{ + size_t prev = 0; + for (size_t i = 1; i < A.size(); ) + { + if (i == 0 || A[i] >= A[i - 1]) + { + if (prev != 0) { i += prev; prev = 0; } + ++i; + } + else + { + A.swap(i, i - 1); + --i; ++prev; + } + } +} + // **************************************************************************** // *** Comb Sort @@ -1148,7 +1247,6 @@ void flip(SortArray& A, size_t high) size_t low = 0; while (low < high) { - A.mark_swap(low, high); A.swap(low, high); ++low; --high; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 0227a1af6..1659c9cb2 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -53,7 +53,9 @@ extern const struct AlgoEntry* g_algolist_end; // *** Sorting Algorithms void SelectionSort(class SortArray& a); +void DoubleSelectionSort(class SortArray& a); void SandpaperSort(class SortArray& a); +void DoubleSandpaperSort(class SortArray& a); void InsertionSort(class SortArray& a); void BinaryInsertionSort(class SortArray& a); @@ -73,8 +75,10 @@ void QuickSortDualPivot(class SortArray& a); void BubbleSort(class SortArray& a); void CocktailShakerSort(class SortArray& a); +void DualCocktailShakerSort(class SortArray& a); void CombSort(class SortArray& a); void GnomeSort(class SortArray& a); +void OptimizedGnomeSort(class SortArray& a); void OddEvenSort(class SortArray& a); void ShellSort(SortArray& a); From 899671b895826d54b389b58e8fcc4729f6a014ea Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 17:02:47 +0800 Subject: [PATCH 015/289] Update SortAlgo.cpp Fixed DoubleSandpaperSort --- src/SortAlgo.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index fbb78b62d..eeb250eb5 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -200,15 +200,19 @@ void DoubleSandpaperSort(SortArray& A) { for (size_t left = 0, right = A.size() - 1; left < right; ++left, --right) { - for (size_t i = left + 1, j = right; i <= right; ++i, --j) + if (A[left] > A[right]) + { + A.swap(left, right); + } + for (size_t i = left + 1; i <= right; ++i) { if (A[left] > A[i]) { - A.swap(i, left); + A.swap(i, left); } - if (A[right] < A[j]) + else if (A[i] > A[right]) { - A.swap(j, right); + A.swap(i, right); } } } From bbe2bc0571cf3d81dda4e919e4135863cef2b87b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 17:34:41 +0800 Subject: [PATCH 016/289] Update SortAlgo.cpp Slightly tweaked Double Sandpaper Sort --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index eeb250eb5..7c3a4ab94 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -204,7 +204,7 @@ void DoubleSandpaperSort(SortArray& A) { A.swap(left, right); } - for (size_t i = left + 1; i <= right; ++i) + for (size_t i = left + 1; i < right; ++i) { if (A[left] > A[i]) { From 3c102d3ef1276a4a91da4731fcc00163af9ca683 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 18:30:56 +0800 Subject: [PATCH 017/289] Simplified find_max() method of Pancake Sort It should make the find_max() method more readable, and hopefully more performant. --- src/SortAlgo.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 7c3a4ab94..d97e3fdb9 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1259,9 +1259,7 @@ void flip(SortArray& A, size_t high) size_t find_max(SortArray& A, size_t n) // Optimized find_max method, the original method performs the search in linear time { size_t max = 0; - size_t low = 1; - size_t hi = n; - while (low <= hi) + for (size_t low = 1, hi = n; low <= hi; ++low, --hi) { if (A[low] > A[max]) { @@ -1271,7 +1269,6 @@ size_t find_max(SortArray& A, size_t n) // Optimized find_max method, the origi { max = hi; } - ++low; --hi; } return max; } From 95af55b1798b74425b02c7d68bc13c7e8a8909d7 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 20:50:18 +0800 Subject: [PATCH 018/289] Pancake Sort sound during flip --- src/SortAlgo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d97e3fdb9..0e0f86977 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1251,6 +1251,7 @@ void flip(SortArray& A, size_t high) size_t low = 0; while (low < high) { + A[low].get(); A.swap(low, high); ++low; --high; } From 585b238dea4fc541ae21c0e26f8c12325663a035 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 22:24:43 +0800 Subject: [PATCH 019/289] Introduce optimized variants of Bubble/Cocktail Due to n% pre-sorted data input types being available, adding the optimized variant of Bubble Sort and Cocktail Shaker Sort now has even more value. The original variants have been kept for demonstration and educational purposes, to show that a simple swapped/sorted boolean flag can make a difference in terms of performance. --- src/SortAlgo.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++- src/SortAlgo.h | 2 ++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 0e0f86977..f0d6db646 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -80,8 +80,12 @@ const struct AlgoEntry g_algolist[] = "two at left and one at right.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, + _("This variant can detect if an array is sorted, if the array is sorted, the sorting process will stop.") }, { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Optimized Cocktail Shaker Sort"), &OptimizedCocktailShakerSort, UINT_MAX, UINT_MAX, + _("This variant can detect if the array is sorted, in which it will terminate early. This allows for better performance on pre-sorted data.") }, { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, _("This variant sorts from both directions of the array simultaneously.") }, { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, @@ -284,7 +288,7 @@ void BinaryInsertionSort(SortArray& A) int lo = 0, hi = i; while (lo < hi) { int mid = (lo + hi) / 2; - if (key <= A[mid]) + if (key < A[mid]) hi = mid; else lo = mid + 1; @@ -753,6 +757,23 @@ void BubbleSort(SortArray& A) } } +void OptimizedBubbleSort(SortArray& A) +{ + for (size_t i = 0; i < A.size() - 1; ++i) + { + bool sorted = true; + for (size_t j = 0; j < A.size() - 1 - i; ++j) + { + if (A[j] > A[j + 1]) + { + A.swap(j, j + 1); + sorted = false; + } + } + if (sorted == true) { break; } + } +} + // **************************************************************************** // *** Cocktail Shaker Sort @@ -788,6 +809,37 @@ void CocktailShakerSort(SortArray& A) } } +void OptimizedCocktailShakerSort(SortArray& A) +{ + size_t lo = 0, hi = A.size() - 1, mov = lo; + bool swapped = true; + while (swapped == true) + { + swapped = false; + for (size_t i = hi; i > lo; --i) + { + if (A[i - 1] > A[i]) + { + A.swap(i - 1, i); + swapped = true; + mov = i; + } + } + if (swapped == false) { break; } + lo = mov; + for (size_t i = lo; i < hi; ++i) + { + if (A[i] > A[i + 1]) + { + A.swap(i, i + 1); + swapped = true; + mov = i; + } + } + hi = mov; + } +} + void DualCocktailShakerSort(SortArray& A) { size_t lo = 0, hi = A.size() - 1; diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 1659c9cb2..47d923993 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -74,7 +74,9 @@ void QuickSortTernaryLL(class SortArray& a); void QuickSortDualPivot(class SortArray& a); void BubbleSort(class SortArray& a); +void OptimizedBubbleSort(class SortArray& a); void CocktailShakerSort(class SortArray& a); +void OptimizedCocktailShakerSort(class SortArray& a); void DualCocktailShakerSort(class SortArray& a); void CombSort(class SortArray& a); void GnomeSort(class SortArray& a); From 2d02359cddfda1a7938dac9c1433ddfad824b077 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 22:29:33 +0800 Subject: [PATCH 020/289] Removed Optimized Cocktail Shaker Sort The Cocktail Shaker Sort that current exists in the visualizer is already optimized --- src/SortAlgo.cpp | 33 --------------------------------- src/SortAlgo.h | 1 - 2 files changed, 34 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f0d6db646..794fb11f9 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -84,8 +84,6 @@ const struct AlgoEntry g_algolist[] = _("This variant can detect if an array is sorted, if the array is sorted, the sorting process will stop.") }, { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, wxEmptyString }, - { _("Optimized Cocktail Shaker Sort"), &OptimizedCocktailShakerSort, UINT_MAX, UINT_MAX, - _("This variant can detect if the array is sorted, in which it will terminate early. This allows for better performance on pre-sorted data.") }, { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, _("This variant sorts from both directions of the array simultaneously.") }, { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, @@ -809,37 +807,6 @@ void CocktailShakerSort(SortArray& A) } } -void OptimizedCocktailShakerSort(SortArray& A) -{ - size_t lo = 0, hi = A.size() - 1, mov = lo; - bool swapped = true; - while (swapped == true) - { - swapped = false; - for (size_t i = hi; i > lo; --i) - { - if (A[i - 1] > A[i]) - { - A.swap(i - 1, i); - swapped = true; - mov = i; - } - } - if (swapped == false) { break; } - lo = mov; - for (size_t i = lo; i < hi; ++i) - { - if (A[i] > A[i + 1]) - { - A.swap(i, i + 1); - swapped = true; - mov = i; - } - } - hi = mov; - } -} - void DualCocktailShakerSort(SortArray& A) { size_t lo = 0, hi = A.size() - 1; diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 47d923993..7556e1abb 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -76,7 +76,6 @@ void QuickSortDualPivot(class SortArray& a); void BubbleSort(class SortArray& a); void OptimizedBubbleSort(class SortArray& a); void CocktailShakerSort(class SortArray& a); -void OptimizedCocktailShakerSort(class SortArray& a); void DualCocktailShakerSort(class SortArray& a); void CombSort(class SortArray& a); void GnomeSort(class SortArray& a); From 71fc5a20d87751f7a5fb23aaeda38eb82aab9b25 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 5 Oct 2024 22:49:55 +0800 Subject: [PATCH 021/289] Fix lag when using Heap Sort on large array size Fix by @chroni, before this fix, using Heap Sort to sort an array with large input size causes a major lag --- src/SortArray.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index ac9489820..6d1524ca8 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -457,7 +457,7 @@ unsigned short SortArray::InWatchList(ssize_t idx) const int SortArray::GetIndexColor(size_t idx) { - int clr; + int clr, acl = InAccessList(idx); // select color if (idx == m_access1.index) @@ -476,8 +476,9 @@ int SortArray::GetIndexColor(size_t idx) { clr = m_mark[idx]; } - else if ( (clr = InAccessList(idx)) >= 0 ) + else if ( acl >= 0 ) { + clr = acl; } else { From 3fd52319fc93fb62751d0613244ae9c28cfc712e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 6 Oct 2024 00:27:09 +0800 Subject: [PATCH 022/289] Introduced Wave input type --- src/SortArray.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 6d1524ca8..395118d18 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -26,6 +26,7 @@ #include #include +#include extern void SoundAccess(size_t i); @@ -117,6 +118,7 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Shuffled n-2 Equal")); list.Add(_("Pipe Organ")); list.Add(_("Mirrored Organ")); + list.Add(_("Wave")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -257,6 +259,18 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val); ++val; } } + else if (schema == 12) // Wave + { + double n = double(m_array.size()); + double pi = 3.14159265358979323846; + for (size_t i = 0; i < m_array.size(); ++i) + { + double x = i / n * 3 * pi * 5; + double sineVal = sin(x); + int val = std::round((sineVal + 1) * 100); + m_array[i] = ArrayItem(val + 1); + } + } else // fallback { return FillData(0, arraysize); From e26a2735d4dac882ed98c7ab369224fc38739311 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 6 Oct 2024 01:33:08 +0800 Subject: [PATCH 023/289] Add files via upload --- src/WSortView.cpp | 8 ++++---- src/WSortView.h | 11 +++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index b11542ba8..49ca500c6 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -249,11 +249,11 @@ END_EVENT_TABLE() // **************************************************************************** // *** Threading -SortAlgoThread::SortAlgoThread(WMain* wmain, class WSortView& sortview, size_t algo) +SortAlgoThread::SortAlgoThread(WMain* wmain, WSortView& sortview, size_t algo) : wxThread(wxTHREAD_JOINABLE), - m_wmain(wmain), - m_sortview(sortview), - m_algo(algo) + m_wmain(wmain), + m_sortview(sortview), + m_algo(algo) { } diff --git a/src/WSortView.h b/src/WSortView.h index da5f0f064..92a57e640 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -37,7 +37,7 @@ extern bool g_sound_on; extern double g_sound_sustain; /// the SDL sound callback -void SoundCallback(void *udata, unsigned char *stream, int len); +void SoundCallback(void* udata, Uint8* stream, int len); /// reset internal state of sound generator void SoundReset(); @@ -106,14 +106,13 @@ class WSortView : public wxPanel, public SortDelay class SortAlgoThread : public wxThread { protected: - class WMain* m_wmain; - class WSortView& m_sortview; - - size_t m_algo; + WMain* m_wmain; + WSortView& m_sortview; + size_t m_algo; public: - SortAlgoThread(class WMain* wmain, class WSortView& sortview, size_t algo); + SortAlgoThread(WMain* wmain, WSortView& sortview, size_t algo); virtual ExitCode Entry(); From 22fa431bd8366311de802b3093a82373a7ddcdca Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 6 Oct 2024 01:54:07 +0800 Subject: [PATCH 024/289] Add files via upload --- src/WSortView.cpp | 282 ---------------------------------------------- src/WSortView.h | 124 -------------------- 2 files changed, 406 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 49ca500c6..e69de29bb 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -1,282 +0,0 @@ -/****************************************************************************** - * src/WSortView.cpp - * - * WSortView contains both the instrumentated array operators and draws the - * displayed visualization. - * - ****************************************************************************** - * Copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#include "WSortView.h" -#include "SortAlgo.h" -#include "WMain.h" - -#include - -// **************************************************************************** -// *** WSortView - -double g_delay = 0; - -bool g_algo_running = false; - -wxString g_algo_name; - -WSortView::WSortView(wxWindow *parent, int id, class WMain_wxg* wmain) - : wxPanel(parent, id), - wmain(reinterpret_cast(wmain)) -{ - SetBackgroundStyle(wxBG_STYLE_CUSTOM); - - m_stepwise = false; - m_array.SetSortDelay(this); -} - -WSortView::~WSortView() -{ -} - -#if MSW_PERFORMANCECOUNTER - -void mswMicroSleep(int microseconds) -{ - static LARGE_INTEGER s_liFreq = { 0, 0 }; - - if (s_liFreq.QuadPart == 0) - QueryPerformanceFrequency(&s_liFreq); - - LARGE_INTEGER liStart, liGoal; - QueryPerformanceCounter(&liStart); - - liGoal.QuadPart = liStart.QuadPart; - liGoal.QuadPart += (s_liFreq.QuadPart * microseconds) / 1000000; - LARGE_INTEGER liAct; - do - { - QueryPerformanceCounter(&liAct); - if (liStart.QuadPart > liAct.QuadPart) break; - } while(liAct.QuadPart < liGoal.QuadPart); -} - -#endif // MSW_PERFORMANCECOUNTER - -void WSortView::DoDelay(double delay) -{ - // must be called by the algorithm thread - ASSERT(wmain->m_thread); - ASSERT(wxThread::GetCurrentId() == wmain->m_thread->GetId()); - - if (wmain->m_thread_terminate) - wmain->m_thread->Exit(); - - // idle until main thread signals a condition - while (m_stepwise) - { - wxSemaError se = m_step_semaphore.WaitTimeout(200); - if (se == wxSEMA_NO_ERROR) - break; - // else timeout, recheck m_stepwise and loop - wmain->m_thread->TestDestroy(); - wmain->m_thread->Yield(); - } - - wmain->m_thread->TestDestroy(); - -#if __WXGTK__ - wxMicroSleep(delay * 1000.0); -#elif MSW_PERFORMANCECOUNTER - mswMicroSleep(delay * 1000.0); -#else - // wxMSW does not have a high resolution timer, maybe others do? - wxMilliSleep(delay); -#endif -} - -void WSortView::OnAccess() -{ - DoDelay(g_delay); -} - -void WSortView::DoStepwise() -{ - wxSemaError se = m_step_semaphore.Post(); - if (se != wxSEMA_NO_ERROR) { - wxLogError(_T("Error posting to semaphore: %d"), se); - } -} - -void WSortView::RepaintNow() -{ - if (!IsShownOnScreen()) return; - - wxClientDC dc(this); - wxBufferedDC bdc(&dc, GetSize(), wxBUFFER_CLIENT_AREA); - paint(bdc, GetSize()); -} - -void WSortView::OnPaint(wxPaintEvent&) -{ - wxAutoBufferedPaintDC dc(this); - // on wxMSW, wxAutoBufferedPaintDC holds a bitmap. The bitmaps size = - // wxDC's size may not match the window size, thus we pass the window size - // explicitly. - paint(dc, GetSize()); -} - -void WSortView::OnSize(wxSizeEvent&) -{ - // full redraw on resize - Refresh(false); -} - -void WSortView::paint(wxDC& dc, const wxSize& dcsize) -{ - dc.SetBackground(*wxBLACK_BRUSH); - dc.Clear(); - - if (m_array.size() == 0) return; - - size_t size = m_array.size(); - - size_t fwidth = dcsize.GetWidth(); - size_t fheight = dcsize.GetHeight(); - - size_t width = fwidth - 20; - size_t height = fheight - 20; - - dc.SetDeviceOrigin(10,10); - - // *** draw array element bars - - // draw | | | | bars: each bar is width w, separation is w/2 - // thus n bars need n * w + (n-1) * w/2 width - - // 1st variant: space is 0.5 of bar size - //double wbar = width / (size + (size-1) / 2.0); - //double bstep = 1.5 * wbar; - - // 2nd variant: one pixel between bars - double wbar = (width - (size-1)) / (double)size; - if (width <= (size-1)) wbar = 0.0; - - double bstep = wbar + 1.0; - - // special case for bstep = 2 pixel -> draw 2 pixel bars instead of 1px - // bar/1px gaps. - if ( fabs(wbar - 1.0) < 0.1 && fabs(bstep - 2.0) < 0.1 ) wbar = 2, bstep = 2; - - static const wxPen pens[] = { - *wxWHITE_PEN, - *wxRED_PEN, - *wxGREEN_PEN, - *wxCYAN_PEN, - wxPen(wxColour(255,255,0)), // 4 yellow - wxPen(wxColour(255,0,255)), // 5 magenta - wxPen(wxColour(255,192,128)), // 6 orange - wxPen(wxColour(255,128,192)), // 7 pink - wxPen(wxColour(128,192,255)), // 8 darker cyan - wxPen(wxColour(192,255,128)), // 9 darker green - wxPen(wxColour(192,128,255)), // 10 purple - wxPen(wxColour(128,255,192)), // 11 light green - wxPen(wxColour(128,128,255)), // 12 blue - wxPen(wxColour(192,128,192)), // 13 dark purple - wxPen(wxColour(128,192,192)), // 14 dark cyan - wxPen(wxColour(192,192,128)), // 15 dark yellow - wxPen(wxColour(0,128,255)), // 16 blue/cyan mix - }; - - static const wxBrush brushes[] = { - *wxWHITE_BRUSH, - *wxRED_BRUSH, - *wxGREEN_BRUSH, - *wxCYAN_BRUSH, - wxBrush(wxColour(255,255,0)), // 4 yellow - wxBrush(wxColour(255,0,255)), // 5 magenta - wxBrush(wxColour(255,192,128)), // 6 orange - wxBrush(wxColour(255,128,192)), // 7 pink - wxBrush(wxColour(128,192,255)), // 8 darker cyan - wxBrush(wxColour(192,255,128)), // 9 darker green - wxBrush(wxColour(192,128,255)), // 10 purple - wxBrush(wxColour(128,255,192)), // 11 light green - wxBrush(wxColour(128,128,255)), // 12 blue - wxBrush(wxColour(192,128,192)), // 13 dark purple - wxBrush(wxColour(128,192,192)), // 14 dark cyan - wxBrush(wxColour(192,192,128)), // 15 dark yellow - wxBrush(wxColour(0,128,255)), // 16 blue/cyan mix - }; - - wxMutexLocker lock(m_array.m_mutex); - ASSERT(lock.IsOk()); - - for (size_t i = 0; i < size; ++i) - { - int clr = m_array.GetIndexColor(i); - - ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); - dc.SetPen( pens[clr] ); - dc.SetBrush( brushes[clr] ); - - dc.DrawRectangle(i*bstep, height, - wxMax(1, // draw at least 1 pixel - (wxCoord((i+1)*bstep) - wxCoord(i*bstep)) // integral gap to next bar - - (bstep - wbar) // space between bars - ), - -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); - } -} - -BEGIN_EVENT_TABLE(WSortView, wxWindow) - - EVT_PAINT (WSortView::OnPaint) - EVT_SIZE (WSortView::OnSize) - -END_EVENT_TABLE() - -// **************************************************************************** -// *** Threading - -SortAlgoThread::SortAlgoThread(WMain* wmain, WSortView& sortview, size_t algo) - : wxThread(wxTHREAD_JOINABLE), - m_wmain(wmain), - m_sortview(sortview), - m_algo(algo) -{ -} - -void* SortAlgoThread::Entry() -{ - ASSERT(m_algo < g_algolist_size); - const AlgoEntry& ae = g_algolist[m_algo]; - - m_sortview.m_array.OnAlgoLaunch(ae); - - ae.func(m_sortview.m_array); - - m_sortview.m_array.CheckSorted(); - - wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, WMain::ID_RUN_FINISHED); - m_wmain->GetEventHandler()->AddPendingEvent(evt); - - return NULL; -} - -void SortAlgoThread::Exit() -{ - wxThread::Exit(); -} - -// **************************************************************************** diff --git a/src/WSortView.h b/src/WSortView.h index 92a57e640..e69de29bb 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -1,124 +0,0 @@ -/****************************************************************************** - * src/WSortView.h - * - * WSortView contains both the instrumentated array operators and draws the - * displayed visualization. - * - ****************************************************************************** - * Copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#ifndef WSORTVIEW_H -#define WSORTVIEW_H - -#include - -#include "SortArray.h" - -// ---------------------------------------------------------------------------- - -/// global sound processing on/off -extern bool g_sound_on; - -/// multiplying g_delay with this value yields the duration a sound is sustained -extern double g_sound_sustain; - -/// the SDL sound callback -void SoundCallback(void* udata, Uint8* stream, int len); - -/// reset internal state of sound generator -void SoundReset(); - -/// append access to start output in next sound callback -void SoundAccess(size_t i); - -// ---------------------------------------------------------------------------- - -/// global delay for one step -extern double g_delay; - -/// global flag when algorithm is running -extern bool g_algo_running; - -/// global string of running algorithm -extern wxString g_algo_name; - -class WSortView : public wxPanel, public SortDelay -{ -public: - WSortView(wxWindow *parent, int id, class WMain_wxg* wmain); - ~WSortView(); - - /// reference to WMain - class WMain* wmain; - - /// the instrumentated array to sort - SortArray m_array; - - void RepaintNow(); - - virtual void OnPaint(wxPaintEvent& pe); - virtual void OnSize(wxSizeEvent& se); - - // paint the visualization, (dcsize is passed along due to wxMSW issues) - void paint(wxDC& dc, const wxSize& dcsize); - - /// central access function called by each array access of the algorithms - virtual void OnAccess(); - - /// delay algorithm time by this amount - void DoDelay(double delay); - -protected: - - /// flag for step-wise processing (idle while true) - bool m_stepwise; - - /// semaphore for signaling steps from main thread - wxSemaphore m_step_semaphore; - -public: - - /// set stepwise processing for Step button - void SetStepwise(bool v) { m_stepwise = v; } - - /// stepwise processing for Step button - void DoStepwise(); - -public: - DECLARE_EVENT_TABLE(); -}; - -// ---------------------------------------------------------------------------- - -class SortAlgoThread : public wxThread { -protected: - WMain* m_wmain; - WSortView& m_sortview; - size_t m_algo; - -public: - - SortAlgoThread(WMain* wmain, WSortView& sortview, size_t algo); - - virtual ExitCode Entry(); - - void Exit(); -}; - -// ---------------------------------------------------------------------------- - -#endif // WSORTVIEW_H From 9597ef30181b4a5f501fbd564631c2a4613ef241 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 6 Oct 2024 01:55:56 +0800 Subject: [PATCH 025/289] Add files via upload --- src/WSortView.cpp | 282 ++++++++++++++++++++++++++++++++++++++++++++++ src/WSortView.h | 125 ++++++++++++++++++++ 2 files changed, 407 insertions(+) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index e69de29bb..b11542ba8 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -0,0 +1,282 @@ +/****************************************************************************** + * src/WSortView.cpp + * + * WSortView contains both the instrumentated array operators and draws the + * displayed visualization. + * + ****************************************************************************** + * Copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#include "WSortView.h" +#include "SortAlgo.h" +#include "WMain.h" + +#include + +// **************************************************************************** +// *** WSortView + +double g_delay = 0; + +bool g_algo_running = false; + +wxString g_algo_name; + +WSortView::WSortView(wxWindow *parent, int id, class WMain_wxg* wmain) + : wxPanel(parent, id), + wmain(reinterpret_cast(wmain)) +{ + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + + m_stepwise = false; + m_array.SetSortDelay(this); +} + +WSortView::~WSortView() +{ +} + +#if MSW_PERFORMANCECOUNTER + +void mswMicroSleep(int microseconds) +{ + static LARGE_INTEGER s_liFreq = { 0, 0 }; + + if (s_liFreq.QuadPart == 0) + QueryPerformanceFrequency(&s_liFreq); + + LARGE_INTEGER liStart, liGoal; + QueryPerformanceCounter(&liStart); + + liGoal.QuadPart = liStart.QuadPart; + liGoal.QuadPart += (s_liFreq.QuadPart * microseconds) / 1000000; + LARGE_INTEGER liAct; + do + { + QueryPerformanceCounter(&liAct); + if (liStart.QuadPart > liAct.QuadPart) break; + } while(liAct.QuadPart < liGoal.QuadPart); +} + +#endif // MSW_PERFORMANCECOUNTER + +void WSortView::DoDelay(double delay) +{ + // must be called by the algorithm thread + ASSERT(wmain->m_thread); + ASSERT(wxThread::GetCurrentId() == wmain->m_thread->GetId()); + + if (wmain->m_thread_terminate) + wmain->m_thread->Exit(); + + // idle until main thread signals a condition + while (m_stepwise) + { + wxSemaError se = m_step_semaphore.WaitTimeout(200); + if (se == wxSEMA_NO_ERROR) + break; + // else timeout, recheck m_stepwise and loop + wmain->m_thread->TestDestroy(); + wmain->m_thread->Yield(); + } + + wmain->m_thread->TestDestroy(); + +#if __WXGTK__ + wxMicroSleep(delay * 1000.0); +#elif MSW_PERFORMANCECOUNTER + mswMicroSleep(delay * 1000.0); +#else + // wxMSW does not have a high resolution timer, maybe others do? + wxMilliSleep(delay); +#endif +} + +void WSortView::OnAccess() +{ + DoDelay(g_delay); +} + +void WSortView::DoStepwise() +{ + wxSemaError se = m_step_semaphore.Post(); + if (se != wxSEMA_NO_ERROR) { + wxLogError(_T("Error posting to semaphore: %d"), se); + } +} + +void WSortView::RepaintNow() +{ + if (!IsShownOnScreen()) return; + + wxClientDC dc(this); + wxBufferedDC bdc(&dc, GetSize(), wxBUFFER_CLIENT_AREA); + paint(bdc, GetSize()); +} + +void WSortView::OnPaint(wxPaintEvent&) +{ + wxAutoBufferedPaintDC dc(this); + // on wxMSW, wxAutoBufferedPaintDC holds a bitmap. The bitmaps size = + // wxDC's size may not match the window size, thus we pass the window size + // explicitly. + paint(dc, GetSize()); +} + +void WSortView::OnSize(wxSizeEvent&) +{ + // full redraw on resize + Refresh(false); +} + +void WSortView::paint(wxDC& dc, const wxSize& dcsize) +{ + dc.SetBackground(*wxBLACK_BRUSH); + dc.Clear(); + + if (m_array.size() == 0) return; + + size_t size = m_array.size(); + + size_t fwidth = dcsize.GetWidth(); + size_t fheight = dcsize.GetHeight(); + + size_t width = fwidth - 20; + size_t height = fheight - 20; + + dc.SetDeviceOrigin(10,10); + + // *** draw array element bars + + // draw | | | | bars: each bar is width w, separation is w/2 + // thus n bars need n * w + (n-1) * w/2 width + + // 1st variant: space is 0.5 of bar size + //double wbar = width / (size + (size-1) / 2.0); + //double bstep = 1.5 * wbar; + + // 2nd variant: one pixel between bars + double wbar = (width - (size-1)) / (double)size; + if (width <= (size-1)) wbar = 0.0; + + double bstep = wbar + 1.0; + + // special case for bstep = 2 pixel -> draw 2 pixel bars instead of 1px + // bar/1px gaps. + if ( fabs(wbar - 1.0) < 0.1 && fabs(bstep - 2.0) < 0.1 ) wbar = 2, bstep = 2; + + static const wxPen pens[] = { + *wxWHITE_PEN, + *wxRED_PEN, + *wxGREEN_PEN, + *wxCYAN_PEN, + wxPen(wxColour(255,255,0)), // 4 yellow + wxPen(wxColour(255,0,255)), // 5 magenta + wxPen(wxColour(255,192,128)), // 6 orange + wxPen(wxColour(255,128,192)), // 7 pink + wxPen(wxColour(128,192,255)), // 8 darker cyan + wxPen(wxColour(192,255,128)), // 9 darker green + wxPen(wxColour(192,128,255)), // 10 purple + wxPen(wxColour(128,255,192)), // 11 light green + wxPen(wxColour(128,128,255)), // 12 blue + wxPen(wxColour(192,128,192)), // 13 dark purple + wxPen(wxColour(128,192,192)), // 14 dark cyan + wxPen(wxColour(192,192,128)), // 15 dark yellow + wxPen(wxColour(0,128,255)), // 16 blue/cyan mix + }; + + static const wxBrush brushes[] = { + *wxWHITE_BRUSH, + *wxRED_BRUSH, + *wxGREEN_BRUSH, + *wxCYAN_BRUSH, + wxBrush(wxColour(255,255,0)), // 4 yellow + wxBrush(wxColour(255,0,255)), // 5 magenta + wxBrush(wxColour(255,192,128)), // 6 orange + wxBrush(wxColour(255,128,192)), // 7 pink + wxBrush(wxColour(128,192,255)), // 8 darker cyan + wxBrush(wxColour(192,255,128)), // 9 darker green + wxBrush(wxColour(192,128,255)), // 10 purple + wxBrush(wxColour(128,255,192)), // 11 light green + wxBrush(wxColour(128,128,255)), // 12 blue + wxBrush(wxColour(192,128,192)), // 13 dark purple + wxBrush(wxColour(128,192,192)), // 14 dark cyan + wxBrush(wxColour(192,192,128)), // 15 dark yellow + wxBrush(wxColour(0,128,255)), // 16 blue/cyan mix + }; + + wxMutexLocker lock(m_array.m_mutex); + ASSERT(lock.IsOk()); + + for (size_t i = 0; i < size; ++i) + { + int clr = m_array.GetIndexColor(i); + + ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); + dc.SetPen( pens[clr] ); + dc.SetBrush( brushes[clr] ); + + dc.DrawRectangle(i*bstep, height, + wxMax(1, // draw at least 1 pixel + (wxCoord((i+1)*bstep) - wxCoord(i*bstep)) // integral gap to next bar + - (bstep - wbar) // space between bars + ), + -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); + } +} + +BEGIN_EVENT_TABLE(WSortView, wxWindow) + + EVT_PAINT (WSortView::OnPaint) + EVT_SIZE (WSortView::OnSize) + +END_EVENT_TABLE() + +// **************************************************************************** +// *** Threading + +SortAlgoThread::SortAlgoThread(WMain* wmain, class WSortView& sortview, size_t algo) + : wxThread(wxTHREAD_JOINABLE), + m_wmain(wmain), + m_sortview(sortview), + m_algo(algo) +{ +} + +void* SortAlgoThread::Entry() +{ + ASSERT(m_algo < g_algolist_size); + const AlgoEntry& ae = g_algolist[m_algo]; + + m_sortview.m_array.OnAlgoLaunch(ae); + + ae.func(m_sortview.m_array); + + m_sortview.m_array.CheckSorted(); + + wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, WMain::ID_RUN_FINISHED); + m_wmain->GetEventHandler()->AddPendingEvent(evt); + + return NULL; +} + +void SortAlgoThread::Exit() +{ + wxThread::Exit(); +} + +// **************************************************************************** diff --git a/src/WSortView.h b/src/WSortView.h index e69de29bb..da5f0f064 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -0,0 +1,125 @@ +/****************************************************************************** + * src/WSortView.h + * + * WSortView contains both the instrumentated array operators and draws the + * displayed visualization. + * + ****************************************************************************** + * Copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#ifndef WSORTVIEW_H +#define WSORTVIEW_H + +#include + +#include "SortArray.h" + +// ---------------------------------------------------------------------------- + +/// global sound processing on/off +extern bool g_sound_on; + +/// multiplying g_delay with this value yields the duration a sound is sustained +extern double g_sound_sustain; + +/// the SDL sound callback +void SoundCallback(void *udata, unsigned char *stream, int len); + +/// reset internal state of sound generator +void SoundReset(); + +/// append access to start output in next sound callback +void SoundAccess(size_t i); + +// ---------------------------------------------------------------------------- + +/// global delay for one step +extern double g_delay; + +/// global flag when algorithm is running +extern bool g_algo_running; + +/// global string of running algorithm +extern wxString g_algo_name; + +class WSortView : public wxPanel, public SortDelay +{ +public: + WSortView(wxWindow *parent, int id, class WMain_wxg* wmain); + ~WSortView(); + + /// reference to WMain + class WMain* wmain; + + /// the instrumentated array to sort + SortArray m_array; + + void RepaintNow(); + + virtual void OnPaint(wxPaintEvent& pe); + virtual void OnSize(wxSizeEvent& se); + + // paint the visualization, (dcsize is passed along due to wxMSW issues) + void paint(wxDC& dc, const wxSize& dcsize); + + /// central access function called by each array access of the algorithms + virtual void OnAccess(); + + /// delay algorithm time by this amount + void DoDelay(double delay); + +protected: + + /// flag for step-wise processing (idle while true) + bool m_stepwise; + + /// semaphore for signaling steps from main thread + wxSemaphore m_step_semaphore; + +public: + + /// set stepwise processing for Step button + void SetStepwise(bool v) { m_stepwise = v; } + + /// stepwise processing for Step button + void DoStepwise(); + +public: + DECLARE_EVENT_TABLE(); +}; + +// ---------------------------------------------------------------------------- + +class SortAlgoThread : public wxThread { +protected: + class WMain* m_wmain; + class WSortView& m_sortview; + + size_t m_algo; + +public: + + SortAlgoThread(class WMain* wmain, class WSortView& sortview, size_t algo); + + virtual ExitCode Entry(); + + void Exit(); +}; + +// ---------------------------------------------------------------------------- + +#endif // WSORTVIEW_H From 9c30c9cac7b4826b6bb85325c293e77d5e0ccfac Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 6 Oct 2024 11:34:35 +0800 Subject: [PATCH 026/289] Dual Cocktail Shaker Sort is now more adaptive --- src/SortAlgo.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 794fb11f9..22220839d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -810,25 +810,24 @@ void CocktailShakerSort(SortArray& A) void DualCocktailShakerSort(SortArray& A) { size_t lo = 0, hi = A.size() - 1; - bool swapped = true; - while (swapped) + while (lo < hi) { - swapped = false; + size_t lo_mov = 0, hi_mov = 0; for (size_t i = lo, j = hi; i < hi; ++i, --j) { if (A[i] > A[i + 1]) { A.swap(i + 1, i); - swapped = true; + lo_mov = i; } if (A[j] < A[j - 1]) { A.swap(j - 1, j); - swapped = true; + hi_mov = j; } } - ++lo; - --hi; + lo = hi_mov; + hi = lo_mov; } } From 154610f9e641bc48ed62f150ff58786325c09016 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 6 Oct 2024 13:57:17 +0800 Subject: [PATCH 027/289] Fixed Dual Cocktail Sort The new adaptive variant now uses the mirrored tail comparison strategy, which I have proven to be more robust. This change ensures that Dual Cocktail Shaker Sort will never fail to sort in the middle --- src/SortAlgo.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 22220839d..b32ed494e 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -813,16 +813,16 @@ void DualCocktailShakerSort(SortArray& A) while (lo < hi) { size_t lo_mov = 0, hi_mov = 0; - for (size_t i = lo, j = hi; i < hi; ++i, --j) + for (size_t i = lo + 1, j = hi - 1; i <= hi; ++i, --j) { - if (A[i] > A[i + 1]) + if (A[i - 1] > A[i]) { - A.swap(i + 1, i); + A.swap(i - 1, i); lo_mov = i; } - if (A[j] < A[j - 1]) + if (A[j + 1] < A[j]) { - A.swap(j - 1, j); + A.swap(j + 1, j); hi_mov = j; } } From 791fceb788cd5756c4061aa66f6d9810b8023d2d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 03:43:59 +0800 Subject: [PATCH 028/289] Fixed warning on CheckSorted() Should slightly reduce warnings, 50% sorted (head) is also introduced --- src/SortArray.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 395118d18..b59ea884a 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -119,6 +119,7 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Pipe Organ")); list.Add(_("Mirrored Organ")); list.Add(_("Wave")); + list.Add(_("50% Sorted (Head)")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -271,6 +272,19 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val + 1); } } + else if (schema == 13) // 50% Sorted, Head + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { + ++it; + } + } + std::shuffle(m_array.begin(), it, g); + } else // fallback { return FillData(0, arraysize); @@ -292,27 +306,21 @@ bool SortArray::CheckSorted() unmark_all(); // needed because iterator instrumentated algorithms may have changed the array RecalcInversions(); - - ArrayItem prev = get_nocount(0); mark(0); - bool is_sorted = true; for (size_t i = 1; i < size(); ++i) { - ArrayItem key = get_nocount(i); g_compare_count--; // dont count the following comparison - if (!(prev <= key)) { + if (get_nocount(i - 1) > get_nocount(i)) { wxLogError(_T("Result of sorting algorithm is incorrect!")); is_sorted = false; break; } mark(i); - prev = key; } unmark_all(); - return (m_is_sorted = is_sorted); } From ec2ac78ac16af6ba2a1ac31b875dce41588ffb6a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 03:51:33 +0800 Subject: [PATCH 029/289] Fixed 1 warning --- src/WSortView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.h b/src/WSortView.h index da5f0f064..020606754 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -37,7 +37,7 @@ extern bool g_sound_on; extern double g_sound_sustain; /// the SDL sound callback -void SoundCallback(void *udata, unsigned char *stream, int len); +void SoundCallback(void *udata, Uint8* stream, int len); /// reset internal state of sound generator void SoundReset(); From 16f20f0373f18092697f17b147d5e95b9811b127 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 04:13:45 +0800 Subject: [PATCH 030/289] Update WSortView.h Reverted --- src/WSortView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.h b/src/WSortView.h index 020606754..da5f0f064 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -37,7 +37,7 @@ extern bool g_sound_on; extern double g_sound_sustain; /// the SDL sound callback -void SoundCallback(void *udata, Uint8* stream, int len); +void SoundCallback(void *udata, unsigned char *stream, int len); /// reset internal state of sound generator void SoundReset(); From 4d5ec5d4b987aacc263bd92e7a65303e5bed8e88 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 04:42:50 +0800 Subject: [PATCH 031/289] Fixed "implicit operator=" warning --- src/SortArray.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/SortArray.h b/src/SortArray.h index 7a1874d24..861451ef3 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -78,7 +78,14 @@ class ArrayItem const value_type& get_direct() const { return value; } - // *** comparisons + ArrayItem& operator= (const ArrayItem& other) + { + if (this != &other) + { + this->value = other.value; + } + return *this; + } bool operator== (const ArrayItem& v) const { OnComparison(*this,v); return (value == v.value); } From 96d46c4def77539647dd9e6685c0dc4017bbca09 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 05:23:10 +0800 Subject: [PATCH 032/289] Improved MyIterator class The MyIterator class does not use std::iterator anymore, which has been deprecated, further reducing warning while retaining the same functionality (hopefully) --- src/SortAlgo.h | 64 +++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 7556e1abb..72d272652 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -113,80 +113,77 @@ void CycleSort(class SortArray& a); // iterator based on http://zotu.blogspot.de/2010/01/creating-random-access-iterator.html -class MyIterator : public std::iterator -{ +class MyIterator { protected: - SortArray* m_array; - size_t m_pos; + SortArray* m_array; + size_t m_pos; public: - typedef std::iterator base_type; - - typedef std::random_access_iterator_tag iterator_category; + using iterator_category = std::random_access_iterator_tag; + using value_type = ArrayItem; + using difference_type = std::ptrdiff_t; + using reference = ArrayItem&; + using pointer = ArrayItem*; - typedef base_type::value_type value_type; - typedef base_type::difference_type difference_type; - typedef base_type::reference reference; - typedef base_type::pointer pointer; - - MyIterator() : m_array(NULL), m_pos(0) {} + MyIterator() : m_array(nullptr), m_pos(0) {} MyIterator(SortArray* A, size_t p) : m_array(A), m_pos(p) {} MyIterator(const MyIterator& r) : m_array(r.m_array), m_pos(r.m_pos) {} - MyIterator& operator=(const MyIterator& r) - { m_array = r.m_array, m_pos = r.m_pos; return *this; } + MyIterator& operator=(const MyIterator& r) + { m_array = r.m_array; m_pos = r.m_pos; return *this; } - MyIterator& operator++() + MyIterator& operator++() { ++m_pos; return *this; } - MyIterator& operator--() + MyIterator& operator--() { --m_pos; return *this; } - MyIterator operator++(int) + MyIterator operator++(int) { return MyIterator(m_array, m_pos++); } - MyIterator operator--(int) + MyIterator operator--(int) { return MyIterator(m_array, m_pos--); } - MyIterator operator+(const difference_type& n) const + MyIterator operator+(difference_type n) const { return MyIterator(m_array, m_pos + n); } - MyIterator& operator+=(const difference_type& n) + MyIterator& operator+=(difference_type n) { m_pos += n; return *this; } - MyIterator operator-(const difference_type& n) const + MyIterator operator-(difference_type n) const { return MyIterator(m_array, m_pos - n); } - MyIterator& operator-=(const difference_type& n) + MyIterator& operator-=(difference_type n) { m_pos -= n; return *this; } - reference operator*() const + reference operator*() const { return m_array->get_mutable(m_pos); } - pointer operator->() const + pointer operator->() const { return &(m_array->get_mutable(m_pos)); } - reference operator[](const difference_type& n) const + reference operator[](difference_type n) const { return m_array->get_mutable(m_pos + n); } - bool operator==(const MyIterator& r) + // Comparison operators + bool operator==(const MyIterator& r) const { return (m_array == r.m_array) && (m_pos == r.m_pos); } - bool operator!=(const MyIterator& r) + bool operator!=(const MyIterator& r) const { return (m_array != r.m_array) || (m_pos != r.m_pos); } - bool operator<(const MyIterator& r) - { return (m_array == r.m_array ? (m_pos < r.m_pos) : (m_array < r.m_array)); } + bool operator<(const MyIterator& r) const + { return (m_array == r.m_array) ? (m_pos < r.m_pos) : (m_array < r.m_array); } - bool operator>(const MyIterator& r) + bool operator>(const MyIterator& r) const { return (m_array == r.m_array ? (m_pos > r.m_pos) : (m_array > r.m_array)); } - bool operator<=(const MyIterator& r) + bool operator<=(const MyIterator& r) const { return (m_array == r.m_array ? (m_pos <= r.m_pos) : (m_array <= r.m_array)); } - bool operator>=(const MyIterator& r) + bool operator>=(const MyIterator& r) const { return (m_array == r.m_array ? (m_pos >= r.m_pos) : (m_array >= r.m_array)); } difference_type operator+(const MyIterator& r2) const @@ -196,5 +193,4 @@ class MyIterator : public std::iterator Date: Mon, 7 Oct 2024 05:29:01 +0800 Subject: [PATCH 033/289] Minor corrections on MyIterator --- src/SortAlgo.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 72d272652..8bef802f1 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -167,7 +167,6 @@ class MyIterator { reference operator[](difference_type n) const { return m_array->get_mutable(m_pos + n); } - // Comparison operators bool operator==(const MyIterator& r) const { return (m_array == r.m_array) && (m_pos == r.m_pos); } @@ -175,7 +174,7 @@ class MyIterator { { return (m_array != r.m_array) || (m_pos != r.m_pos); } bool operator<(const MyIterator& r) const - { return (m_array == r.m_array) ? (m_pos < r.m_pos) : (m_array < r.m_array); } + { return (m_array == r.m_array ? (m_pos < r.m_pos) : (m_array < r.m_array)); } bool operator>(const MyIterator& r) const { return (m_array == r.m_array ? (m_pos > r.m_pos) : (m_array > r.m_array)); } From 82511181fef0733717cec554c927dd728a575814 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 14:52:11 +0800 Subject: [PATCH 034/289] Update to higher version of Automake Inspired by @chromi --- Makefile.in | 17 ++-- aclocal.m4 | 288 ++++++++++++++++++++++++++-------------------------- configure | 150 +++++++++++++++------------ 3 files changed, 237 insertions(+), 218 deletions(-) diff --git a/Makefile.in b/Makefile.in index c3feba08c..37440b027 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -154,16 +154,13 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/acscripts/compile \ $(top_srcdir)/acscripts/config.guess \ $(top_srcdir)/acscripts/config.sub \ $(top_srcdir)/acscripts/install-sh \ - $(top_srcdir)/acscripts/missing AUTHORS COPYING \ + $(top_srcdir)/acscripts/missing AUTHORS COPYING README.md \ acscripts/compile acscripts/config.guess acscripts/config.sub \ acscripts/depcomp acscripts/install-sh acscripts/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -204,6 +201,8 @@ am__relativize = \ DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' @@ -219,6 +218,8 @@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ @@ -228,6 +229,7 @@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -476,7 +478,6 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am @@ -623,7 +624,7 @@ distcheck: dist $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ diff --git a/aclocal.m4 b/aclocal.m4 index b385b22aa..0ec3a7819 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.2 -*- Autoconf -*- +# generated automatically by aclocal 1.16.5 -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,8 +20,8 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# serial 11 (pkg-config-0.29.1) +# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson @@ -63,13 +63,13 @@ dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], -[m4_define([PKG_MACROS_VERSION], [0.29.1]) +[m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ -dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) -dnl ---------------------------------- +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to @@ -77,6 +77,12 @@ dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. +dnl +dnl If pkg-config is not found or older than specified, it will result +dnl in an empty PKG_CONFIG variable. To avoid widespread issues with +dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting. +dnl You can specify [PKG_CONFIG=false] as an action instead, which would +dnl result in pkg-config tests failing, but no bogus error messages. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) @@ -97,6 +103,9 @@ if test -n "$PKG_CONFIG"; then AC_MSG_RESULT([no]) PKG_CONFIG="" fi +fi +if test -z "$PKG_CONFIG"; then + m4_default([$2], [AC_MSG_ERROR([pkg-config not found])]) fi[]dnl ])dnl PKG_PROG_PKG_CONFIG @@ -108,7 +117,7 @@ dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -dnl only at the first occurence in configure.ac, so if the first place +dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], @@ -164,7 +173,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no -AC_MSG_CHECKING([for $1]) +AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) @@ -174,17 +183,17 @@ and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - m4_default([$4], [AC_MSG_ERROR( + m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS @@ -195,8 +204,8 @@ installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. @@ -206,10 +215,10 @@ _PKG_TEXT To get pkg-config, see .])[]dnl ]) else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) - $3 + $3 fi[]dnl ])dnl PKG_CHECK_MODULES @@ -373,14 +382,17 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], # # Changelog: # * also look for SDL2.framework under Mac OS X +# * removed HP/UX 9 support. +# * updated for newer autoconf. +# * (v3) use $PKG_CONFIG for pkg-config cross-compiling support -# serial 1 +# serial 3 dnl AM_PATH_SDL2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS dnl AC_DEFUN([AM_PATH_SDL2], -[dnl +[dnl dnl Get the cflags and libraries from the sdl2-config script dnl AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)], @@ -418,7 +430,7 @@ AC_ARG_VAR(SDL2_FRAMEWORK, [Path to SDL2.framework]) if test "x$sdl_pc" = xyes ; then no_sdl="" - SDL2_CONFIG="pkg-config sdl2" + SDL2_CONFIG="$PKG_CONFIG sdl2" else as_save_PATH="$PATH" if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then @@ -434,8 +446,8 @@ AC_ARG_VAR(SDL2_FRAMEWORK, [Path to SDL2.framework]) sdl_framework=$SDL2_FRAMEWORK else for d in / ~/ /System/; do - if test -d "$dLibrary/Frameworks/SDL2.framework"; then - sdl_framework="$dLibrary/Frameworks/SDL2.framework" + if test -d "${d}Library/Frameworks/SDL2.framework"; then + sdl_framework="${d}Library/Frameworks/SDL2.framework" fi done fi @@ -475,41 +487,19 @@ dnl Now check if the installed SDL is sufficiently new. (Also sanity dnl checks the results of sdl2-config to some extent dnl rm -f conf.sdltest - AC_TRY_RUN([ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include -#include #include "SDL.h" -char* -my_strdup (char *str) -{ - char *new_str; - - if (str) - { - new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char)); - strcpy (new_str, str); - } - else - new_str = NULL; - - return new_str; -} - int main (int argc, char *argv[]) { int major, minor, micro; - char *tmp_version; + FILE *fp = fopen("conf.sdltest", "w"); - /* This hangs on some systems (?) - system ("touch conf.sdltest"); - */ - { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); } + if (fp) fclose(fp); - /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = my_strdup("$min_sdl_version"); - if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + if (sscanf("$min_sdl_version", "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_sdl_version"); exit(1); } @@ -532,7 +522,7 @@ int main (int argc, char *argv[]) } } -],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) +]])], [], [no_sdl=yes], [echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" CXXFLAGS="$ac_save_CXXFLAGS" LIBS="$ac_save_LIBS" @@ -563,7 +553,7 @@ int main (int argc, char *argv[]) CFLAGS="$CFLAGS $SDL_CFLAGS" CXXFLAGS="$CXXFLAGS $SDL_CFLAGS" LIBS="$LIBS $SDL_LIBS" - AC_TRY_LINK([ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include "SDL.h" @@ -571,7 +561,7 @@ int main(int argc, char *argv[]) { return 0; } #undef main #define main K_and_R_C_main -], [ return 0; ], +]], [[ return 0; ]])], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding SDL or finding the wrong" echo "*** version of SDL. If it is not finding SDL, you'll need to set your" @@ -606,6 +596,9 @@ dnl Bob McCown (Mac-testing) dnl Creation date: 24/11/2001 dnl --------------------------------------------------------------------------- +dnl Increment this when changing this file. +# serial 42 + dnl =========================================================================== dnl Table of Contents of this macro file: dnl ------------------------------------- @@ -665,7 +658,7 @@ dnl If you want to support standard --enable-debug/unicode/shared options, you dnl may do the following: dnl dnl ... -dnl AC_CANONICAL_SYSTEM +dnl AC_CANONICAL_TARGET dnl dnl # define configure options dnl WX_CONFIG_OPTIONS @@ -743,7 +736,8 @@ AC_DEFUN([_WX_PRIVATE_CHECK_VERSION], dnl --------------------------------------------------------------------------- dnl WX_CONFIG_CHECK(VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND -dnl [, WX-LIBS [, ADDITIONAL-WX-CONFIG-FLAGS]]]]) +dnl [, WX-LIBS [, ADDITIONAL-WX-CONFIG-FLAGS +dnl [, WX-OPTIONAL-LIBS]]]]]) dnl dnl Test for wxWidgets, and define WX_C*FLAGS, WX_LIBS and WX_LIBS_STATIC dnl (the latter is for static linking against wxWidgets). Set WX_CONFIG_NAME @@ -760,6 +754,10 @@ dnl Optional ADDITIONAL-WX-CONFIG-FLAGS argument is appended to wx-config dnl invocation command in present. It can be used to fine-tune lookup of dnl best wxWidgets build available. dnl +dnl Optional WX-OPTIONAL-LIBS argument contains comma- or space-separated list +dnl of wxWidgets libraries to link against if they are available. +dnl WX-OPTIONAL-LIBS is supported on version 2.9.0 and later. +dnl dnl Example use: dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1], [wxWin=0], [html,core,net] dnl [--unicode --debug]) @@ -811,8 +809,8 @@ AC_DEFUN([WX_CONFIG_CHECK], AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version ($5)]) fi - dnl don't add the libraries ($4) to this variable as this would result in - dnl an error when it's used with --version below + dnl don't add the libraries (4th argument) to this variable as this would + dnl result in an error when it's used with --version below WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args $5" WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null` @@ -836,14 +834,20 @@ AC_DEFUN([WX_CONFIG_CHECK], if test -n "$wx_ver_ok"; then AC_MSG_RESULT(yes (version $WX_VERSION)) - WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $4` + + wx_optional_libs="" + _WX_PRIVATE_CHECK_VERSION(2,9,0) + if test -n "$wx_ver_ok" -a -n "$6"; then + wx_optional_libs="--optional-libs $6" + fi + WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $4 $wx_optional_libs` dnl is this even still appropriate? --static is a real option now dnl and WX_CONFIG_WITH_ARGS is likely to contain it if that is dnl what the user actually wants, making this redundant at best. dnl For now keep it in case anyone actually used it in the past. AC_MSG_CHECKING([for wxWidgets static library]) - WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $4 2>/dev/null` + WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $4 $wx_optional_libs 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then AC_MSG_RESULT(no) else @@ -1106,7 +1110,7 @@ dnl $5 = additional action to do in case option is given with "yes" value dnl --------------------------------------------------------------------------- AC_DEFUN([WX_ARG_ENABLE_YESNOAUTO], [AC_ARG_ENABLE($1, - AC_HELP_STRING([--enable-$1], [$3 (default is $4)]), + AS_HELP_STRING([--enable-$1],[$3 (default is $4)]), [], [enableval="$4"]) dnl Show a message to the user about this option @@ -1120,7 +1124,7 @@ AC_DEFUN([WX_ARG_ENABLE_YESNOAUTO], $2=0 elif test "$enableval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) - $2="auto" + $2="" else AC_MSG_ERROR([ Unrecognized option value (allowed values: yes, no, auto) @@ -1130,7 +1134,7 @@ AC_DEFUN([WX_ARG_ENABLE_YESNOAUTO], AC_DEFUN([WX_ARG_WITH_YESNOAUTO], [AC_ARG_WITH($1, - AC_HELP_STRING([--with-$1], [$3 (default is $4)]), + AS_HELP_STRING([--with-$1],[$3 (default is $4)]), [], [withval="$4"]) dnl Show a message to the user about this option @@ -1146,7 +1150,7 @@ AC_DEFUN([WX_ARG_WITH_YESNOAUTO], $2=0 elif test "$withval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) - $2="auto" + $2="" else AC_MSG_ERROR([ Unrecognized option value (allowed values: yes, auto) @@ -1190,25 +1194,24 @@ AC_DEFUN([WX_STANDARD_OPTIONS], ifelse(index([$1], [toolkit]), [-1],, [ AC_ARG_WITH([toolkit], - AC_HELP_STRING([--with-toolkit], - [Build against a specific wxWidgets toolkit (default is auto)]), + AS_HELP_STRING([--with-toolkit],[Build against a specific wxWidgets toolkit (default is auto)]), [], [withval="auto"]) dnl Show a message to the user about this option AC_MSG_CHECKING([for the --with-toolkit option]) if test "$withval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) - TOOLKIT="auto" + TOOLKIT="" else TOOLKIT="$withval" dnl PORT must be one of the allowed values - if test "$TOOLKIT" != "gtk1" -a "$TOOLKIT" != "gtk2" -a \ + if test "$TOOLKIT" != "gtk1" -a "$TOOLKIT" != "gtk2" -a "$TOOLKIT" != "gtk3" -a \ "$TOOLKIT" != "msw" -a "$TOOLKIT" != "motif" -a \ "$TOOLKIT" != "osx_carbon" -a "$TOOLKIT" != "osx_cocoa" -a \ - "$TOOLKIT" != "dfb" -a "$TOOLKIT" != "x11"; then + "$TOOLKIT" != "dfb" -a "$TOOLKIT" != "x11" -a "$TOOLKIT" != "base"; then AC_MSG_ERROR([ - Unrecognized option value (allowed values: auto, gtk1, gtk2, msw, motif, osx_carbon, osx_cocoa, dfb, x11) + Unrecognized option value (allowed values: auto, gtk1, gtk2, gtk3, msw, motif, osx_carbon, osx_cocoa, dfb, x11, base) ]) fi @@ -1264,15 +1267,14 @@ AC_DEFUN([WX_STANDARD_OPTIONS], ifelse(index([$1], [wxversion]), [-1],, [ AC_ARG_WITH([wxversion], - AC_HELP_STRING([--with-wxversion], - [Build against a specific version of wxWidgets (default is auto)]), + AS_HELP_STRING([--with-wxversion],[Build against a specific version of wxWidgets (default is auto)]), [], [withval="auto"]) dnl Show a message to the user about this option AC_MSG_CHECKING([for the --with-wxversion option]) if test "$withval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) - WX_RELEASE="auto" + WX_RELEASE="" else wx_requested_major_version=`echo $withval | \ @@ -1307,7 +1309,7 @@ dnl --------------------------------------------------------------------------- dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS dnl dnl Sets the WXCONFIG_FLAGS string using the SHARED,DEBUG,UNICODE variable values -dnl which are different from "auto". +dnl which were specified. dnl Thus this macro needs to be called only once all options have been set. dnl --------------------------------------------------------------------------- AC_DEFUN([WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS], @@ -1331,11 +1333,11 @@ AC_DEFUN([WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS], WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=no " fi - if test "$TOOLKIT" != "auto" ; then + if test -n "$TOOLKIT" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--toolkit=$TOOLKIT " fi - if test "$WX_RELEASE" != "auto" ; then + if test -n "$WX_RELEASE" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--version=$WX_RELEASE " fi @@ -1349,16 +1351,16 @@ AC_DEFUN([WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS], dnl --------------------------------------------------------------------------- -dnl _WX_SELECTEDCONFIG_CHECKFOR([RESULTVAR], [STRING], [MSG] -dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl _WX_SELECTEDCONFIG_CHECKFOR([RESULTVAR], [STRING], [MSG]) dnl -dnl Outputs the given MSG. Then searches the given STRING in the wxWidgets -dnl additional CPP flags and put the result of the search in WX_$RESULTVAR -dnl also adding the "yes" or "no" message result to MSG. +dnl Sets WX_$RESULTVAR to the value of $RESULTVAR if it's defined. Otherwise, +dnl auto-detect the value by checking for the presence of STRING in +dnl $WX_SELECTEDCONFIG (which is supposed to be set by caller) and set +dnl WX_$RESULTVAR to either 0 or 1, also outputting "yes" or "no" after MSG. dnl --------------------------------------------------------------------------- AC_DEFUN([_WX_SELECTEDCONFIG_CHECKFOR], [ - if test "$$1" = "auto" ; then + if test -z "$$1" ; then dnl The user does not have particular preferences for this option; dnl so we will detect the wxWidgets relative build setting and use it @@ -1373,11 +1375,9 @@ AC_DEFUN([_WX_SELECTEDCONFIG_CHECKFOR], if test "$WX_$1" != "0"; then WX_$1=1 AC_MSG_RESULT([yes]) - ifelse([$4], , :, [$4]) else WX_$1=0 AC_MSG_RESULT([no]) - ifelse([$5], , :, [$5]) fi else @@ -1424,19 +1424,16 @@ AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], echo "[[dbg]] WX_SELECTEDCONFIG: $WX_SELECTEDCONFIG" fi - dnl we could test directly for WX_SHARED with a line like: dnl _WX_SELECTEDCONFIG_CHECKFOR([SHARED], [shared], dnl [if wxWidgets was built in SHARED mode]) dnl but wx-config --selected-config DOES NOT outputs the 'shared' dnl word when wx was built in shared mode; it rather outputs the dnl 'static' word when built in static mode. - if test $WX_SHARED = "1"; then + if test "$WX_SHARED" = "1"; then STATIC=0 - elif test $WX_SHARED = "0"; then + elif test "$WX_SHARED" = "0"; then STATIC=1 - elif test $WX_SHARED = "auto"; then - STATIC="auto" fi dnl Now set the WX_UNICODE, WX_DEBUG, WX_STATIC variables @@ -1459,7 +1456,7 @@ AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], AC_SUBST(WX_SHARED) dnl detect the WX_PORT to use - if test "$TOOLKIT" = "auto" ; then + if test -z "$TOOLKIT" ; then dnl The user does not have particular preferences for this option; dnl so we will detect the wxWidgets relative build setting and use it @@ -1467,22 +1464,26 @@ AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], WX_GTKPORT1=$(expr "$WX_SELECTEDCONFIG" : ".*gtk1.*") WX_GTKPORT2=$(expr "$WX_SELECTEDCONFIG" : ".*gtk2.*") + WX_GTKPORT3=$(expr "$WX_SELECTEDCONFIG" : ".*gtk3.*") WX_MSWPORT=$(expr "$WX_SELECTEDCONFIG" : ".*msw.*") WX_MOTIFPORT=$(expr "$WX_SELECTEDCONFIG" : ".*motif.*") WX_OSXCOCOAPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_cocoa.*") WX_OSXCARBONPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_carbon.*") WX_X11PORT=$(expr "$WX_SELECTEDCONFIG" : ".*x11.*") WX_DFBPORT=$(expr "$WX_SELECTEDCONFIG" : ".*dfb.*") + WX_BASEPORT=$(expr "$WX_SELECTEDCONFIG" : ".*base.*") WX_PORT="unknown" if test "$WX_GTKPORT1" != "0"; then WX_PORT="gtk1"; fi if test "$WX_GTKPORT2" != "0"; then WX_PORT="gtk2"; fi + if test "$WX_GTKPORT3" != "0"; then WX_PORT="gtk3"; fi if test "$WX_MSWPORT" != "0"; then WX_PORT="msw"; fi if test "$WX_MOTIFPORT" != "0"; then WX_PORT="motif"; fi if test "$WX_OSXCOCOAPORT" != "0"; then WX_PORT="osx_cocoa"; fi if test "$WX_OSXCARBONPORT" != "0"; then WX_PORT="osx_carbon"; fi if test "$WX_X11PORT" != "0"; then WX_PORT="x11"; fi if test "$WX_DFBPORT" != "0"; then WX_PORT="dfb"; fi + if test "$WX_BASEPORT" != "0"; then WX_PORT="base"; fi dnl NOTE: backward-compatible check for wx2.8; in wx2.9 the mac dnl ports are called 'osx_cocoa' and 'osx_carbon' (see above) @@ -1500,14 +1501,8 @@ AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], AC_MSG_RESULT([$WX_PORT]) else - dnl Use the setting given by the user - if test -z "$TOOLKIT" ; then - WX_PORT=$TOOLKIT - else - dnl try with PORT - WX_PORT=$PORT - fi + WX_PORT=$TOOLKIT fi AC_SUBST(WX_PORT) @@ -1538,35 +1533,29 @@ AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], ]) fi - dnl now we can finally update the DEBUG,UNICODE,SHARED options - dnl to their final values if they were set to 'auto' - if test "$DEBUG" = "auto"; then - DEBUG=$WX_DEBUG - fi - if test "$UNICODE" = "auto"; then + dnl now we can finally update the options to their final values if they + dnl were not already set + if test -z "$UNICODE" ; then UNICODE=$WX_UNICODE fi - if test "$SHARED" = "auto"; then + if test -z "$SHARED" ; then SHARED=$WX_SHARED fi - if test "$TOOLKIT" = "auto"; then + if test -z "$TOOLKIT" ; then TOOLKIT=$WX_PORT fi - dnl in case the user needs a BUILD=debug/release var... - if test "$DEBUG" = "1"; then - BUILD="debug" - elif test "$DEBUG" = "0" -o "$DEBUG" = ""; then - BUILD="release" - fi - - dnl respect the DEBUG variable adding the optimize/debug flags + dnl respect the DEBUG variable adding the optimize/debug flags and also + dnl define a BUILD variable in case the user wants to use it + dnl dnl NOTE: the CXXFLAGS are merged together with the CPPFLAGS so we dnl don't need to set them, too if test "$DEBUG" = "1"; then + BUILD="debug" CXXFLAGS="$CXXFLAGS -g -O0" CFLAGS="$CFLAGS -g -O0" - else + elif test "$DEBUG" = "0"; then + BUILD="release" CXXFLAGS="$CXXFLAGS -O2" CFLAGS="$CFLAGS -O2" fi @@ -1659,7 +1648,7 @@ AC_DEFUN([AM_PATH_WXCONFIG], [ ]) AC_DEFUN([AM_PATH_WXRC], [WXRC_CHECK([$1],[$2])]) -# Copyright (C) 2002-2020 Free Software Foundation, Inc. +# Copyright (C) 2002-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1674,7 +1663,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.2], [], +m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -1690,14 +1679,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.2])dnl +[AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1749,7 +1738,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1780,7 +1769,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1971,7 +1960,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2039,7 +2028,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2067,6 +2056,10 @@ m4_defn([AC_PROG_CC]) # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl +m4_ifdef([_$0_ALREADY_INIT], + [m4_fatal([$0 expanded multiple times +]m4_defn([_$0_ALREADY_INIT]))], + [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl @@ -2103,7 +2096,7 @@ m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( - m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl @@ -2155,6 +2148,20 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi +AC_SUBST([CTAGS]) +if test -z "$ETAGS"; then + ETAGS=etags +fi +AC_SUBST([ETAGS]) +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi +AC_SUBST([CSCOPE]) + AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This @@ -2236,7 +2243,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2257,7 +2264,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2020 Free Software Foundation, Inc. +# Copyright (C) 2003-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2279,7 +2286,7 @@ AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2314,7 +2321,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2357,7 +2364,7 @@ AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2378,12 +2385,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then @@ -2396,7 +2398,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2425,7 +2427,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2472,7 +2474,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2491,7 +2493,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2572,7 +2574,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2020 Free Software Foundation, Inc. +# Copyright (C) 2009-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2632,7 +2634,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2660,7 +2662,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2020 Free Software Foundation, Inc. +# Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2679,7 +2681,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2020 Free Software Foundation, Inc. +# Copyright (C) 2004-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/configure b/configure index bfa8dbabf..abce69dd7 100755 --- a/configure +++ b/configure @@ -640,6 +640,9 @@ AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V +CSCOPE +ETAGS +CTAGS am__untar am__tar AMTAR @@ -1673,7 +1676,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { #ifndef $as_decl_name #ifdef __cplusplus @@ -2370,12 +2373,7 @@ program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then @@ -2730,6 +2728,20 @@ am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi + +if test -z "$ETAGS"; then + ETAGS=etags +fi + +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi + + # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile @@ -3182,7 +3194,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3322,7 +3334,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3386,7 +3398,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3437,7 +3449,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3478,7 +3490,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3493,7 +3505,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3509,7 +3521,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3558,9 +3570,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -3595,7 +3605,7 @@ int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, i int argc; char **argv; int -main () +main (void) { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; @@ -3653,7 +3663,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -4034,7 +4044,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -4075,7 +4085,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -4090,7 +4100,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -4106,7 +4116,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -4497,6 +4507,9 @@ $as_echo "no" >&6; } PKG_CONFIG="" fi fi +if test -z "$PKG_CONFIG"; then + as_fn_error $? "pkg-config not found" "$LINENO" 5 +fi # Check whether --with-sdl-prefix was given. @@ -4536,8 +4549,8 @@ fi if test "x$sdl_prefix$sdl_exec_prefix" = x ; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SDL" >&5 -$as_echo_n "checking for SDL... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sdl2 >= $min_sdl_version" >&5 +$as_echo_n "checking for sdl2 >= $min_sdl_version... " >&6; } if test -n "$SDL_CFLAGS"; then pkg_cv_SDL_CFLAGS="$SDL_CFLAGS" @@ -4577,7 +4590,7 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -4586,24 +4599,24 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - SDL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sdl2 >= $min_sdl_version" 2>&1` + SDL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sdl2 >= $min_sdl_version" 2>&1` else - SDL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sdl2 >= $min_sdl_version" 2>&1` + SDL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sdl2 >= $min_sdl_version" 2>&1` fi - # Put the nasty error message in config.log where it belongs - echo "$SDL_PKG_ERRORS" >&5 + # Put the nasty error message in config.log where it belongs + echo "$SDL_PKG_ERRORS" >&5 - sdl_pc=no + sdl_pc=no elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - sdl_pc=no + sdl_pc=no else - SDL_CFLAGS=$pkg_cv_SDL_CFLAGS - SDL_LIBS=$pkg_cv_SDL_LIBS + SDL_CFLAGS=$pkg_cv_SDL_CFLAGS + SDL_LIBS=$pkg_cv_SDL_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - sdl_pc=yes + sdl_pc=yes fi else sdl_pc=no @@ -4623,7 +4636,7 @@ fi if test "x$sdl_pc" = xyes ; then no_sdl="" - SDL2_CONFIG="pkg-config sdl2" + SDL2_CONFIG="$PKG_CONFIG sdl2" else as_save_PATH="$PATH" if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then @@ -4680,8 +4693,8 @@ $as_echo_n "checking for SDL2.framework... " >&6; } sdl_framework=$SDL2_FRAMEWORK else for d in / ~/ /System/; do - if test -d "$dLibrary/Frameworks/SDL2.framework"; then - sdl_framework="$dLibrary/Frameworks/SDL2.framework" + if test -d "${d}Library/Frameworks/SDL2.framework"; then + sdl_framework="${d}Library/Frameworks/SDL2.framework" fi done fi @@ -4727,38 +4740,16 @@ else #include #include -#include #include "SDL.h" -char* -my_strdup (char *str) -{ - char *new_str; - - if (str) - { - new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char)); - strcpy (new_str, str); - } - else - new_str = NULL; - - return new_str; -} - int main (int argc, char *argv[]) { int major, minor, micro; - char *tmp_version; + FILE *fp = fopen("conf.sdltest", "w"); - /* This hangs on some systems (?) - system ("touch conf.sdltest"); - */ - { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); } + if (fp) fclose(fp); - /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = my_strdup("$min_sdl_version"); - if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + if (sscanf("$min_sdl_version", "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_sdl_version"); exit(1); } @@ -4836,7 +4827,7 @@ int main(int argc, char *argv[]) #define main K_and_R_C_main int -main () +main (void) { return 0; ; @@ -5036,11 +5027,36 @@ $as_echo_n "checking for wxWidgets version >= $min_wx_version ()... " >&6; } if test -n "$wx_ver_ok"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 $as_echo "yes (version $WX_VERSION)" >&6; } - WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs adv,core,base` + + wx_optional_libs="" + + wx_ver_ok="" + if test "x$WX_VERSION" != x ; then + if test $wx_config_major_version -gt 2; then + wx_ver_ok=yes + else + if test $wx_config_major_version -eq 2; then + if test $wx_config_minor_version -gt 9; then + wx_ver_ok=yes + else + if test $wx_config_minor_version -eq 9; then + if test $wx_config_micro_version -ge 0; then + wx_ver_ok=yes + fi + fi + fi + fi + fi + fi + + if test -n "$wx_ver_ok" -a -n ""; then + wx_optional_libs="--optional-libs " + fi + WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs adv,core,base $wx_optional_libs` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 $as_echo_n "checking for wxWidgets static library... " >&6; } - WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs adv,core,base 2>/dev/null` + WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs adv,core,base $wx_optional_libs 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } From 482495e54137d1831182c316bf44528cda39b1d8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 14:54:38 +0800 Subject: [PATCH 035/289] Update to higher version of automake Inspired by @chromi --- src/Makefile.in | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 818a299ef..7580c571e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -191,8 +191,6 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no @@ -375,6 +373,7 @@ am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log @@ -412,6 +411,8 @@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ @@ -421,6 +422,7 @@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -855,7 +857,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS) test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ @@ -910,7 +912,6 @@ sorting-test.log: sorting-test$(EXEEXT) @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am From ca196ecdfbe7d18b7ef2440f325f704fc2bbed9b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 17:16:12 +0800 Subject: [PATCH 036/289] Introduced more array input types Added n% scrambled head input types --- src/SortArray.cpp | 77 ++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b59ea884a..a0a9dedad 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -110,16 +110,18 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Ascending")); list.Add(_("Descending")); list.Add(_("Near Sorted")); - list.Add(_("25% Sorted")); - list.Add(_("50% Sorted")); - list.Add(_("75% Sorted")); + list.Add(_("25% Shuffled (Tail)")); + list.Add(_("25% Shuffled (Head)")); + list.Add(_("50% Shuffled (Tail)")); + list.Add(_("50% Shuffled (Head)")); + list.Add(_("75% Shuffled (Tail)")); + list.Add(_("75% Shuffled (Head)")); list.Add(_("Shuffled Cubic")); list.Add(_("Shuffled Quintic")); list.Add(_("Shuffled n-2 Equal")); list.Add(_("Pipe Organ")); list.Add(_("Mirrored Organ")); list.Add(_("Wave")); - list.Add(_("50% Sorted (Head)")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -161,12 +163,24 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4) - 1) + if (i <= (m_array.size() / 4)) { ++it; } } std::shuffle(it, m_array.end(), g); } - else if (schema == 5) // 50% Sorted + else if (schema == 5) // 25% Sorted, Head + { + std::vector::iterator it = m_array.begin(); + size_t half = m_array.size() / 2; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= half + (half / 2)) + { ++it; } + } + std::shuffle(m_array.begin(), it, g); + } + else if (schema == 6) // 50% Sorted { std::vector::iterator it = m_array.begin(); for (size_t i = 0; i < m_array.size(); ++i) @@ -177,19 +191,41 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } std::shuffle(it, m_array.end(), g); } - else if (schema == 6) // 75% Sorted + else if (schema == 7) // 50% Sorted, Head + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { ++it; } + } + std::shuffle(m_array.begin(), it, g); + } + else if (schema == 8) // 75% Sorted { std::vector::iterator it = m_array.begin(); size_t half = m_array.size() / 2; for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i < half + (half / 2)) + if (i <= half + (half / 2)) { ++it; } } std::shuffle(it, m_array.end(), g); } - else if (schema == 7) // Cubic skew of [1,n] + else if (schema == 9) // 75% Sorted, Head + { + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4)) + { ++it; } + } + std::shuffle(m_array.begin(), it, g); + } + else if (schema == 10) // Cubic skew of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { @@ -206,7 +242,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); } - else if (schema == 8) // Quintic skew of [1,n] + else if (schema == 11) // Quintic skew of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { @@ -223,7 +259,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); } - else if (schema == 9) // shuffled n-2 equal values in [1,n] + else if (schema == 12) // shuffled n-2 equal values in [1,n] { m_array[0] = ArrayItem(1); for (size_t i = 1; i < m_array.size()-1; ++i) @@ -234,7 +270,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); } - else if (schema == 10) // Pipe organ (1, 1, 2, 2, 1, 1) + else if (schema == 13) // Pipe organ (1, 1, 2, 2, 1, 1) { int val = 1; for (size_t i = 0; i < m_array.size() / 2; ++i) @@ -247,7 +283,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val); --val; } } - else if (schema == 11) // Mirrored organ (3, 2, 1, 1, 2, 3) + else if (schema == 14) // Mirrored organ (3, 2, 1, 1, 2, 3) { int val = m_array.size() / 2; for (size_t i = 0; i < m_array.size() / 2; ++i) @@ -260,7 +296,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val); ++val; } } - else if (schema == 12) // Wave + else if (schema == 15) // Wave { double n = double(m_array.size()); double pi = 3.14159265358979323846; @@ -272,19 +308,6 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val + 1); } } - else if (schema == 13) // 50% Sorted, Head - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) - { - ++it; - } - } - std::shuffle(m_array.begin(), it, g); - } else // fallback { return FillData(0, arraysize); From 960c00d605d1ea50877fd6a04a02029e455ac89b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 20:49:31 +0800 Subject: [PATCH 037/289] Added Bead Sort Due to Bead Sort requiring access to the element as part of its sorting logic, ArrayItem can now be casted to an int --- src/SortAlgo.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 1 + src/SortArray.h | 2 ++ 3 files changed, 51 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index b32ed494e..5181b0d0d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -38,6 +38,7 @@ #include #include #include +#include typedef ArrayItem value_type; @@ -123,6 +124,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, _("An O(1) place O(n log n) time stable merge sort.") }, + { _("Gravity Sort"), &GravitySort, UINT_MAX, UINT_MAX, + _("This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, @@ -1306,6 +1309,51 @@ void PancakeSort(SortArray& A) } } +void GravitySort(SortArray& A) +{ + int max = 0; + int len = A.size(); + for (int n = 1; n < len; ++n) + { + int m = A[n]; + if (m > max) + { + max = A[n]; + } + } + + // allocating memory + std::vector> beads; + beads.resize(len); + for (int i = 0; i < len; i++) { + beads[i].resize(max); + std::fill(beads[i].begin(), beads[i].end(), 0); + } + + // mark the beads + for (int i = 0; i < len; i++) { + int n = A[i]; + for (int j = 0; j < n; j++) { + beads[i][j] = 1; + } + } + + // move down the beads + for (int j = 0; j < max; j++) + { + int sum = 0; + for (int i = 0; i < len; i++) + { + sum += beads[i][j]; + beads[i][j] = 0; + } + for (int i = len - 1; i >= len - sum; --i) { + size_t k = static_cast(i); + A.set(k, ArrayItem(j + 1)); + } + } +} + // **************************************************************************** // *** Bitonic Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 8bef802f1..1a7bf500d 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -105,6 +105,7 @@ void BozoSort(class SortArray& a); void StoogeSort(class SortArray& a); void SlowSort(class SortArray& a); void PancakeSort(class SortArray& a); +void GravitySort(class SortArray& a); void CycleSort(class SortArray& a); diff --git a/src/SortArray.h b/src/SortArray.h index 861451ef3..1093079cb 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -87,6 +87,8 @@ class ArrayItem return *this; } + operator int() const { return value; } + bool operator== (const ArrayItem& v) const { OnComparison(*this,v); return (value == v.value); } From 2ce26fb6ab78060dd11bb4bd0d9b7c5409f4fe35 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 20:51:25 +0800 Subject: [PATCH 038/289] Minor corrections on Bead Sort --- src/SortAlgo.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 5181b0d0d..4a9cfab33 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -124,8 +124,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, _("An O(1) place O(n log n) time stable merge sort.") }, - { _("Gravity Sort"), &GravitySort, UINT_MAX, UINT_MAX, - _("This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, + { _("Bead Sort"), &GravitySort, UINT_MAX, UINT_MAX, + _("Also known as Gravity Sort. This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, @@ -1322,7 +1322,6 @@ void GravitySort(SortArray& A) } } - // allocating memory std::vector> beads; beads.resize(len); for (int i = 0; i < len; i++) { @@ -1330,7 +1329,6 @@ void GravitySort(SortArray& A) std::fill(beads[i].begin(), beads[i].end(), 0); } - // mark the beads for (int i = 0; i < len; i++) { int n = A[i]; for (int j = 0; j < n; j++) { @@ -1338,7 +1336,6 @@ void GravitySort(SortArray& A) } } - // move down the beads for (int j = 0; j < max; j++) { int sum = 0; From 44db2d598c4da09cc0bdae6dd71318840ab61ecb Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 21:00:15 +0800 Subject: [PATCH 039/289] Bead Sort now has sounds --- src/SortAlgo.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 4a9cfab33..efc52dd92 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1315,7 +1315,7 @@ void GravitySort(SortArray& A) int len = A.size(); for (int n = 1; n < len; ++n) { - int m = A[n]; + int m = A[n].get(); if (m > max) { max = A[n]; @@ -1330,7 +1330,7 @@ void GravitySort(SortArray& A) } for (int i = 0; i < len; i++) { - int n = A[i]; + int n = A[i].get(); for (int j = 0; j < n; j++) { beads[i][j] = 1; } @@ -1347,6 +1347,7 @@ void GravitySort(SortArray& A) for (int i = len - 1; i >= len - sum; --i) { size_t k = static_cast(i); A.set(k, ArrayItem(j + 1)); + A[k].get(); } } } From e112bde158f4ae41c8d12878d63d017a56576eeb Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 21:40:06 +0800 Subject: [PATCH 040/289] Fixed issue on Bead Sort Bead Sort, before this fix, makes the last 2 elements after the sorting process is done to be equal, when they shouldn't be, this also results in a small chance of crashing the program. The issue is now resolved. --- src/SortAlgo.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index efc52dd92..d91dbe70e 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1324,27 +1324,27 @@ void GravitySort(SortArray& A) std::vector> beads; beads.resize(len); - for (int i = 0; i < len; i++) { + for (int i = 0; i < len; ++i) { beads[i].resize(max); std::fill(beads[i].begin(), beads[i].end(), 0); } - for (int i = 0; i < len; i++) { + for (int i = 0; i < len; ++i) { int n = A[i].get(); - for (int j = 0; j < n; j++) { + for (int j = 0; j < n; ++j) { beads[i][j] = 1; } } - for (int j = 0; j < max; j++) + for (int j = 0; j < max; ++j) { int sum = 0; - for (int i = 0; i < len; i++) + for (int i = 0; i < len; ++i) { sum += beads[i][j]; beads[i][j] = 0; } - for (int i = len - 1; i >= len - sum; --i) { + for (int i = len - sum; i < len; ++i) { size_t k = static_cast(i); A.set(k, ArrayItem(j + 1)); A[k].get(); From db6f6ee4a8a6d1fa250ad94ac0bec7bad434f23c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 7 Oct 2024 23:23:20 +0800 Subject: [PATCH 041/289] Fixed Bead Sort, for real My declaration of int max is wrong, leading to incorrect results on reverse sorted array, this should FINALLY fix it now, I have also tested it out. --- src/SortAlgo.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d91dbe70e..7f4d485f9 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1311,29 +1311,22 @@ void PancakeSort(SortArray& A) void GravitySort(SortArray& A) { - int max = 0; + int max = A[0]; int len = A.size(); for (int n = 1; n < len; ++n) { int m = A[n].get(); if (m > max) - { - max = A[n]; - } + { max = m; } } - std::vector> beads; - beads.resize(len); - for (int i = 0; i < len; ++i) { - beads[i].resize(max); - std::fill(beads[i].begin(), beads[i].end(), 0); - } + std::vector> beads(len, std::vector(max, 0));; - for (int i = 0; i < len; ++i) { + for (int i = 0; i < len; ++i) + { int n = A[i].get(); - for (int j = 0; j < n; ++j) { - beads[i][j] = 1; - } + for (int j = 0; j < n; ++j) + { beads[i][j] = 1; } } for (int j = 0; j < max; ++j) @@ -1344,7 +1337,8 @@ void GravitySort(SortArray& A) sum += beads[i][j]; beads[i][j] = 0; } - for (int i = len - sum; i < len; ++i) { + for (int i = len - 1; i >= len - sum; --i) + { size_t k = static_cast(i); A.set(k, ArrayItem(j + 1)); A[k].get(); From 63b0c4e03c05f5c59c1a0ae6a3158f531d67da6e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 8 Oct 2024 00:10:41 +0800 Subject: [PATCH 042/289] Added Sawtooth and Reverse Sawtooth array input --- src/SortArray.cpp | 50 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index a0a9dedad..b9a9b79d0 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -122,6 +122,8 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Pipe Organ")); list.Add(_("Mirrored Organ")); list.Add(_("Wave")); + list.Add(_("Sawtooth")); + list.Add(_("Reverse Sawtooth")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -157,13 +159,14 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[0] = m_array[m_array.size() - 1]; m_array[m_array.size() - 1] = temp; } - else if (schema == 4) // 25% Sorted + else if (schema == 4) // 25% Shuffled { std::vector::iterator it = m_array.begin(); + size_t half = m_array.size() / 2; for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) + if (i <= half + (half / 2)) { ++it; } } std::shuffle(it, m_array.end(), g); @@ -171,11 +174,10 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) else if (schema == 5) // 25% Sorted, Head { std::vector::iterator it = m_array.begin(); - size_t half = m_array.size() / 2; for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) + if (i <= (m_array.size() / 4)) { ++it; } } std::shuffle(m_array.begin(), it, g); @@ -198,29 +200,29 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= (m_array.size() / 2) - 1) - { ++it; } + { ++it;} } std::shuffle(m_array.begin(), it, g); } - else if (schema == 8) // 75% Sorted + else if (schema == 8) // 75% Shuffled { std::vector::iterator it = m_array.begin(); - size_t half = m_array.size() / 2; for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4)) { ++it; } } std::shuffle(it, m_array.end(), g); } - else if (schema == 9) // 75% Sorted, Head + else if (schema == 9) // 75% Shuffled, Head { std::vector::iterator it = m_array.begin(); + size_t half = m_array.size() / 2; for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) + if (i <= half + (half / 2)) { ++it; } } std::shuffle(m_array.begin(), it, g); @@ -308,6 +310,32 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[i] = ArrayItem(val + 1); } } + else if (schema == 16) // Sawtooth + { + int teeth = sqrt(m_array.size()) / 7; + if (teeth <= 1) { teeth = 2; } + int max = m_array.size() / teeth; + int count = 1; + for (size_t i = 0; i < m_array.size(); ++i) + { + if (count > max) { count = 1; } + m_array[i] = ArrayItem(count); + ++count; + } + } + else if (schema == 17) // Reverse Sawtooth + { + int teeth = sqrt(m_array.size()) / 7; + if (teeth <= 1) { teeth = 2; } + int max = m_array.size() / teeth; + int count = max; + for (size_t i = 0; i < m_array.size(); ++i) + { + if (count <= 0) { count = max; } + m_array[i] = ArrayItem(count); + --count; + } + } else // fallback { return FillData(0, arraysize); From 19071a9df787b41f4447aa3529f8c23763ee8940 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 8 Oct 2024 21:40:27 +0800 Subject: [PATCH 043/289] Added Circle Sort --- src/SortAlgo.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 1 + 2 files changed, 40 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 7f4d485f9..eb09bdae2 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -87,6 +87,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, _("This variant sorts from both directions of the array simultaneously.") }, + { _("Circle Sort"), &CircleSort, UINT_MAX, UINT_MAX, + _("Circle Sort is a recursive sorting algorithm that works by comparing and swapping elements in a circular manner.") }, { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Optimized Gnome Sort"), &OptimizedGnomeSort, UINT_MAX, UINT_MAX, @@ -834,6 +836,43 @@ void DualCocktailShakerSort(SortArray& A) } } +// **************************************************************************** +// *** Circle Sort + +bool CircleSortRec(SortArray& A, size_t low, size_t high) +{ + bool swapped = false; + if (low == high) { return false; } + size_t lo = low, hi = high; + while (lo < hi) + { + if (A[lo] > A[hi]) + { + A.swap(lo, hi); + swapped = true; + } + ++lo; --hi; + } + if (lo == hi) + { + if (A[lo] > A[hi + 1]) + { + A.swap(lo, hi + 1); + swapped = true; + } + } + size_t mid = (high - low) / 2; + bool firstHalf = CircleSortRec(A, low, low + mid); + bool secondHalf = CircleSortRec(A, low + mid + 1, high); + return swapped || firstHalf || secondHalf; +} + +void CircleSort(SortArray& A) +{ + size_t n = A.size(); + while (CircleSortRec(A, 0, n - 1)) {} +} + // **************************************************************************** // *** Gnome Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 1a7bf500d..a4c51ce18 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -81,6 +81,7 @@ void CombSort(class SortArray& a); void GnomeSort(class SortArray& a); void OptimizedGnomeSort(class SortArray& a); void OddEvenSort(class SortArray& a); +void CircleSort(class SortArray& a); void ShellSort(SortArray& a); void HeapSort(class SortArray& a); From 1ef2707ee0b03fa6de7a60970c1821f9e25436ca Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 9 Oct 2024 21:01:02 +0800 Subject: [PATCH 044/289] Prepare files for Grail Sort --- src/Makefile.am | 2 ++ src/SortAlgo.cpp | 4 ++-- src/SortAlgo.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d29ee395e..28f4fdc58 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,8 +5,10 @@ bin_PROGRAMS = sound-of-sorting COMMON = SortArray.cpp SortArray.h \ SortSound.cpp \ SortAlgo.cpp SortAlgo.h \ + algorithms/grailsort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp + sound_of_sorting_SOURCES = \ WMain.cpp WMain.h \ diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index eb09bdae2..6fb5de561 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -126,6 +126,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, _("An O(1) place O(n log n) time stable merge sort.") }, + { _("Grail Sort"), &GrailSort, UINT_MAX, inversion_count_instrumented, + _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, { _("Bead Sort"), &GravitySort, UINT_MAX, UINT_MAX, _("Also known as Gravity Sort. This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, @@ -1940,5 +1942,3 @@ void CycleSort(SortArray& A) { CycleSort(A, A.size()); } - -// **************************************************************************** diff --git a/src/SortAlgo.h b/src/SortAlgo.h index a4c51ce18..b418caef8 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -100,6 +100,7 @@ void StlHeapSort(class SortArray& a); void TimSort(class SortArray& a); void WikiSort(class SortArray& a); +void GrailSort(class SortArray& a); void BogoSort(class SortArray& a); void BozoSort(class SortArray& a); From 3f4e9441816e43df92123e13fb4e5bd7b86cd542 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 9 Oct 2024 21:01:46 +0800 Subject: [PATCH 045/289] Added Grail Sort --- src/algorithms/grailsort.cpp | 1330 ++++++++++++++++++++++++++++++++++ 1 file changed, 1330 insertions(+) create mode 100644 src/algorithms/grailsort.cpp diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp new file mode 100644 index 000000000..6cb19a65b --- /dev/null +++ b/src/algorithms/grailsort.cpp @@ -0,0 +1,1330 @@ +/* + * MIT License + * + * Copyright (c) 2013 Andrey Astrelin + * Copyright (c) 2020-2021 The Holy Grail Sort Project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + /* + * The Holy Grail Sort Project + * Project Manager: Summer Dragonfly + * Project Contributors: 666666t + * Anonymous0726 + * aphitorite + * Control + * dani_dlg + * DeveloperSort + * EilrahcF + * Enver + * Gaming32 + * lovebuny + * Morwenn + * MP + * phoenixbound + * Spex_guy + * thatsOven + * _fluffyy + * + * Special thanks to "The Studio" Discord community! + */ + +#include "../SortAlgo.h" +#include +#include +#include +#include +#include + +namespace grailsort_detail +{ + // Credit to phoenixbound for this clever idea + enum struct Subarray + { + LEFT, + RIGHT + }; + + template + struct ThreeWayCompare + { + Compare compare; + + explicit ThreeWayCompare(Compare&& comp) : + compare(std::forward(comp)) + {} + + template + int operator()(T&& lhs, U&& rhs) + { + if (compare(lhs, rhs)) { + return -1; + } + if (compare(rhs, lhs)) { + return 1; + } + return 0; + } + }; + + struct GrailSort + { + int currBlockLen; + Subarray currBlockOrigin; + + template + static void BlockSwap(RandomAccessIterator array, int a, int b, int blockLen) { + std::swap_ranges(array + a, array + (a + blockLen), array + b); + } + + // Swaps the order of two adjacent blocks whose lengths may or may not be equal. + // Variant of the Gries-Mills algorithm, which is basically recursive block swaps + template + static void Rotate(RandomAccessIterator array, int start, int leftLen, int rightLen) { + while (leftLen > 0 && rightLen > 0) { + if (leftLen <= rightLen) { + BlockSwap(array, start, start + leftLen, leftLen); + start += leftLen; + rightLen -= leftLen; + } + else { + BlockSwap(array, start + leftLen - rightLen, start + leftLen, rightLen); + leftLen -= rightLen; + } + } + } + + // Variant of Insertion Sort that utilizes swaps instead of overwrites. + // Also known as "Optimized Gnomesort". + template + static void InsertSort(RandomAccessIterator array, int start, int length, Compare comp) { + for (int item = 1; item < length; item++) { + int left = start + item - 1; + int right = start + item; + + while (left >= start && comp(array[left], array[right]) > 0) { + std::iter_swap(array + left, array + right); + left--; + right--; + } + } + } + + template + static int BinarySearchLeft(RandomAccessIterator array, int start, int length, const T& target, Compare comp) { + int left = 0; + int right = length; + + while (left < right) { + // equivalent to (left + right) / 2 with added overflow protection + int middle = left + ((right - left) / 2); + + if (comp(array[start + middle], target) < 0) { + left = middle + 1; + } + else { + right = middle; + } + } + return left; + } + + // Credit to Anonymous0726 for debugging + template + static int BinarySearchRight(RandomAccessIterator array, int start, int length, const T& target, Compare comp) { + int left = 0; + int right = length; + + while (left < right) { + // equivalent to (left + right) / 2 with added overflow protection + int middle = left + ((right - left) / 2); + if (comp(array[start + middle], target) > 0) { + right = middle; + } + else { + left = middle + 1; + } + } + // OFF-BY-ONE BUG FIXED: used to be `return right - 1;` + return right; + } + + // cost: 2 * length + idealKeys^2 / 2 + template + static int CollectKeys(RandomAccessIterator array, int start, int length, int idealKeys, Compare comp) { + int keysFound = 1; // by itself, the first item in the array is our first unique key + int firstKey = 0; // the first item in the array is at the first position in the array + int currKey = 1; // the index used for finding potentially unique items ("keys") in the array + + while (currKey < length && keysFound < idealKeys) { + + // Find the location in the key-buffer where our current key can be inserted in sorted order. + // If the key at insertPos is equal to currKey, then currKey isn't unique and we move on. + int insertPos = BinarySearchLeft(array, start + firstKey, keysFound, array[start + currKey], comp); + + // The second part of this conditional does the equal check we were just talking about; however, + // if currKey is larger than everything in the key-buffer (meaning insertPos == keysFound), + // then that also tells us it wasn't *equal* to anything in the key-buffer. Magic! :) + if (insertPos == keysFound || comp(array[start + currKey], array[start + firstKey + insertPos]) != 0) { + + // First, rotate the key-buffer over to currKey's immediate left... + // (this helps save a TON of swaps/writes!!!) + Rotate(array, start + firstKey, keysFound, currKey - (firstKey + keysFound)); + + // Update the new position of firstKey... + firstKey = currKey - keysFound; + + // Then, "insertion sort" currKey to its spot in the key-buffer! + Rotate(array, start + firstKey + insertPos, keysFound - insertPos, 1); + + // One step closer to idealKeys. + keysFound++; + } + // Move on and test the next key... + currKey++; + } + + // Bring however many keys we found back to the beginning of our array, + // and return the number of keys collected. + Rotate(array, start, firstKey, keysFound); + return keysFound; + } + + template + static void PairwiseSwaps(RandomAccessIterator array, int start, int length, Compare comp) { + int index; + for (index = 1; index < length; index += 2) { + int left = start + index - 1; + int right = start + index; + + if (comp(array[left], array[right]) > 0) { + std::swap(array[left - 2], array[right]); + std::swap(array[right - 2], array[left]); + } + else { + std::swap(array[left - 2], array[left]); + std::swap(array[right - 2], array[right]); + } + } + + int left = start + index - 1; + if (left < start + length) { + std::swap(array[left - 2], array[left]); + } + } + + template + static void PairwiseWrites(RandomAccessIterator array, int start, int length, Compare comp) { + int index; + for (index = 1; index < length; index += 2) { + int left = start + index - 1; + int right = start + index; + + if (comp(array[left], array[right]) > 0) { + array[left - 2] = std::move(array[right]); + array[right - 2] = std::move(array[left]); + } + else { + array[left - 2] = std::move(array[left]); + array[right - 2] = std::move(array[right]); + } + } + + int left = start + index - 1; + if (left < start + length) { + array[left - 2] = std::move(array[left]); + } + } + + // array[buffer .. start - 1] <=> "scrolling buffer" + // + // "scrolling buffer" + array[start, middle - 1] + array[middle, end - 1] + // --> array[buffer, buffer + end - 1] + "scrolling buffer" + template + static void MergeForwards(RandomAccessIterator array, int start, int leftLen, int rightLen, int bufferOffset, Compare comp) { + auto buffer = array + (start - bufferOffset); + auto left = array + start; + auto middle = array + (start + leftLen); + auto right = middle; + auto end = middle + rightLen; + + while (right != end) { + if (left == middle || comp(*left, *right) > 0) { + std::iter_swap(buffer, right); + ++right; + } + else { + std::iter_swap(buffer, left); + ++left; + } + ++buffer; + } + + while (left != middle) { + std::iter_swap(buffer, left); + ++buffer; + ++left; + } + } + + // credit to 666666t for thorough bug-checking/fixing + template + static void MergeBackwards(RandomAccessIterator array, int start, int leftLen, int rightLen, int bufferOffset, Compare comp) { + // used to be '= start' + int end = start - 1; + // used to be '= start + leftLen - 1' + int left = end + leftLen; + int middle = left; + // OFF-BY-ONE BUG FIXED: used to be `int right = middle + rightLen - 1;` + int right = middle + rightLen; + // OFF-BY-ONE BUG FIXED: used to be `int buffer = right + bufferOffset - 1;` + int buffer = right + bufferOffset; + + // used to be 'left >= end' + while (left > end) { + if (right == middle || comp(array[left], array[right]) > 0) { + + std::swap(array[buffer], array[left]); + left--; + } + else { + std::swap(array[buffer], array[right]); + right--; + } + buffer--; + } + + if (right != buffer) { + while (right > middle) { + std::swap(array[buffer], array[right]); + buffer--; + right--; + } + } + } + + // array[buffer .. start - 1] <=> "free space" + // + // "free space" + array[start, middle - 1] + array[middle, end - 1] + // --> array[buffer, buffer + end - 1] + "free space" + // + // FUNCTION RENAMED: More consistent with "out-of-place" being at the end + template + static void MergeOutOfPlace(RandomAccessIterator array, int start, int leftLen, int rightLen, int bufferOffset, Compare comp) { + int buffer = start - bufferOffset; + int left = start; + int middle = start + leftLen; + int right = middle; + int end = middle + rightLen; + + while (right < end) { + if (left == middle || comp(array[left], array[right]) > 0) { + array[buffer] = std::move(array[right]); + right++; + } + else { + array[buffer] = std::move(array[left]); + left++; + } + buffer++; + } + + if (buffer != left) { + while (left < middle) { + array[buffer] = std::move(array[left]); + buffer++; + left++; + } + } + } + + template + static void BuildInPlace(RandomAccessIterator array, int start, int length, int currentLen, int bufferLen, Compare comp) { + for (int mergeLen = currentLen; mergeLen < bufferLen; mergeLen *= 2) { + int fullMerge = 2 * mergeLen; + + int mergeIndex; + int mergeEnd = start + length - fullMerge; + int bufferOffset = mergeLen; + + for (mergeIndex = start; mergeIndex <= mergeEnd; mergeIndex += fullMerge) { + MergeForwards(array, mergeIndex, mergeLen, mergeLen, bufferOffset, comp); + } + + int leftOver = length - (mergeIndex - start); + + if (leftOver > mergeLen) { + MergeForwards(array, mergeIndex, mergeLen, leftOver - mergeLen, bufferOffset, comp); + } + else { + Rotate(array, mergeIndex - mergeLen, mergeLen, leftOver); + } + + start -= mergeLen; + } + + int fullMerge = 2 * bufferLen; + int lastBlock = length % fullMerge; + int lastOffset = start + length - lastBlock; + + if (lastBlock <= bufferLen) { + Rotate(array, lastOffset, lastBlock, bufferLen); + } + else { + MergeBackwards(array, lastOffset, bufferLen, lastBlock - bufferLen, bufferLen, comp); + } + + for (int mergeIndex = lastOffset - fullMerge; mergeIndex >= start; mergeIndex -= fullMerge) { + MergeBackwards(array, mergeIndex, bufferLen, bufferLen, bufferLen, comp); + } + } + + template + void BuildOutOfPlace(RandomAccessIterator array, int start, int length, int bufferLen, int extLen, + BufferIterator extBuffer, Compare comp) { + std::move(array + (start - extLen), array + start, extBuffer); + + PairwiseWrites(array, start, length, comp); + start -= 2; + + int mergeLen; + for (mergeLen = 2; mergeLen < extLen; mergeLen *= 2) { + int fullMerge = 2 * mergeLen; + + int mergeIndex; + int mergeEnd = start + length - fullMerge; + int bufferOffset = mergeLen; + + for (mergeIndex = start; mergeIndex <= mergeEnd; mergeIndex += fullMerge) { + MergeOutOfPlace(array, mergeIndex, mergeLen, mergeLen, bufferOffset, comp); + } + + int leftOver = length - (mergeIndex - start); + + if (leftOver > mergeLen) { + MergeOutOfPlace(array, mergeIndex, mergeLen, leftOver - mergeLen, bufferOffset, comp); + } + else { + // MINOR CHANGE: Used to be a loop; much clearer now + std::move(array + mergeIndex, array + (mergeIndex + leftOver), array + (mergeIndex - mergeLen)); + } + + start -= mergeLen; + } + + std::move(extBuffer, extBuffer + extLen, array + (start + length)); + BuildInPlace(array, start, length, mergeLen, bufferLen, comp); + } + + // build blocks of length 'bufferLen' + // input: [start - mergeLen, start - 1] elements are buffer + // output: first 'bufferLen' elements are buffer, blocks (2 * bufferLen) and last subblock sorted + template + void BuildBlocks(RandomAccessIterator array, int start, int length, int bufferLen, + BufferIterator extBuffer, int extBufferLen, Compare comp) { + if (extBufferLen != 0) { + int extLen; + + if (bufferLen < extBufferLen) { + extLen = bufferLen; + } + else { + // max power of 2 -- just in case + extLen = 1; + while ((extLen * 2) <= extBufferLen) { + extLen *= 2; + } + } + + BuildOutOfPlace(array, start, length, bufferLen, extLen, extBuffer, comp); + } + else { + PairwiseSwaps(array, start, length, comp); + BuildInPlace(array, start - 2, length, 2, bufferLen, comp); + } + } + + // Returns the final position of 'medianKey' + template + static int BlockSelectSort(RandomAccessIterator array, int firstKey, int start, int medianKey, int blockCount, int blockLen, Compare comp) { + for (int firstBlock = 0; firstBlock < blockCount; firstBlock++) { + int selectBlock = firstBlock; + + for (int currBlock = firstBlock + 1; currBlock < blockCount; currBlock++) { + int compare = comp(array[start + (currBlock * blockLen)], + array[start + (selectBlock * blockLen)]); + + if (compare < 0 || (compare == 0 && comp(array[firstKey + currBlock], + array[firstKey + selectBlock]) < 0)) { + selectBlock = currBlock; + } + } + + if (selectBlock != firstBlock) { + // Swap the left and right selected blocks... + BlockSwap(array, start + (firstBlock * blockLen), start + (selectBlock * blockLen), blockLen); + + // Swap the keys... + std::swap(array[firstKey + firstBlock], array[firstKey + selectBlock]); + + // ...and follow the 'medianKey' if it was swapped + + // ORIGINAL LOC: if(midkey==u-1 || midkey==p) midkey^=(u-1)^p; + // MASSIVE, MASSIVE credit to lovebuny for figuring this one out! + if (medianKey == firstBlock) { + medianKey = selectBlock; + } + else if (medianKey == selectBlock) { + medianKey = firstBlock; + } + } + } + + return medianKey; + } + + // Swaps Grailsort's "scrolling buffer" from the right side of the array all the way back to 'start'. + // Costs O(n) swaps (amortized). + // + // OFF-BY-ONE BUG FIXED: used to be `int index = start + resetLen`; credit to 666666t for debugging + // RESTRUCTED, BETTER NAMES: 'resetLen' is now 'length' and 'bufferLen' is now 'bufferOffset' + template + static void InPlaceBufferReset(RandomAccessIterator array, int start, int length, int bufferOffset) { + int index = start + length - 1; + int buffer = index - bufferOffset; + + while (index >= start) { + std::swap(array[index], array[buffer]); + index--; + buffer--; + } + } + + // Shifts entire array over 'bufferOffset' spaces to move the out-of-place merging buffer back to + // the beginning of the array. + // Costs O(n) writes (amortized). + // + // OFF-BY-ONE BUG FIXED: used to be `int index = start + resetLen`; credit to 666666t for debugging + // RESTRUCTED, BETTER NAMES: 'resetLen' is now 'length' and 'bufferLen' is now 'bufferOffset' + template + static void OutOfPlaceBufferReset(RandomAccessIterator array, int start, int length, int bufferOffset) { + int index = start + length - 1; + int buffer = index - bufferOffset; + + while (index >= start) { + array[index] = std::move(array[buffer]); + index--; + buffer--; + } + } + + // Rewinds Grailsort's "scrolling buffer" to the left any items belonging to the left subarray block + // left over by a "smart merge". This is used to continue an ongoing merge that has run out of buffer space. + // Costs O(sqrt n) swaps (amortized) in the *absolute* worst-case. + // + // NAMING IMPROVED: the left over items are in the middle of the merge while the buffer is at the end + // BETTER ORDER-OF-OPERATIONS, NAMING IMPROVED: the left over items (now called 'leftBlock') are in the + // middle of the merge while the buffer is at the end + template + static void InPlaceBufferRewind(RandomAccessIterator array, int start, int leftBlock, int buffer) { + while (leftBlock >= start) { + std::swap(array[buffer], array[leftBlock]); + leftBlock--; + buffer--; + } + } + + // Rewinds Grailsort's out-of-place buffer to the left of any items belonging to the left subarray block + // left over by a "smart merge". This is used to continue an ongoing merge that has run out of buffer space. + // Costs O(sqrt n) writes (amortized) in the *absolute* worst-case. + // + // INCORRECT ORDER OF PARAMETERS BUG FIXED: `leftOvers` should be the middle, and `buffer` should be the end + // BETTER ORDER, INCORRECT ORDER OF PARAMETERS BUG FIXED: `leftOvers` (now called 'leftBlock') should be + // the middle, and `buffer` should be the end + template + static void OutOfPlaceBufferRewind(RandomAccessIterator array, int start, int leftBlock, int buffer) { + while (leftBlock >= start) { + array[buffer] = std::move(array[leftBlock]); + leftBlock--; + buffer--; + } + } + + template + static Subarray GetSubarray(RandomAccessIterator array, int currKey, int medianKey, Compare comp) { + if (comp(array[currKey], array[medianKey]) < 0) { + return Subarray::LEFT; + } + else { + return Subarray::RIGHT; + } + } + + // FUNCTION RE-RENAMED: last/final left blocks are used to calculate the length of the final merge + template + static int CountLastMergeBlocks(RandomAccessIterator array, int offset, int blockCount, int blockLen, Compare comp) { + int blocksToMerge = 0; + + int lastRightFrag = offset + (blockCount * blockLen); + int prevLeftBlock = lastRightFrag - blockLen; + + while (blocksToMerge < blockCount && comp(array[lastRightFrag], array[prevLeftBlock]) < 0) { + blocksToMerge++; + prevLeftBlock -= blockLen; + } + + return blocksToMerge; + } + + template + void SmartMerge(RandomAccessIterator array, int start, int leftLen, Subarray leftOrigin, int rightLen, int bufferOffset, Compare comp) { + auto buffer = array + (start - bufferOffset); + auto left = array + start; + auto middle = left + leftLen; + auto right = middle; + auto end = middle + rightLen; + + if (leftOrigin == Subarray::LEFT) { + while (left != middle && right != end) { + if (comp(*left, *right) <= 0) { + std::iter_swap(buffer, left); + ++left; + } + else { + std::iter_swap(buffer, right); + ++right; + } + ++buffer; + } + } + else { + while (left != middle && right != end) { + if (comp(*left, *right) < 0) { + std::iter_swap(buffer, left); + ++left; + } + else { + std::iter_swap(buffer, right); + ++right; + } + ++buffer; + } + } + + if (left < middle) { + this->currBlockLen = middle - left; + // UPDATED ARGUMENTS: 'middle' and 'end' now 'middle - 1' and 'end - 1' + InPlaceBufferRewind(array, left - array, (middle - array) - 1, (end - array) - 1); + } + else { + this->currBlockLen = end - right; + if (leftOrigin == Subarray::LEFT) { + this->currBlockOrigin = Subarray::RIGHT; + } + else { + this->currBlockOrigin = Subarray::LEFT; + } + } + } + + // MINOR CHANGE: better naming -- 'insertPos' is now 'mergeLen' -- and "middle" calculation simplified + template + void SmartLazyMerge(RandomAccessIterator array, int start, int leftLen, Subarray leftOrigin, int rightLen, Compare comp) { + int middle = start + leftLen; + + if (leftOrigin == Subarray::LEFT) { + if (comp(array[middle - 1], array[middle]) > 0) { + while (leftLen != 0) { + int mergeLen = BinarySearchLeft(array, middle, rightLen, array[start], comp); + + if (mergeLen != 0) { + Rotate(array, start, leftLen, mergeLen); + start += mergeLen; + rightLen -= mergeLen; + } + + middle += mergeLen; + + if (rightLen == 0) { + this->currBlockLen = leftLen; + return; + } + else { + do { + start++; + leftLen--; + } while (leftLen != 0 && comp(array[start], array[middle]) <= 0); + } + } + } + } + else { + if (comp(array[middle - 1], array[middle]) >= 0) { + while (leftLen != 0) { + int mergeLen = BinarySearchRight(array, start + leftLen, rightLen, array[start], comp); + + if (mergeLen != 0) { + Rotate(array, start, leftLen, mergeLen); + start += mergeLen; + rightLen -= mergeLen; + } + + middle += mergeLen; + + if (rightLen == 0) { + this->currBlockLen = leftLen; + return; + } + else { + do { + start++; + leftLen--; + } while (leftLen != 0 && comp(array[start], array[middle]) < 0); + } + } + } + } + + this->currBlockLen = rightLen; + if (leftOrigin == Subarray::LEFT) { + this->currBlockOrigin = Subarray::RIGHT; + } + else { + this->currBlockOrigin = Subarray::LEFT; + } + } + + // FUNCTION RENAMED: more consistent with other "out-of-place" merges + template + void SmartMergeOutOfPlace(RandomAccessIterator array, int start, int leftLen, Subarray leftOrigin, int rightLen, int bufferOffset, Compare comp) { + int buffer = start - bufferOffset; + int left = start; + int middle = start + leftLen; + int right = middle; + int end = middle + rightLen; + + if (leftOrigin == Subarray::LEFT) { + while (left < middle && right < end) { + if (comp(array[left], array[right]) <= 0) { + array[buffer] = std::move(array[left]); + left++; + } + else { + array[buffer] = std::move(array[right]); + right++; + } + buffer++; + } + } + else { + while (left < middle && right < end) { + if (comp(array[left], array[right]) < 0) { + array[buffer] = std::move(array[left]); + left++; + } + else { + array[buffer] = std::move(array[right]); + right++; + } + buffer++; + } + } + + if (left < middle) { + this->currBlockLen = middle - left; + // UPDATED ARGUMENTS: 'middle' and 'end' now 'middle - 1' and 'end - 1' + OutOfPlaceBufferRewind(array, left, middle - 1, end - 1); + } + else { + this->currBlockLen = end - right; + if (leftOrigin == Subarray::LEFT) { + this->currBlockOrigin = Subarray::RIGHT; + } + else { + this->currBlockOrigin = Subarray::LEFT; + } + } + } + + // Credit to Anonymous0726 for better variable names such as "nextBlock" + // Also minor change: removed unnecessary "currBlock = nextBlock" lines + template + void MergeBlocks(RandomAccessIterator array, int firstKey, int medianKey, int start, int blockCount, int blockLen, + int lastMergeBlocks, int lastLen, Compare comp) { + int buffer; + + int currBlock; + int nextBlock = start + blockLen; + + this->currBlockLen = blockLen; + this->currBlockOrigin = GetSubarray(array, firstKey, medianKey, comp); + + Subarray nextBlockOrigin; + for (int keyIndex = 1; keyIndex < blockCount; keyIndex++, nextBlock += blockLen) { + currBlock = nextBlock - this->currBlockLen; + nextBlockOrigin = GetSubarray(array, firstKey + keyIndex, medianKey, comp); + + if (nextBlockOrigin == this->currBlockOrigin) { + buffer = currBlock - blockLen; + + BlockSwap(array, buffer, currBlock, this->currBlockLen); + this->currBlockLen = blockLen; + } + else { + SmartMerge(array, currBlock, this->currBlockLen, this->currBlockOrigin, blockLen, blockLen, comp); + } + } + + currBlock = nextBlock - this->currBlockLen; + buffer = currBlock - blockLen; + + if (lastLen != 0) { + if (this->currBlockOrigin == Subarray::RIGHT) { + BlockSwap(array, buffer, currBlock, this->currBlockLen); + + currBlock = nextBlock; + this->currBlockLen = blockLen * lastMergeBlocks; + this->currBlockOrigin = Subarray::LEFT; + } + else { + this->currBlockLen += blockLen * lastMergeBlocks; + } + + MergeForwards(array, currBlock, this->currBlockLen, lastLen, blockLen, comp); + } + else { + BlockSwap(array, buffer, currBlock, this->currBlockLen); + } + } + + template + void LazyMergeBlocks(RandomAccessIterator array, int firstKey, int medianKey, int start, int blockCount, int blockLen, + int lastMergeBlocks, int lastLen, Compare comp) { + int currBlock; + int nextBlock = start + blockLen; + + this->currBlockLen = blockLen; + this->currBlockOrigin = GetSubarray(array, firstKey, medianKey, comp); + + Subarray nextBlockOrigin; + for (int keyIndex = 1; keyIndex < blockCount; keyIndex++, nextBlock += blockLen) { + currBlock = nextBlock - this->currBlockLen; + + nextBlockOrigin = GetSubarray(array, firstKey + keyIndex, medianKey, comp); + + if (nextBlockOrigin == this->currBlockOrigin) { + this->currBlockLen = blockLen; + } + else { + // These checks were included in the original code... but why??? + if (blockLen != 0 && this->currBlockLen != 0) { + SmartLazyMerge(array, currBlock, this->currBlockLen, this->currBlockOrigin, blockLen, comp); + } + } + } + + currBlock = nextBlock - this->currBlockLen; + + if (lastLen != 0) { + if (this->currBlockOrigin == Subarray::RIGHT) { + currBlock = nextBlock; + this->currBlockLen = blockLen * lastMergeBlocks; + this->currBlockOrigin = Subarray::LEFT; + } + else { + this->currBlockLen += blockLen * lastMergeBlocks; + } + + LazyMerge(array, currBlock, this->currBlockLen, lastLen, comp); + } + } + + template + void MergeBlocksOutOfPlace(RandomAccessIterator array, int firstKey, int medianKey, int start, int blockCount, int blockLen, + int lastMergeBlocks, int lastLen, Compare comp) { + int buffer; + int currBlock; + int nextBlock = start + blockLen; + + this->currBlockLen = blockLen; + this->currBlockOrigin = GetSubarray(array, firstKey, medianKey, comp); + + Subarray nextBlockOrigin; + for (int keyIndex = 1; keyIndex < blockCount; keyIndex++, nextBlock += blockLen) { + currBlock = nextBlock - this->currBlockLen; + nextBlockOrigin = GetSubarray(array, firstKey + keyIndex, medianKey, comp); + + if (nextBlockOrigin == this->currBlockOrigin) { + buffer = currBlock - blockLen; + std::move(array + currBlock, array + (currBlock + this->currBlockLen), array + buffer); + this->currBlockLen = blockLen; + } + else { + SmartMergeOutOfPlace(array, currBlock, this->currBlockLen, this->currBlockOrigin, blockLen, blockLen, comp); + } + } + + currBlock = nextBlock - this->currBlockLen; + buffer = currBlock - blockLen; + + if (lastLen != 0) { + if (this->currBlockOrigin == Subarray::RIGHT) { + std::move(array + currBlock, array + (currBlock + this->currBlockLen), array + buffer); + currBlock = nextBlock; + this->currBlockLen = blockLen * lastMergeBlocks; + this->currBlockOrigin = Subarray::LEFT; + } + else { + this->currBlockLen += blockLen * lastMergeBlocks; + } + + MergeOutOfPlace(array, currBlock, this->currBlockLen, lastLen, blockLen, comp); + } + else { + std::move(array + currBlock, array + (currBlock + this->currBlockLen), array + buffer); + } + } + + //TODO: Double-check "Merge Blocks" arguments + template + void CombineInPlace(RandomAccessIterator array, int firstKey, int start, int length, int subarrayLen, int blockLen, + int mergeCount, int lastSubarrays, bool buffer, Compare comp) { + int fullMerge = 2 * subarrayLen; + // SLIGHT OPTIMIZATION: 'blockCount' only needs to be calculated once for regular merges + int blockCount = fullMerge / blockLen; + + for (int mergeIndex = 0; mergeIndex < mergeCount; mergeIndex++) { + int offset = start + (mergeIndex * fullMerge); + + InsertSort(array, firstKey, blockCount, comp); + + // INCORRECT PARAMETER BUG FIXED: `block select sort` should be using `offset`, not `start` + int medianKey = subarrayLen / blockLen; + medianKey = BlockSelectSort(array, firstKey, offset, medianKey, blockCount, blockLen, comp); + + if (buffer) { + MergeBlocks(array, firstKey, firstKey + medianKey, offset, blockCount, blockLen, 0, 0, comp); + } + else { + LazyMergeBlocks(array, firstKey, firstKey + medianKey, offset, blockCount, blockLen, 0, 0, comp); + } + } + + // INCORRECT CONDITIONAL/PARAMETER BUG FIXED: Credit to 666666t for debugging. + if (lastSubarrays != 0) { + int offset = start + (mergeCount * fullMerge); + blockCount = lastSubarrays / blockLen; + + InsertSort(array, firstKey, blockCount + 1, comp); + + // INCORRECT PARAMETER BUG FIXED: `block select sort` should be using `offset`, not `start` + int medianKey = subarrayLen / blockLen; + medianKey = BlockSelectSort(array, firstKey, offset, medianKey, blockCount, blockLen, comp); + + // MISSING BOUNDS CHECK BUG FIXED: `lastFragment` *can* be 0 if the last two subarrays are evenly + // divided into blocks. This prevents Grailsort from going out-of-bounds. + int lastFragment = lastSubarrays - (blockCount * blockLen); + int lastMergeBlocks; + if (lastFragment != 0) { + lastMergeBlocks = CountLastMergeBlocks(array, offset, blockCount, blockLen, comp); + } + else { + lastMergeBlocks = 0; + } + + int smartMerges = blockCount - lastMergeBlocks; + + //TODO: Double-check if this micro-optimization works correctly like the original + if (smartMerges == 0) { + int leftLen = lastMergeBlocks * blockLen; + + // INCORRECT PARAMETER BUG FIXED: these merges should be using `offset`, not `start` + if (buffer) { + MergeForwards(array, offset, leftLen, lastFragment, blockLen, comp); + } + else { + LazyMerge(array, offset, leftLen, lastFragment, comp); + } + } + else { + if (buffer) { + MergeBlocks(array, firstKey, firstKey + medianKey, offset, + smartMerges, blockLen, lastMergeBlocks, lastFragment, comp); + } + else { + LazyMergeBlocks(array, firstKey, firstKey + medianKey, offset, + smartMerges, blockLen, lastMergeBlocks, lastFragment, comp); + } + } + } + + if (buffer) { + InPlaceBufferReset(array, start, length, blockLen); + } + } + + template + void CombineOutOfPlace(RandomAccessIterator array, int firstKey, int start, int length, int subarrayLen, int blockLen, + int mergeCount, int lastSubarrays, BufferIterator extBuffer, Compare comp) { + std::move(array + (start - blockLen), array + start, extBuffer); + + int fullMerge = 2 * subarrayLen; + // SLIGHT OPTIMIZATION: 'blockCount' only needs to be calculated once for regular merges + int blockCount = fullMerge / blockLen; + + for (int mergeIndex = 0; mergeIndex < mergeCount; mergeIndex++) { + int offset = start + (mergeIndex * fullMerge); + + InsertSort(array, firstKey, blockCount, comp); + + // INCORRECT PARAMETER BUG FIXED: `block select sort` should be using `offset`, not `start` + int medianKey = subarrayLen / blockLen; + medianKey = BlockSelectSort(array, firstKey, offset, medianKey, blockCount, blockLen, comp); + + MergeBlocksOutOfPlace(array, firstKey, firstKey + medianKey, offset, + blockCount, blockLen, 0, 0, comp); + } + + // INCORRECT CONDITIONAL/PARAMETER BUG FIXED: Credit to 666666t for debugging. + if (lastSubarrays != 0) { + int offset = start + (mergeCount * fullMerge); + blockCount = lastSubarrays / blockLen; + + InsertSort(array, firstKey, blockCount + 1, comp); + + // INCORRECT PARAMETER BUG FIXED: `block select sort` should be using `offset`, not `start` + int medianKey = subarrayLen / blockLen; + medianKey = BlockSelectSort(array, firstKey, offset, medianKey, blockCount, blockLen, comp); + + // MISSING BOUNDS CHECK BUG FIXED: `lastFragment` *can* be 0 if the last two subarrays are evenly + // divided into blocks. This prevents Grailsort from going out-of-bounds. + int lastFragment = lastSubarrays - (blockCount * blockLen); + int lastMergeBlocks; + if (lastFragment != 0) { + lastMergeBlocks = CountLastMergeBlocks(array, offset, blockCount, blockLen, comp); + } + else { + lastMergeBlocks = 0; + } + + int smartMerges = blockCount - lastMergeBlocks; + + if (smartMerges == 0) { + // MINOR CHANGE: renamed for consistency (used to be 'leftLength') + int leftLen = lastMergeBlocks * blockLen; + + // INCORRECT PARAMETER BUG FIXED: this merge should be using `offset`, not `start` + MergeOutOfPlace(array, offset, leftLen, lastFragment, blockLen, comp); + } + else { + MergeBlocksOutOfPlace(array, firstKey, firstKey + medianKey, offset, + smartMerges, blockLen, lastMergeBlocks, lastFragment, comp); + } + } + + OutOfPlaceBufferReset(array, start, length, blockLen); + std::move(extBuffer, extBuffer + blockLen, array + (start - blockLen)); + } + + // Keys are on the left side of array. Blocks of length 'subarrayLen' combined. We'll combine them in pairs + // 'subarrayLen' is a power of 2. (2 * subarrayLen / blockLen) keys are guaranteed + // + // IMPORTANT RENAMES: 'lastSubarray' is now 'lastSubarrays' because it includes the length of the last left + // subarray AND last right subarray (if there is a right subarray at all). + // + // *Please also check everything surrounding 'if(lastSubarrays != 0)' inside + // 'combine in-/out-of-place' methods for other renames!!* + template + void CombineBlocks(RandomAccessIterator array, int firstKey, int start, int length, int subarrayLen, int blockLen, + bool buffer, BufferIterator extBuffer, int extBufferLen, Compare comp) { + int fullMerge = 2 * subarrayLen; + int mergeCount = length / fullMerge; + int lastSubarrays = length - (fullMerge * mergeCount); + + if (lastSubarrays <= subarrayLen) { + length -= lastSubarrays; + lastSubarrays = 0; + } + + // INCOMPLETE CONDITIONAL BUG FIXED: In order to combine blocks out-of-place, we must check if a full-sized + // block fits into our external buffer. + if (buffer && blockLen <= extBufferLen) { + CombineOutOfPlace(array, firstKey, start, length, subarrayLen, blockLen, mergeCount, lastSubarrays, + extBuffer, comp); + } + else { + CombineInPlace(array, firstKey, start, length, subarrayLen, blockLen, + mergeCount, lastSubarrays, buffer, comp); + } + } + + // "Classic" in-place merge sort using binary searches and rotations + // + // cost: min(leftLen, rightLen)^2 + max(leftLen, rightLen) + // MINOR CHANGES: better naming -- 'insertPos' is now 'mergeLen' -- and "middle"/"end" calculations simplified + template + static void LazyMerge(RandomAccessIterator array, int start, int leftLen, int rightLen, Compare comp) { + if (leftLen < rightLen) { + int middle = start + leftLen; + + while (leftLen != 0) { + int mergeLen = BinarySearchLeft(array, middle, rightLen, array[start], comp); + + if (mergeLen != 0) { + Rotate(array, start, leftLen, mergeLen); + start += mergeLen; + rightLen -= mergeLen; + } + + middle += mergeLen; + + if (rightLen == 0) { + break; + } + else { + do { + start++; + leftLen--; + } while (leftLen != 0 && comp(array[start], array[middle]) <= 0); + } + } + } + // INDEXING BUG FIXED: Credit to Anonymous0726 for debugging. + else { + int end = start + leftLen + rightLen - 1; + + + while (rightLen != 0) { + int mergeLen = BinarySearchRight(array, start, leftLen, array[end], comp); + + if (mergeLen != leftLen) { + Rotate(array, start + mergeLen, leftLen - mergeLen, rightLen); + end -= leftLen - mergeLen; + leftLen = mergeLen; + } + + if (leftLen == 0) { + break; + } + else { + int middle = start + leftLen; + do { + rightLen--; + end--; + } while (rightLen != 0 && comp(array[middle - 1], array[end]) <= 0); + } + } + } + } + + template + static void LazyStableSort(RandomAccessIterator array, int start, int length, Compare comp) { + for (int index = 1; index < length; index += 2) { + int left = start + index - 1; + int right = start + index; + + if (comp(array[left], array[right]) > 0) { + std::swap(array[left], array[right]); + } + } + for (int mergeLen = 2; mergeLen < length; mergeLen *= 2) { + int fullMerge = 2 * mergeLen; + + int mergeIndex; + int mergeEnd = length - fullMerge; + + for (mergeIndex = 0; mergeIndex <= mergeEnd; mergeIndex += fullMerge) { + LazyMerge(array, start + mergeIndex, mergeLen, mergeLen, comp); + } + + int leftOver = length - mergeIndex; + if (leftOver > mergeLen) { + LazyMerge(array, start + mergeIndex, mergeLen, leftOver - mergeLen, comp); + } + } + } + + // Calculates the minimum between numKeys and cbrt(2 * subarrayLen * keysFound). + // Math will be further explained later, but just like in CommonSort, this + // loop is rendered completely useless by the scrolling buffer optimization; + // minKeys will always equal numKeys. + // + // Code still here for preservation purposes. + /*static int CalcMinKeys(int numKeys, long halfSubarrKeys) { + int minKeys = 1; + while(minKeys < numKeys && halfSubarrKeys != 0) { + minKeys *= 2; + halfSubarrKeys /= 8; + } + return minKeys; + }*/ + + template + void CommonSort(RandomAccessIterator array, int start, int length, BufferIterator extBuf, int extBufLen, Compare comp) { + if (length < 16) { + InsertSort(array, start, length, comp); + return; + } + + BufferIterator extBuffer = 0; + int extBufferLen = 0; + + int blockLen = 1; + + // find the smallest power of two greater than or equal to + // the square root of the input's length + while ((blockLen * blockLen) < length) { + blockLen *= 2; + } + + // '((a - 1) / b) + 1' is actually a clever and very efficient + // formula for the ceiling of (a / b) + // + // credit to Anonymous0726 for figuring this out! + int keyLen = ((length - 1) / blockLen) + 1; + + // Grailsort is hoping to find `2 * sqrt(n)` unique items + // throughout the array + int idealKeys = keyLen + blockLen; + + //TODO: Clean up `start +` offsets + int keysFound = CollectKeys(array, start, length, idealKeys, comp); + + bool idealBuffer; + if (keysFound < idealKeys) { + if (keysFound == 1) return; + if (keysFound < 4) { + // GRAILSORT STRATEGY 3 -- No block swaps or scrolling buffer; resort to Lazy Stable Sort + LazyStableSort(array, start, length, comp); + return; + } + else { + // GRAILSORT STRATEGY 2 -- Block swaps with small scrolling buffer and/or lazy merges + keyLen = blockLen; + blockLen = 0; + idealBuffer = false; + + while (keyLen > keysFound) { + keyLen /= 2; + } + } + } + else { + // GRAILSORT STRATEGY 1 -- Block swaps with scrolling buffer + idealBuffer = true; + } + + int bufferEnd = blockLen + keyLen; + int subarrayLen; + if (idealBuffer) { + subarrayLen = blockLen; + } + else { + subarrayLen = keyLen; + } + + if (idealBuffer && extBufLen != 0) { + // GRAILSORT + EXTRA SPACE + extBuffer = extBuf; + extBufferLen = extBufLen; + } + + BuildBlocks(array, start + bufferEnd, length - bufferEnd, subarrayLen, + extBuffer, extBufferLen, comp); + + while ((length - bufferEnd) > (2 * subarrayLen)) { + subarrayLen *= 2; + + int currBlockLen = blockLen; + bool scrollingBuffer = idealBuffer; + + // Huge credit to Anonymous0726, phoenixbound, and DeveloperSort for their tireless efforts + // towards deconstructing this math. + if (!idealBuffer) { + int keyBuffer = keyLen / 2; + // TODO: Rewrite explanation for this math + if (keyBuffer >= (2 * subarrayLen) / keyBuffer) { + currBlockLen = keyBuffer; + scrollingBuffer = true; + } + else { + // This is a very recent discovery, and the math will be spelled out later, but this + // "minKeys" calculation is *completely unnecessary*. "minKeys" would be less than + // "keyLen" iff keyBuffer >= (2 * subarrayLen) / keyBuffer... but this situation is + // already covered by our scrolling buffer optimization right above!! Consequently, + // "minKeys" will *always* be equal to "keyLen" when Grailsort resorts to smart lazy + // merges. Removing this loop is by itself a decent optimization, as well! + // + // Code still here for preservation purposes. + /*long halfSubarrKeys = ((long) subarrayLen * keysFound) / 2; + int minKeys = CalcMinKeys(keyLen, halfSubarrKeys);*/ + + currBlockLen = (2 * subarrayLen) / keyLen; + } + } + + // WRONG VARIABLE BUG FIXED: 4th argument should be `length - bufferEnd`, was `length - bufferLen` before. + // Credit to 666666t and Anonymous0726 for debugging. + CombineBlocks(array, start, start + bufferEnd, length - bufferEnd, + subarrayLen, currBlockLen, scrollingBuffer, + extBuffer, extBufferLen, comp); + } + + InsertSort(array, start, bufferEnd, comp); + LazyMerge(array, start, bufferEnd, length - bufferEnd, comp); + } + }; +} + +template< + typename RandomAccessIterator, + typename Compare = std::less<> +> +void grailsort(RandomAccessIterator first, RandomAccessIterator last, Compare comp = {}) +{ + using value_type = typename std::iterator_traits::value_type; + + grailsort_detail::GrailSort gsort; + gsort.CommonSort(first, 0, last - first, + (value_type*)nullptr, 0, + grailsort_detail::ThreeWayCompare(std::move(comp))); +} + +template< + typename RandomAccessIterator1, + typename RandomAccessIterator2, + typename Compare = std::less<> +> +void grailsort(RandomAccessIterator1 first, RandomAccessIterator1 last, + RandomAccessIterator2 buff_first, RandomAccessIterator2 buff_last, + Compare comp = {}) +{ + grailsort_detail::GrailSort gsort; + gsort.CommonSort(first, 0, last - first, + buff_first, buff_last - buff_first, + grailsort_detail::ThreeWayCompare(std::move(comp))); +} + + +void GrailSort(SortArray& A) +{ + grailsort(MyIterator(&A, 0), MyIterator(&A, A.size())); +} +// **************************************************************************** \ No newline at end of file From f7321643bf3134c924a20735ba8a086921248924 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 9 Oct 2024 21:02:50 +0800 Subject: [PATCH 046/289] Allow make to detect Grail Sort --- Makefile | 804 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 804 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..c950dc230 --- /dev/null +++ b/Makefile @@ -0,0 +1,804 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# $Id: Makefile.am 2 2007-01-05 14:04:27Z tb $ + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/sound-of-sorting +pkgincludedir = $(includedir)/sound-of-sorting +pkglibdir = $(libdir)/sound-of-sorting +pkglibexecdir = $(libexecdir)/sound-of-sorting +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-w64-mingw32 +host_triplet = x86_64-w64-mingw32 +target_triplet = x86_64-w64-mingw32 +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir distdir-am dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/acscripts/compile \ + $(top_srcdir)/acscripts/config.guess \ + $(top_srcdir)/acscripts/config.sub \ + $(top_srcdir)/acscripts/install-sh \ + $(top_srcdir)/acscripts/missing AUTHORS COPYING README.md \ + acscripts/compile acscripts/config.guess acscripts/config.sub \ + acscripts/depcomp acscripts/install-sh acscripts/missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' aclocal-1.16 +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +AUTOCONF = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoconf +AUTOHEADER = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoheader +AUTOMAKE = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' automake-1.16 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -Wno-unused-local-typedefs +CPPFLAGS = +CSCOPE = cscope +CTAGS = ctags +CXX = g++ +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -Wno-unused-local-typedefs +CYGPATH_W = cygpath -w +DEFS = -DPACKAGE_NAME=\"sound-of-sorting\" -DPACKAGE_TARNAME=\"sound-of-sorting\" -DPACKAGE_VERSION=\"0.6.5\" -DPACKAGE_STRING=\"sound-of-sorting\ 0.6.5\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"sound-of-sorting\" -DVERSION=\"0.6.5\" -DMSW_PERFORMANCECOUNTER=1 +DEPDIR = .deps +ECHO_C = +ECHO_N = -n +ECHO_T = +ETAGS = etags +EXEEXT = .exe +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LDFLAGS = +LIBOBJS = +LIBS = +LTLIBOBJS = +MAINT = # +MAKEINFO = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' makeinfo +MKDIR_P = /usr/bin/mkdir -p +OBJEXT = o +PACKAGE = sound-of-sorting +PACKAGE_BUGREPORT = +PACKAGE_NAME = sound-of-sorting +PACKAGE_STRING = sound-of-sorting 0.6.5 +PACKAGE_TARNAME = sound-of-sorting +PACKAGE_URL = +PACKAGE_VERSION = 0.6.5 +PATH_SEPARATOR = : +PKG_CONFIG = /mingw64/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = /mingw64/lib/pkgconfig:/mingw64/share/pkgconfig +RANLIB = ranlib +SDL2_CONFIG = /mingw64/bin/pkg-config sdl2 +SDL2_FRAMEWORK = +SDL_CFLAGS = -IC:/msys64/mingw64/include/SDL2 -Dmain=SDL_main +SDL_LIBS = -lmingw32 -mwindows -lSDL2main -lSDL2 +SET_MAKE = +SHELL = /bin/sh +STRIP = +VERSION = 0.6.5 +WX_CFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_CFLAGS_ONLY = +WX_CONFIG_PATH = /mingw64/bin/wx-config +WX_CPPFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_CXXFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_CXXFLAGS_ONLY = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_LIBS = -L/mingw64/lib -Wl,--subsystem,windows -mwindows -lwx_mswu_core-3.2 -lwx_baseu-3.2 +WX_LIBS_STATIC = -LC:/msys64/mingw64/lib -pipe -Wl,--subsystem,windows -mwindows C:/msys64/mingw64/lib/libwx_mswu_adv-3.0.a C:/msys64/mingw64/lib/libwx_mswu_core-3.0.a C:/msys64/mingw64/lib/libwx_baseu-3.0.a -lwxregexu-3.0 -lwxexpat-3.0 -lwxtiff-3.0 -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 -lrpcrt4 -loleaut32 -lole32 -luuid -llzma -ljbig -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 -loleacc +WX_RESCOMP = windres --include-dir /mingw64/include/wx-3.2 --define __WIN32__ --define __GNUWIN32__ --define WX_CPU_AMD64 +WX_VERSION = 3.2.6 +WX_VERSION_MAJOR = 3 +WX_VERSION_MICRO = 6 +WX_VERSION_MINOR = 2 +abs_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master +abs_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master +abs_top_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master +abs_top_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master +ac_ct_CC = gcc +ac_ct_CXX = g++ +am__include = include +am__leading_dot = . +am__quote = +am__tar = $${TAR-tar} chof - "$$tardir" +am__untar = $${TAR-tar} xf - +bindir = ${exec_prefix}/bin +build = x86_64-w64-mingw32 +build_alias = x86_64-w64-mingw32 +build_cpu = x86_64 +build_os = mingw32 +build_vendor = w64 +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +host = x86_64-w64-mingw32 +host_alias = +host_cpu = x86_64 +host_os = mingw32 +host_vendor = w64 +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +prefix = /mingw64 +program_transform_name = s,x,x, +psdir = ${docdir} +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = ${prefix}/etc +target = x86_64-w64-mingw32 +target_alias = +target_cpu = x86_64 +target_os = mingw32 +target_vendor = w64 +top_build_prefix = +top_builddir = . +top_srcdir = . +SUBDIRS = src +EXTRA_DIST = \ + README.md + +all: all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: # $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): # $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-zstd: distdir + tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + *.tar.zst*) \ + zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ + dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ + dist-zstd distcheck distclean distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: From d12c160600664015b4c1409c52cf9174b7539554 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 9 Oct 2024 21:09:11 +0800 Subject: [PATCH 047/289] Allow make to detect Grail Sort --- Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index c950dc230..60b3e7545 100644 --- a/Makefile +++ b/Makefile @@ -207,12 +207,12 @@ distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print -ACLOCAL = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' aclocal-1.16 +ACLOCAL = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' aclocal-1.16 AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 1 -AUTOCONF = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoconf -AUTOHEADER = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoheader -AUTOMAKE = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' automake-1.16 +AUTOCONF = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' autoconf +AUTOHEADER = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' autoheader +AUTOMAKE = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' automake-1.16 AWK = gawk CC = gcc CCDEPMODE = depmode=gcc3 @@ -241,7 +241,7 @@ LIBOBJS = LIBS = LTLIBOBJS = MAINT = # -MAKEINFO = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' makeinfo +MAKEINFO = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' makeinfo MKDIR_P = /usr/bin/mkdir -p OBJEXT = o PACKAGE = sound-of-sorting @@ -277,10 +277,10 @@ WX_VERSION = 3.2.6 WX_VERSION_MAJOR = 3 WX_VERSION_MICRO = 6 WX_VERSION_MINOR = 2 -abs_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master -abs_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master -abs_top_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master -abs_top_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master +abs_builddir = /c/Users/louwe/Desktop/soundofsortingfork +abs_srcdir = /c/Users/louwe/Desktop/soundofsortingfork +abs_top_builddir = /c/Users/louwe/Desktop/soundofsortingfork +abs_top_srcdir = /c/Users/louwe/Desktop/soundofsortingfork ac_ct_CC = gcc ac_ct_CXX = g++ am__include = include @@ -308,7 +308,7 @@ host_vendor = w64 htmldir = ${docdir} includedir = ${prefix}/include infodir = ${datarootdir}/info -install_sh = ${SHELL} /c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/install-sh +install_sh = ${SHELL} /c/Users/louwe/Desktop/soundofsortingfork/acscripts/install-sh libdir = ${exec_prefix}/lib libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale From 962cc60796cd0b78c74664c725b7221e264aa374 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 10 Oct 2024 18:13:48 +0800 Subject: [PATCH 048/289] Added Bad Sort, and 2 new input types Credits to @MusicTheorist for the Quicksort Killer input --- src/SortAlgo.cpp | 33 ++++++++++++++++++++++++++++--- src/SortAlgo.h | 1 + src/SortArray.cpp | 50 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 6fb5de561..4190f0ec7 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -60,8 +60,7 @@ const struct AlgoEntry g_algolist[] = { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Merge Sort"), &MergeSort, UINT_MAX, 512, - _("Merge sort which merges two sorted sequences into a shadow array," - "and then copies it back to the shown array.") }, + _("Merge sort which merges two sorted sequences into a shadow array, and then copies it back to the shown array.") }, { _("Merge Sort (iterative)"), &MergeSortIterative, UINT_MAX, 512, _("Merge sort variant which iteratively merges " "subarrays of sizes of powers of two.") }, @@ -139,7 +138,9 @@ const struct AlgoEntry g_algolist[] = { _("Stooge Sort"), &StoogeSort, 256, inversion_count_instrumented, wxEmptyString }, { _("Slow Sort"), &SlowSort, 128, inversion_count_instrumented, - wxEmptyString } + wxEmptyString }, + { _("Bad Sort"), &BadSort, 128, inversion_count_instrumented, + _("A humorous sorting algorithm with the time complexity of O(n^3).") } }; const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); @@ -1862,6 +1863,32 @@ void StoogeSort(SortArray& A) StoogeSort(A, 0, A.size()-1); } +void BadSort(SortArray& A) +{ + for (size_t i = 0; i < A.size(); i++) + { + size_t shortest = i; + for (size_t j = i; j < A.size(); j++) + { + bool isShortest = true; + for (size_t k = j + 1; k < A.size(); k++) + { + if (A[j] > A[k]) + { + isShortest = false; + break; + } + } + if (isShortest) + { + shortest = j; + break; + } + } + A.swap(i, shortest); + } +} + // **************************************************************************** // *** Slow Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index b418caef8..8474d448d 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -102,6 +102,7 @@ void TimSort(class SortArray& a); void WikiSort(class SortArray& a); void GrailSort(class SortArray& a); +void BadSort(class SortArray& a); void BogoSort(class SortArray& a); void BozoSort(class SortArray& a); void StoogeSort(class SortArray& a); diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b9a9b79d0..402c63632 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -124,6 +124,8 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Wave")); list.Add(_("Sawtooth")); list.Add(_("Reverse Sawtooth")); + list.Add(_("Many Similar")); + list.Add(_("Quicksort Killer")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -312,9 +314,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } else if (schema == 16) // Sawtooth { - int teeth = sqrt(m_array.size()) / 7; - if (teeth <= 1) { teeth = 2; } - int max = m_array.size() / teeth; + int max = m_array.size() / 4; int count = 1; for (size_t i = 0; i < m_array.size(); ++i) { @@ -325,9 +325,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } else if (schema == 17) // Reverse Sawtooth { - int teeth = sqrt(m_array.size()) / 7; - if (teeth <= 1) { teeth = 2; } - int max = m_array.size() / teeth; + int max = m_array.size() / 4; int count = max; for (size_t i = 0; i < m_array.size(); ++i) { @@ -336,6 +334,46 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) --count; } } + else if (schema == 18) // Many Similar + { + size_t group_count = 0; + size_t size = m_array.size(); + if (size % 10 == 0) { group_count = 10; } + else if (size % 9 == 0) { group_count = 9; } + else if (size % 8 == 0) { group_count = 8; } + else if (size % 7 == 0) { group_count = 7; } + else if (size % 6 == 0) { group_count = 6; } + else if (size % 5 == 0) { group_count = 5; } + else if (size % 4 == 0) { group_count = 4; } + else if (size % 2 != 0) { group_count = 3; } + else { group_count = 2; } + + size_t repeat = 1; + int val = 1; + for (size_t i = 0; i < size; ++i) + { + if (repeat > group_count) + { ++val; repeat = 1; } + m_array[i] = ArrayItem(val); + ++repeat; + } + std::shuffle(m_array.begin(), m_array.end(), g); + } + else if (schema == 19) // Quicksort Killer + { + int currentLen = m_array.size(); + for (int i = 0; i < currentLen; ++i) + { + m_array[i] = ArrayItem(i + 1); + } + for (int j = currentLen - currentLen % 2 - 2, i = j - 1; i >= 0; i -= 2, j--) + { + ArrayItem temp = m_array[i]; + m_array[i] = m_array[j]; + m_array[j] = temp; + } + + } else // fallback { return FillData(0, arraysize); From 4ffe61899d2ec9662d4b94fa9aebb42a61f9a73e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 10 Oct 2024 20:15:39 +0800 Subject: [PATCH 049/289] Added In-Place Radix Sort, Base 10 Credits to @w0rthy, and "The Studio" Discord channel for teaching me how the major methods work! --- src/SortAlgo.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++-- src/SortAlgo.h | 1 + 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 4190f0ec7..0c5386049 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -39,6 +39,7 @@ #include #include #include +#include typedef ArrayItem value_type; @@ -113,6 +114,8 @@ const struct AlgoEntry g_algolist[] = { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, _("Least significant digit radix sort, which copies item into a shadow " "array during counting.") }, + { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, UINT_MAX, + _("Least significant digit radix sort, performed in O(1) space.") }, { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, @@ -140,7 +143,7 @@ const struct AlgoEntry g_algolist[] = { _("Slow Sort"), &SlowSort, 128, inversion_count_instrumented, wxEmptyString }, { _("Bad Sort"), &BadSort, 128, inversion_count_instrumented, - _("A humorous sorting algorithm with the time complexity of O(n^3).") } + _("A humorous sorting algorithm with a time complexity of O(n^3).") } }; const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); @@ -1197,6 +1200,74 @@ void RadixSortLSD(SortArray& A) } } +void shiftElement(SortArray& A, size_t start, size_t end) +{ + if (start < end) + { + while (start < end) + { + A[start].get(); + A.swap(start, start + 1); + ++start; + } + } + else + { + while (start > end) + { + A[start].get(); + A.swap(start, start - 1); + --start; + } + } +} + +size_t maxLog(SortArray& A, size_t n, size_t base) +{ + int max = A[0]; + for (size_t i = 0, j = n - 1; i <= j; ++i, --j) + { + int ele1 = A[i].get(), ele2 = A[j]; + if (ele1 > max) { max = A[i]; } + if (ele2 > max) { max = A[j]; } + } + size_t digit = static_cast(log(max) / log(base)); + return digit; +} + +int getDigit(int a, double power, int radix) +{ + double digit = (a / static_cast(pow(radix, power)) % radix); + return static_cast(digit); +} + +void InPlaceRadixSortLSD(SortArray& A) +{ + size_t pos = 0, n = A.size(); + size_t bucket = 10; + std::vector buckets(bucket - 1, 0); + size_t maxPow = maxLog(A, n, bucket); + for (size_t p = 0; p <= maxPow; ++p) + { + for (size_t i = 0; i < buckets.size(); ++i) { buckets[i] = n - 1; } + pos = 0; + for (size_t i = 0; i < n; ++i) + { + int ele = A[pos].get(); + int digit = getDigit((int)ele, (double)p, (int)bucket); + if (digit == 0) { ++pos; } + else + { + shiftElement(A, pos, buckets[digit - 1]); + for (size_t j = digit - 1; j > 0; --j) + { + buckets[j - 1] = buckets[j - 1] - 1; + } + } + } + } +} + // **************************************************************************** // *** Use STL Sorts via Iterator Adapters @@ -1362,7 +1433,7 @@ void GravitySort(SortArray& A) { max = m; } } - std::vector> beads(len, std::vector(max, 0));; + std::vector> beads(len, std::vector(max, 0)); for (int i = 0; i < len; ++i) { diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 8474d448d..96e4181f4 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -91,6 +91,7 @@ void BitonicSort(SortArray& a); void BitonicSortNetwork(SortArray& a); void BatcherSortNetwork(SortArray& a); +void InPlaceRadixSortLSD(class SortArray& a); void RadixSortLSD(class SortArray& a); void RadixSortMSD(class SortArray& a); From 2297869e3d02973c955ed3add97a21a376ef2b35 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 10 Oct 2024 21:03:21 +0800 Subject: [PATCH 050/289] In-Place Radix Sort LSD code cleanup --- src/SortAlgo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 0c5386049..52bb5635e 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1225,7 +1225,7 @@ void shiftElement(SortArray& A, size_t start, size_t end) size_t maxLog(SortArray& A, size_t n, size_t base) { int max = A[0]; - for (size_t i = 0, j = n - 1; i <= j; ++i, --j) + for (size_t i = 1, j = n - 1; i <= j; ++i, --j) { int ele1 = A[i].get(), ele2 = A[j]; if (ele1 > max) { max = A[i]; } @@ -1244,7 +1244,7 @@ int getDigit(int a, double power, int radix) void InPlaceRadixSortLSD(SortArray& A) { size_t pos = 0, n = A.size(); - size_t bucket = 10; + int bucket = 20; std::vector buckets(bucket - 1, 0); size_t maxPow = maxLog(A, n, bucket); for (size_t p = 0; p <= maxPow; ++p) @@ -1254,7 +1254,7 @@ void InPlaceRadixSortLSD(SortArray& A) for (size_t i = 0; i < n; ++i) { int ele = A[pos].get(); - int digit = getDigit((int)ele, (double)p, (int)bucket); + int digit = getDigit(ele, (double)p, bucket); if (digit == 0) { ++pos; } else { From 5d364ec2b9b2c75272aa8837d135dfd25d091ee5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 11 Oct 2024 01:36:19 +0800 Subject: [PATCH 051/289] (Experimental) Aggressive bar width downscaling This change allows the application to display as much as 8192 elements without the visualization going past the screen borders. It is possible to go past 8192 elements, but the application will lag at this point. 0.2 downscaling will not work for displaying large array sizes, 0.1 downscaling will allow displaying up to 12000 array elements, but again, this will cause huge lag. --- src/SortTest.cpp | 6 ++---- src/WSortView.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SortTest.cpp b/src/SortTest.cpp index 1bc75ffb4..098ae2134 100644 --- a/src/SortTest.cpp +++ b/src/SortTest.cpp @@ -53,10 +53,8 @@ bool SortTestApp::OnInit() } static size_t testsize[] = { - 10, 11, 12, 13, 14, 15, 16, 32, - 100, 101, 102, 103, 200, - 1024, 1337, 2048, - 0 + 10, 11, 12, 13, 14, 15, 16, 32, 100, 101, 102, 103, 200, 1024, 1337, 1600, 2048, 2500, + 3072, 3500, 4096, 4500, 5000, 5600, 6144, 6500, 7000, 7500, 8192, 0 }; struct SortedCheck diff --git a/src/WSortView.cpp b/src/WSortView.cpp index b11542ba8..bec0ae660 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -170,10 +170,12 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) //double bstep = 1.5 * wbar; // 2nd variant: one pixel between bars - double wbar = (width - (size-1)) / (double)size; - if (width <= (size-1)) wbar = 0.0; - + double wbar = wxMax(1.0, (width - (size - 1)) / (double)size); double bstep = wbar + 1.0; + if (size > width) { + wbar = wxMax(0.1, width / (double)size); // Scale down further if too many elements + bstep = wbar; + } // special case for bstep = 2 pixel -> draw 2 pixel bars instead of 1px // bar/1px gaps. From 8f43d74ccb08be3c13ae85bef6b29a763cf95ca2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 11 Oct 2024 01:38:02 +0800 Subject: [PATCH 052/289] Allow array size slider to go up to 8192 elements This change complements the aggressive bar width downscaling change. --- src/wxg/WMain_wxg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index b2f4bdba5..86f0b42b8 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -44,7 +44,7 @@ WMain_wxg::WMain_wxg(wxWindow* parent, int id, const wxString& title, const wxPo labelRunsCount = new wxClickText(splitter_0_pane_2, wxID_ANY, wxEmptyString); const wxString *inputTypeChoice_choices = NULL; inputTypeChoice = new wxChoice(splitter_0_pane_2, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, inputTypeChoice_choices, 0); - arraySizeSlider = new wxSlider(splitter_0_pane_2, ID_ARRAY_SIZE_SLIDER, 0, 1, 2048); + arraySizeSlider = new wxSlider(splitter_0_pane_2, ID_ARRAY_SIZE_SLIDER, 0, 1, 8192); labelArraySizeValue = new wxStaticText(splitter_0_pane_2, wxID_ANY, _("1024"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE|wxST_NO_AUTORESIZE); const wxString *algoList_choices = NULL; algoList = new wxListBox(splitter_0_pane_2, ID_ALGO_LIST, wxDefaultPosition, wxDefaultSize, 0, algoList_choices, wxLB_SINGLE); From 629c7d0440e7f1e316ee4e00a636d2754e79b200 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 11 Oct 2024 13:17:52 +0800 Subject: [PATCH 053/289] Aggressive bar width downscale fix Reverted the normal calculation back to the original formula, this gives the best of both worlds. Array sizes within the 1000 range will not upscale past the application window border, and array sizes of 2000 and above will also never go past the window border. This should stabilize the aggressive downscale solution even more. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index bec0ae660..2809dc40c 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -170,7 +170,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) //double bstep = 1.5 * wbar; // 2nd variant: one pixel between bars - double wbar = wxMax(1.0, (width - (size - 1)) / (double)size); + double wbar = (width - (size - 1)) / (double)size; double bstep = wbar + 1.0; if (size > width) { wbar = wxMax(0.1, width / (double)size); // Scale down further if too many elements From ec45b49c2cbfc8142271543e65fa68b043d5ea5e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 00:40:38 +0800 Subject: [PATCH 054/289] Fixed code warnings This introduces some corrections: 1. The SoundCallback() method is not apparently being detected, even if it is declared in SortSound.cpp, the reason for this is because the middle argument on the declaration of SoundCallback() is different compared to how it is defined in SortSound.cpp. Even if unsigned char is the same as Uint8, C++ still treats the 2 types as different, hence it says that SoundCallback() cannot be found. Therefore, the SoundCallback() declaration should match its definition, which is what this change introduces. 2. The constructor for SortAlgoThread is apparently not being detected properly by WSortView.h, even if it is properly declared in WSortView.cpp, the apparent cause of this is because there are 2 missing semicolons, one from the class declaration, and one from the END_EVENT_TABLE() above the constructor declaration. This change adds this 2 missing semicolons, making the constructor declaration to be finally detected. 3. DECLARE_EVENT_TABLE() apparently should not have a semicolon. Before, DECLARE_EVENT_TABLE() is not being detected because there is a semicolon after it, which is wrong. This change removes those semicolons so that DECLARE_EVENT_TABLE() is now finally detected. --- src/WMain.h | 3 +-- src/WSortView.cpp | 32 ++++++++++++++++---------------- src/WSortView.h | 6 +++--- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/WMain.h b/src/WMain.h index b77d47f2b..f04e5e32e 100644 --- a/src/WMain.h +++ b/src/WMain.h @@ -87,8 +87,7 @@ class WMain : public WMain_wxg virtual void OnAlgoListDClick(wxCommandEvent &event); virtual void OnRunFinished(wxCommandEvent&); - - DECLARE_EVENT_TABLE(); + DECLARE_EVENT_TABLE() public: diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 2809dc40c..1e9d731ba 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -158,7 +158,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) size_t width = fwidth - 20; size_t height = fheight - 20; - dc.SetDeviceOrigin(10,10); + dc.SetDeviceOrigin(10, 10); // *** draw array element bars @@ -179,7 +179,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) // special case for bstep = 2 pixel -> draw 2 pixel bars instead of 1px // bar/1px gaps. - if ( fabs(wbar - 1.0) < 0.1 && fabs(bstep - 2.0) < 0.1 ) wbar = 2, bstep = 2; + if (fabs(wbar - 1.0) < 0.1 && fabs(bstep - 2.0) < 0.1) wbar = 2, bstep = 2; static const wxPen pens[] = { *wxWHITE_PEN, @@ -229,29 +229,29 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) int clr = m_array.GetIndexColor(i); ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); - dc.SetPen( pens[clr] ); - dc.SetBrush( brushes[clr] ); - - dc.DrawRectangle(i*bstep, height, - wxMax(1, // draw at least 1 pixel - (wxCoord((i+1)*bstep) - wxCoord(i*bstep)) // integral gap to next bar - - (bstep - wbar) // space between bars - ), - -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); + dc.SetPen(pens[clr]); + dc.SetBrush(brushes[clr]); + + dc.DrawRectangle(i * bstep, height, + wxMax(1, // draw at least 1 pixel + (wxCoord((i + 1) * bstep) - wxCoord(i * bstep)) // integral gap to next bar + - (bstep - wbar) // space between bars + ), + -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); } -} +}; BEGIN_EVENT_TABLE(WSortView, wxWindow) - EVT_PAINT (WSortView::OnPaint) - EVT_SIZE (WSortView::OnSize) + EVT_PAINT(WSortView::OnPaint) + EVT_SIZE(WSortView::OnSize) -END_EVENT_TABLE() +END_EVENT_TABLE(); // **************************************************************************** // *** Threading -SortAlgoThread::SortAlgoThread(WMain* wmain, class WSortView& sortview, size_t algo) +SortAlgoThread::SortAlgoThread(WMain* wmain, WSortView& sortview, size_t algo) : wxThread(wxTHREAD_JOINABLE), m_wmain(wmain), m_sortview(sortview), diff --git a/src/WSortView.h b/src/WSortView.h index da5f0f064..5dfca59e1 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -25,7 +25,7 @@ #define WSORTVIEW_H #include - +#include #include "SortArray.h" // ---------------------------------------------------------------------------- @@ -37,7 +37,7 @@ extern bool g_sound_on; extern double g_sound_sustain; /// the SDL sound callback -void SoundCallback(void *udata, unsigned char *stream, int len); +void SoundCallback(void *udata, Uint8* stream, int len); /// reset internal state of sound generator void SoundReset(); @@ -99,7 +99,7 @@ class WSortView : public wxPanel, public SortDelay void DoStepwise(); public: - DECLARE_EVENT_TABLE(); + DECLARE_EVENT_TABLE() }; // ---------------------------------------------------------------------------- From f2a488477d1e1762194b83555833abac96829fcd Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 01:25:38 +0800 Subject: [PATCH 055/289] Code warnings fix change I apparently discovered that including SDL.h on WSortView.h could cause redundant includes when it is included on other files, even if there are include guards. Since Uint8 and unsigned char are the same, SDL is fine with unsigned char, I simply made the definition of SoundCallback() in SortSound.cpp to also use unsigned char, avoiding code warnings due to code definition and declaration mismatch, while being a little closer to how the original code looks like. --- SortSound.cpp | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++ WSortView.h | 124 +++++++++++++++++++ 2 files changed, 456 insertions(+) create mode 100644 SortSound.cpp create mode 100644 WSortView.h diff --git a/SortSound.cpp b/SortSound.cpp new file mode 100644 index 000000000..dec5fdbdc --- /dev/null +++ b/SortSound.cpp @@ -0,0 +1,332 @@ +/****************************************************************************** + * src/SortSound.cpp + * + * This file contains the audio callback which generates all sound. + * + * The sound is created by mixing many many oscillators, whose freqencies are + * defined by the values compared. Each comparison adds two oscillators. + * + * In the final version the oscillators generate a triangular waveform and are + * enveloped using a ADSR function. The total time an oscillator yields sound + * is defined by the "Sound Sustain" user slider. + * + * The callback function also automatically scales the volume when many + * oscillators overlap. In effect, this is dynamic range compression. + * + ****************************************************************************** + * Copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#include "WSortView.h" +#include +#include + +// *** All time counters in the sound system are in sample units. + +static const size_t s_samplerate = 44100; + +/// global sound on/off switch +bool g_sound_on = false; + +/// multiplying g_delay with this value yields the duration a sound is sustained +double g_sound_sustain = 2.0; + +/// limit the number of oscillators to avoid overloading the callback +static const size_t s_max_oscillators = 512; + +/// Oscillator generating sine or triangle waves +class Oscillator +{ +protected: + /// frequency of generated wave + double m_freq; + + /// start and end of wave in sample time + size_t m_tstart, m_tend; + + /// duration of oscillation note + size_t m_duration; + +public: + /// construct new oscillator + Oscillator(double freq, size_t tstart, size_t duration = 44100 / 8) + : m_freq(freq), m_tstart(tstart), + m_tend( m_tstart + duration ), + m_duration(duration) + { + } + + // *** Wave Forms + + /// simple sine wave + static double wave_sin(double x) + { + return sin(x * 2*M_PI); + } + + /// sin^3 wave + static double wave_sin3(double x) + { + double s = sin(x * 2*M_PI); + return s * s * s; + } + + /// triangle wave + static double wave_triangle(double x) + { + x = fmod(x, 1.0); + + if (x <= 0.25) return 4.0 * x; + if (x <= 0.75) return 2.0 - 4.0 * x; + return 4.0 * x - 4.0; + } + + /// picking a waveform + static double wave(double x) + { + //return wave_sin(x); + //return wave_sin3(x); + return wave_triangle(x); + } + + // *** Envelope + + /// envelope applied to wave (uses ADSR) + double envelope(size_t i) const + { + double x = (double)i / m_duration; + if (x > 1.0) x = 1.0; + + // simple envelope functions: + + //return 1.0 - x; + //return cos(M_PI_2 * x); + + // *** ADSR envelope + + static const double attack = 0.025; // percentage of duration + static const double decay = 0.1; // percentage of duration + static const double sustain = 0.9; // percentage of amplitude + static const double release = 0.3; // percentage of duration + + if (x < attack) + return 1.0 / attack * x; + + if (x < attack + decay) + return 1.0 - (x - attack) / decay * (1.0 - sustain); + + if (x < 1.0 - release) + return sustain; + + return sustain / release * (1.0 - x); + } + + // *** Generate Wave and Mix + + /// mix in the output of this oscillator on the wave output + void mix(double* data, int size, size_t p) const + { + for (int i = 0; i < size; ++i) + { + if (p+i < m_tstart) continue; + if (p+i >= m_tend) break; + + size_t trel = (p + i - m_tstart); + + data[i] += envelope(trel) * wave((double)trel / s_samplerate * m_freq); + } + } + + /// return start time + size_t tstart() const + { return m_tstart; } + + /// true if the oscillator is silent at time p + bool is_done(size_t p) const + { + return (p >= m_tend); + } +}; + +/// array of oscillators +static std::vector s_osclist; + +/// global timestamp of callback in sound sample units +static size_t s_pos = 0; + +/// add an oscillator to the list (reuse finished ones) +static void add_oscillator(double freq, size_t p, size_t pstart, size_t duration) +{ + // find free oscillator + size_t oldest = 0, toldest = std::numeric_limits::max(); + for (size_t i = 0; i < s_osclist.size(); ++i) + { + if (s_osclist[i].is_done(p)) + { + s_osclist[i] = Oscillator(freq, pstart, duration); + return; + } + + if (s_osclist[i].tstart() < toldest) { + oldest = i; + toldest = s_osclist[i].tstart(); + } + } + + if (s_osclist.size() < s_max_oscillators) + { + // add new one + s_osclist.push_back( Oscillator(freq, pstart, duration) ); + } + else + { + // replace oldest oscillator + s_osclist[oldest] = Oscillator(freq, pstart, duration); + } +} + +/// list of array accesses since last callback +static std::vector s_access_list; + +// mutex to s_access_list +static wxMutex s_mutex_access_list; + +/// "public" function to add a new array access +void SoundAccess(size_t i) +{ + if (!g_sound_on) return; + + wxMutexLocker lock(s_mutex_access_list); + ASSERT(lock.IsOk()); + + s_access_list.push_back(i); +} + +/// function mapping array index (normalized to [0,1]) to frequency +static double arrayindex_to_frequency(double aindex) +{ + return 120 + 1200 * (aindex*aindex); +} + +/// reset internal sound data (called from main thread) +void SoundReset() +{ + wxMutexLocker lock(s_mutex_access_list); + ASSERT(lock.IsOk()); + + s_pos = 0; + s_osclist.clear(); +} + +/// sound generator callback run by SDL +void SoundCallback(void* udata, unsigned char* stream, int len) +{ + if (!g_sound_on) { + memset(stream, 0, len); + return; + } + + // current sample time (32-bit size_t wraps after 27 hours, 64-bit size_t + // wraps after 13 million years). + size_t& p = s_pos; + + // reference to sortview + WSortView& sv = *reinterpret_cast(udata); + + // we use 16-bit mono output at 44.1 kHz + int16_t* data = (int16_t*)stream; + size_t size = len / sizeof(int16_t); + + // fetch new access list and create oscillators + { + wxMutexLocker lock(s_mutex_access_list); + ASSERT(lock.IsOk()); + + // spread out access list over time of one callback + double pscale = (double)size / s_access_list.size(); + + for (size_t i = 0; i < s_access_list.size(); ++i) + { + double relindex = s_access_list[i] / (double)sv.m_array.array_max(); + double freq = arrayindex_to_frequency(relindex); + + add_oscillator( freq, p, p + i * pscale, + g_delay / 1000.0 * g_sound_sustain * s_samplerate ); + } + + s_access_list.clear(); + } + + // calculate waveform + std::vector wave(size, 0.0); + size_t wavecount = 0; + + for (std::vector::const_iterator it = s_osclist.begin(); + it != s_osclist.end(); ++it) + { + if (!it->is_done(p)) + { + it->mix(wave.data(), size, p); + ++wavecount; + } + } + + // scale output with number of waves mixed + + if (wavecount == 0) + { + // set zero, the function below messes up when vol = 0.0 + memset(stream, 0, len); + } + else + { + // count maximum wave amplitude + double vol = *std::max_element(wave.begin(), wave.end()); + + static double oldvol = 1.0; + + if (vol > oldvol) { + // immediately ramp down volume + } + else { + // but slowly ramp up volume + vol = 0.9 * oldvol; + } + + // convert waveform to samples, with ramping of volume + + for (size_t i = 0; i < size; ++i) + { + int32_t v = 24000.0 * wave[i] / (oldvol + (vol - oldvol) * (i / (double)size)); + + if (v > 32200) { + //std::cout << "clip " << p << "\n"; + v = 32200; + } + if (v < -32200) { + //std::cout << "clip " << p << "\n"; + v = -32200; + } + + data[i] = v; + } + + oldvol = vol; + } + + // advance sample timestamp + p += size; +} diff --git a/WSortView.h b/WSortView.h new file mode 100644 index 000000000..8d6105046 --- /dev/null +++ b/WSortView.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * src/WSortView.h + * + * WSortView contains both the instrumentated array operators and draws the + * displayed visualization. + * + ****************************************************************************** + * Copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#ifndef WSORTVIEW_H +#define WSORTVIEW_H + +#include +#include "SortArray.h" + +// ---------------------------------------------------------------------------- + +/// global sound processing on/off +extern bool g_sound_on; + +/// multiplying g_delay with this value yields the duration a sound is sustained +extern double g_sound_sustain; + +/// the SDL sound callback +void SoundCallback(void *udata, unsigned char* stream, int len); + +/// reset internal state of sound generator +void SoundReset(); + +/// append access to start output in next sound callback +void SoundAccess(size_t i); + +// ---------------------------------------------------------------------------- + +/// global delay for one step +extern double g_delay; + +/// global flag when algorithm is running +extern bool g_algo_running; + +/// global string of running algorithm +extern wxString g_algo_name; + +class WSortView : public wxPanel, public SortDelay +{ +public: + WSortView(wxWindow *parent, int id, class WMain_wxg* wmain); + ~WSortView(); + + /// reference to WMain + class WMain* wmain; + + /// the instrumentated array to sort + SortArray m_array; + + void RepaintNow(); + + virtual void OnPaint(wxPaintEvent& pe); + virtual void OnSize(wxSizeEvent& se); + + // paint the visualization, (dcsize is passed along due to wxMSW issues) + void paint(wxDC& dc, const wxSize& dcsize); + + /// central access function called by each array access of the algorithms + virtual void OnAccess(); + + /// delay algorithm time by this amount + void DoDelay(double delay); + +protected: + + /// flag for step-wise processing (idle while true) + bool m_stepwise; + + /// semaphore for signaling steps from main thread + wxSemaphore m_step_semaphore; + +public: + + /// set stepwise processing for Step button + void SetStepwise(bool v) { m_stepwise = v; } + + /// stepwise processing for Step button + void DoStepwise(); + +public: + DECLARE_EVENT_TABLE() +}; + +// ---------------------------------------------------------------------------- + +class SortAlgoThread : public wxThread { +protected: + class WMain* m_wmain; + class WSortView& m_sortview; + + size_t m_algo; + +public: + + SortAlgoThread(class WMain* wmain, class WSortView& sortview, size_t algo); + + virtual ExitCode Entry(); + + void Exit(); +}; + +// ---------------------------------------------------------------------------- + +#endif // WSORTVIEW_H From e32ae7cad2fc17a17a7968b0e20762a32b3d51ba Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 01:26:15 +0800 Subject: [PATCH 056/289] Delete SortSound.cpp --- SortSound.cpp | 332 -------------------------------------------------- 1 file changed, 332 deletions(-) delete mode 100644 SortSound.cpp diff --git a/SortSound.cpp b/SortSound.cpp deleted file mode 100644 index dec5fdbdc..000000000 --- a/SortSound.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/****************************************************************************** - * src/SortSound.cpp - * - * This file contains the audio callback which generates all sound. - * - * The sound is created by mixing many many oscillators, whose freqencies are - * defined by the values compared. Each comparison adds two oscillators. - * - * In the final version the oscillators generate a triangular waveform and are - * enveloped using a ADSR function. The total time an oscillator yields sound - * is defined by the "Sound Sustain" user slider. - * - * The callback function also automatically scales the volume when many - * oscillators overlap. In effect, this is dynamic range compression. - * - ****************************************************************************** - * Copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#include "WSortView.h" -#include -#include - -// *** All time counters in the sound system are in sample units. - -static const size_t s_samplerate = 44100; - -/// global sound on/off switch -bool g_sound_on = false; - -/// multiplying g_delay with this value yields the duration a sound is sustained -double g_sound_sustain = 2.0; - -/// limit the number of oscillators to avoid overloading the callback -static const size_t s_max_oscillators = 512; - -/// Oscillator generating sine or triangle waves -class Oscillator -{ -protected: - /// frequency of generated wave - double m_freq; - - /// start and end of wave in sample time - size_t m_tstart, m_tend; - - /// duration of oscillation note - size_t m_duration; - -public: - /// construct new oscillator - Oscillator(double freq, size_t tstart, size_t duration = 44100 / 8) - : m_freq(freq), m_tstart(tstart), - m_tend( m_tstart + duration ), - m_duration(duration) - { - } - - // *** Wave Forms - - /// simple sine wave - static double wave_sin(double x) - { - return sin(x * 2*M_PI); - } - - /// sin^3 wave - static double wave_sin3(double x) - { - double s = sin(x * 2*M_PI); - return s * s * s; - } - - /// triangle wave - static double wave_triangle(double x) - { - x = fmod(x, 1.0); - - if (x <= 0.25) return 4.0 * x; - if (x <= 0.75) return 2.0 - 4.0 * x; - return 4.0 * x - 4.0; - } - - /// picking a waveform - static double wave(double x) - { - //return wave_sin(x); - //return wave_sin3(x); - return wave_triangle(x); - } - - // *** Envelope - - /// envelope applied to wave (uses ADSR) - double envelope(size_t i) const - { - double x = (double)i / m_duration; - if (x > 1.0) x = 1.0; - - // simple envelope functions: - - //return 1.0 - x; - //return cos(M_PI_2 * x); - - // *** ADSR envelope - - static const double attack = 0.025; // percentage of duration - static const double decay = 0.1; // percentage of duration - static const double sustain = 0.9; // percentage of amplitude - static const double release = 0.3; // percentage of duration - - if (x < attack) - return 1.0 / attack * x; - - if (x < attack + decay) - return 1.0 - (x - attack) / decay * (1.0 - sustain); - - if (x < 1.0 - release) - return sustain; - - return sustain / release * (1.0 - x); - } - - // *** Generate Wave and Mix - - /// mix in the output of this oscillator on the wave output - void mix(double* data, int size, size_t p) const - { - for (int i = 0; i < size; ++i) - { - if (p+i < m_tstart) continue; - if (p+i >= m_tend) break; - - size_t trel = (p + i - m_tstart); - - data[i] += envelope(trel) * wave((double)trel / s_samplerate * m_freq); - } - } - - /// return start time - size_t tstart() const - { return m_tstart; } - - /// true if the oscillator is silent at time p - bool is_done(size_t p) const - { - return (p >= m_tend); - } -}; - -/// array of oscillators -static std::vector s_osclist; - -/// global timestamp of callback in sound sample units -static size_t s_pos = 0; - -/// add an oscillator to the list (reuse finished ones) -static void add_oscillator(double freq, size_t p, size_t pstart, size_t duration) -{ - // find free oscillator - size_t oldest = 0, toldest = std::numeric_limits::max(); - for (size_t i = 0; i < s_osclist.size(); ++i) - { - if (s_osclist[i].is_done(p)) - { - s_osclist[i] = Oscillator(freq, pstart, duration); - return; - } - - if (s_osclist[i].tstart() < toldest) { - oldest = i; - toldest = s_osclist[i].tstart(); - } - } - - if (s_osclist.size() < s_max_oscillators) - { - // add new one - s_osclist.push_back( Oscillator(freq, pstart, duration) ); - } - else - { - // replace oldest oscillator - s_osclist[oldest] = Oscillator(freq, pstart, duration); - } -} - -/// list of array accesses since last callback -static std::vector s_access_list; - -// mutex to s_access_list -static wxMutex s_mutex_access_list; - -/// "public" function to add a new array access -void SoundAccess(size_t i) -{ - if (!g_sound_on) return; - - wxMutexLocker lock(s_mutex_access_list); - ASSERT(lock.IsOk()); - - s_access_list.push_back(i); -} - -/// function mapping array index (normalized to [0,1]) to frequency -static double arrayindex_to_frequency(double aindex) -{ - return 120 + 1200 * (aindex*aindex); -} - -/// reset internal sound data (called from main thread) -void SoundReset() -{ - wxMutexLocker lock(s_mutex_access_list); - ASSERT(lock.IsOk()); - - s_pos = 0; - s_osclist.clear(); -} - -/// sound generator callback run by SDL -void SoundCallback(void* udata, unsigned char* stream, int len) -{ - if (!g_sound_on) { - memset(stream, 0, len); - return; - } - - // current sample time (32-bit size_t wraps after 27 hours, 64-bit size_t - // wraps after 13 million years). - size_t& p = s_pos; - - // reference to sortview - WSortView& sv = *reinterpret_cast(udata); - - // we use 16-bit mono output at 44.1 kHz - int16_t* data = (int16_t*)stream; - size_t size = len / sizeof(int16_t); - - // fetch new access list and create oscillators - { - wxMutexLocker lock(s_mutex_access_list); - ASSERT(lock.IsOk()); - - // spread out access list over time of one callback - double pscale = (double)size / s_access_list.size(); - - for (size_t i = 0; i < s_access_list.size(); ++i) - { - double relindex = s_access_list[i] / (double)sv.m_array.array_max(); - double freq = arrayindex_to_frequency(relindex); - - add_oscillator( freq, p, p + i * pscale, - g_delay / 1000.0 * g_sound_sustain * s_samplerate ); - } - - s_access_list.clear(); - } - - // calculate waveform - std::vector wave(size, 0.0); - size_t wavecount = 0; - - for (std::vector::const_iterator it = s_osclist.begin(); - it != s_osclist.end(); ++it) - { - if (!it->is_done(p)) - { - it->mix(wave.data(), size, p); - ++wavecount; - } - } - - // scale output with number of waves mixed - - if (wavecount == 0) - { - // set zero, the function below messes up when vol = 0.0 - memset(stream, 0, len); - } - else - { - // count maximum wave amplitude - double vol = *std::max_element(wave.begin(), wave.end()); - - static double oldvol = 1.0; - - if (vol > oldvol) { - // immediately ramp down volume - } - else { - // but slowly ramp up volume - vol = 0.9 * oldvol; - } - - // convert waveform to samples, with ramping of volume - - for (size_t i = 0; i < size; ++i) - { - int32_t v = 24000.0 * wave[i] / (oldvol + (vol - oldvol) * (i / (double)size)); - - if (v > 32200) { - //std::cout << "clip " << p << "\n"; - v = 32200; - } - if (v < -32200) { - //std::cout << "clip " << p << "\n"; - v = -32200; - } - - data[i] = v; - } - - oldvol = vol; - } - - // advance sample timestamp - p += size; -} From 691cf975a648b6298874354c843db3471bce7d52 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 01:26:25 +0800 Subject: [PATCH 057/289] Delete WSortView.h --- WSortView.h | 124 ---------------------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 WSortView.h diff --git a/WSortView.h b/WSortView.h deleted file mode 100644 index 8d6105046..000000000 --- a/WSortView.h +++ /dev/null @@ -1,124 +0,0 @@ -/****************************************************************************** - * src/WSortView.h - * - * WSortView contains both the instrumentated array operators and draws the - * displayed visualization. - * - ****************************************************************************** - * Copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#ifndef WSORTVIEW_H -#define WSORTVIEW_H - -#include -#include "SortArray.h" - -// ---------------------------------------------------------------------------- - -/// global sound processing on/off -extern bool g_sound_on; - -/// multiplying g_delay with this value yields the duration a sound is sustained -extern double g_sound_sustain; - -/// the SDL sound callback -void SoundCallback(void *udata, unsigned char* stream, int len); - -/// reset internal state of sound generator -void SoundReset(); - -/// append access to start output in next sound callback -void SoundAccess(size_t i); - -// ---------------------------------------------------------------------------- - -/// global delay for one step -extern double g_delay; - -/// global flag when algorithm is running -extern bool g_algo_running; - -/// global string of running algorithm -extern wxString g_algo_name; - -class WSortView : public wxPanel, public SortDelay -{ -public: - WSortView(wxWindow *parent, int id, class WMain_wxg* wmain); - ~WSortView(); - - /// reference to WMain - class WMain* wmain; - - /// the instrumentated array to sort - SortArray m_array; - - void RepaintNow(); - - virtual void OnPaint(wxPaintEvent& pe); - virtual void OnSize(wxSizeEvent& se); - - // paint the visualization, (dcsize is passed along due to wxMSW issues) - void paint(wxDC& dc, const wxSize& dcsize); - - /// central access function called by each array access of the algorithms - virtual void OnAccess(); - - /// delay algorithm time by this amount - void DoDelay(double delay); - -protected: - - /// flag for step-wise processing (idle while true) - bool m_stepwise; - - /// semaphore for signaling steps from main thread - wxSemaphore m_step_semaphore; - -public: - - /// set stepwise processing for Step button - void SetStepwise(bool v) { m_stepwise = v; } - - /// stepwise processing for Step button - void DoStepwise(); - -public: - DECLARE_EVENT_TABLE() -}; - -// ---------------------------------------------------------------------------- - -class SortAlgoThread : public wxThread { -protected: - class WMain* m_wmain; - class WSortView& m_sortview; - - size_t m_algo; - -public: - - SortAlgoThread(class WMain* wmain, class WSortView& sortview, size_t algo); - - virtual ExitCode Entry(); - - void Exit(); -}; - -// ---------------------------------------------------------------------------- - -#endif // WSORTVIEW_H From 5a2383bf068eff7c350b1f6c4f6583b97e96e79e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 01:26:49 +0800 Subject: [PATCH 058/289] Code warning fix change I apparently discovered that including SDL.h on WSortView.h could cause redundant includes when it is included on other files, even if there are include guards. Since Uint8 and unsigned char are the same, SDL is fine with unsigned char, I simply made the definition of SoundCallback() in SortSound.cpp to also use unsigned char, avoiding code warnings due to code definition and declaration mismatch, while being a little closer to how the original code looks like. --- src/SortSound.cpp | 2 +- src/WSortView.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SortSound.cpp b/src/SortSound.cpp index 00b3c8ec9..dec5fdbdc 100644 --- a/src/SortSound.cpp +++ b/src/SortSound.cpp @@ -232,7 +232,7 @@ void SoundReset() } /// sound generator callback run by SDL -void SoundCallback(void* udata, Uint8 *stream, int len) +void SoundCallback(void* udata, unsigned char* stream, int len) { if (!g_sound_on) { memset(stream, 0, len); diff --git a/src/WSortView.h b/src/WSortView.h index 5dfca59e1..8d6105046 100644 --- a/src/WSortView.h +++ b/src/WSortView.h @@ -25,7 +25,6 @@ #define WSORTVIEW_H #include -#include #include "SortArray.h" // ---------------------------------------------------------------------------- @@ -37,7 +36,7 @@ extern bool g_sound_on; extern double g_sound_sustain; /// the SDL sound callback -void SoundCallback(void *udata, Uint8* stream, int len); +void SoundCallback(void *udata, unsigned char* stream, int len); /// reset internal state of sound generator void SoundReset(); From 3ca0d9ea409a6b95a19be0b3d795d09207033be8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 13:22:48 +0800 Subject: [PATCH 059/289] Fixed resources.o coming last during build command --- src/Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 28f4fdc58..847919064 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,15 +27,16 @@ sorting_test_SOURCES = \ $(COMMON) AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ @SDL_CFLAGS@ -LDADD = @WX_LIBS@ @SDL_LIBS@ +LDADD = if GOT_RESCOMP resources.o: resources.rc $(WX_RESCOMP) $(srcdir)/resources.rc resources.o - LDADD += resources.o endif +LDADD += @WX_LIBS@ @SDL_LIBS@ + EXTRA_DIST = \ resources.rc sos.ico sos.xpm \ wxg/sos.wxg From 9ec595bdbfb3f8614fbddf846e45d3976a5e50fb Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 13:26:34 +0800 Subject: [PATCH 060/289] Add files via upload --- src/Makefile.in | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 7580c571e..37b8164a3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -108,8 +108,8 @@ am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = SortArray.$(OBJEXT) SortSound.$(OBJEXT) \ - SortAlgo.$(OBJEXT) algorithms/timsort.$(OBJEXT) \ - algorithms/wikisort.$(OBJEXT) + SortAlgo.$(OBJEXT) algorithms/grailsort.$(OBJEXT) \ + algorithms/timsort.$(OBJEXT) algorithms/wikisort.$(OBJEXT) am_sorting_test_OBJECTS = SortTest.$(OBJEXT) $(am__objects_1) sorting_test_OBJECTS = $(am_sorting_test_OBJECTS) sorting_test_LDADD = $(LDADD) @@ -138,7 +138,8 @@ am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/SortAlgo.Po ./$(DEPDIR)/SortArray.Po \ ./$(DEPDIR)/SortSound.Po ./$(DEPDIR)/SortTest.Po \ ./$(DEPDIR)/WMain.Po ./$(DEPDIR)/WSortView.Po \ - ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/timsort.Po \ + ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/grailsort.Po \ + algorithms/$(DEPDIR)/timsort.Po \ algorithms/$(DEPDIR)/wikisort.Po wxg/$(DEPDIR)/WAbout_wxg.Po \ wxg/$(DEPDIR)/WMain_wxg.Po am__mv = mv -f @@ -528,6 +529,7 @@ top_srcdir = @top_srcdir@ COMMON = SortArray.cpp SortArray.h \ SortSound.cpp \ SortAlgo.cpp SortAlgo.h \ + algorithms/grailsort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp @@ -544,7 +546,7 @@ sorting_test_SOURCES = \ $(COMMON) AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ @SDL_CFLAGS@ -LDADD = @WX_LIBS@ @SDL_LIBS@ $(am__append_1) +LDADD = $(am__append_1) @WX_LIBS@ @SDL_LIBS@ EXTRA_DIST = \ resources.rc sos.ico sos.xpm \ wxg/sos.wxg @@ -633,6 +635,8 @@ algorithms/$(am__dirstamp): algorithms/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) algorithms/$(DEPDIR) @: > algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/grailsort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/timsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/wikisort.$(OBJEXT): algorithms/$(am__dirstamp) \ @@ -671,6 +675,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WMain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WSortView.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wxClickText.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/grailsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/timsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/wikisort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@wxg/$(DEPDIR)/WAbout_wxg.Po@am__quote@ # am--include-marker @@ -1003,6 +1008,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/WMain.Po -rm -f ./$(DEPDIR)/WSortView.Po -rm -f ./$(DEPDIR)/wxClickText.Po + -rm -f algorithms/$(DEPDIR)/grailsort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po @@ -1059,6 +1065,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/WMain.Po -rm -f ./$(DEPDIR)/WSortView.Po -rm -f ./$(DEPDIR)/wxClickText.Po + -rm -f algorithms/$(DEPDIR)/grailsort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po From eeb0675f9d570efacd3151892590b75df26d6a70 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 13:39:40 +0800 Subject: [PATCH 061/289] Delete Makefile Not needed --- Makefile | 804 ------------------------------------------------------- 1 file changed, 804 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 60b3e7545..000000000 --- a/Makefile +++ /dev/null @@ -1,804 +0,0 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. -# Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994-2021 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - -# $Id: Makefile.am 2 2007-01-05 14:04:27Z tb $ - -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/sound-of-sorting -pkgincludedir = $(includedir)/sound-of-sorting -pkglibdir = $(libdir)/sound-of-sorting -pkglibexecdir = $(libexecdir)/sound-of-sorting -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = x86_64-w64-mingw32 -host_triplet = x86_64-w64-mingw32 -target_triplet = x86_64-w64-mingw32 -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(am__DIST_COMMON) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_$(V)) -am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_$(V)) -am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_$(V)) -am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - cscope distdir distdir-am dist dist-all distcheck -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -DIST_SUBDIRS = $(SUBDIRS) -am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/acscripts/compile \ - $(top_srcdir)/acscripts/config.guess \ - $(top_srcdir)/acscripts/config.sub \ - $(top_srcdir)/acscripts/install-sh \ - $(top_srcdir)/acscripts/missing AUTHORS COPYING README.md \ - acscripts/compile acscripts/config.guess acscripts/config.sub \ - acscripts/depcomp acscripts/install-sh acscripts/missing -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -rf "$(distdir)" \ - || { sleep 5 && rm -rf "$(distdir)"; }; \ - else :; fi -am__post_remove_distdir = $(am__remove_distdir) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -DIST_ARCHIVES = $(distdir).tar.gz -GZIP_ENV = --best -DIST_TARGETS = dist-gzip -# Exists only to be overridden by the user if desired. -AM_DISTCHECK_DVI_TARGET = dvi -distuninstallcheck_listfiles = find . -type f -print -am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ - | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = find . -type f -print -ACLOCAL = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' aclocal-1.16 -AMTAR = $${TAR-tar} -AM_DEFAULT_VERBOSITY = 1 -AUTOCONF = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' autoconf -AUTOHEADER = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' autoheader -AUTOMAKE = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' automake-1.16 -AWK = gawk -CC = gcc -CCDEPMODE = depmode=gcc3 -CFLAGS = -g -Wno-unused-local-typedefs -CPPFLAGS = -CSCOPE = cscope -CTAGS = ctags -CXX = g++ -CXXDEPMODE = depmode=gcc3 -CXXFLAGS = -g -Wno-unused-local-typedefs -CYGPATH_W = cygpath -w -DEFS = -DPACKAGE_NAME=\"sound-of-sorting\" -DPACKAGE_TARNAME=\"sound-of-sorting\" -DPACKAGE_VERSION=\"0.6.5\" -DPACKAGE_STRING=\"sound-of-sorting\ 0.6.5\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"sound-of-sorting\" -DVERSION=\"0.6.5\" -DMSW_PERFORMANCECOUNTER=1 -DEPDIR = .deps -ECHO_C = -ECHO_N = -n -ECHO_T = -ETAGS = etags -EXEEXT = .exe -INSTALL = /usr/bin/install -c -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = $(install_sh) -c -s -LDFLAGS = -LIBOBJS = -LIBS = -LTLIBOBJS = -MAINT = # -MAKEINFO = ${SHELL} '/c/Users/louwe/Desktop/soundofsortingfork/acscripts/missing' makeinfo -MKDIR_P = /usr/bin/mkdir -p -OBJEXT = o -PACKAGE = sound-of-sorting -PACKAGE_BUGREPORT = -PACKAGE_NAME = sound-of-sorting -PACKAGE_STRING = sound-of-sorting 0.6.5 -PACKAGE_TARNAME = sound-of-sorting -PACKAGE_URL = -PACKAGE_VERSION = 0.6.5 -PATH_SEPARATOR = : -PKG_CONFIG = /mingw64/bin/pkg-config -PKG_CONFIG_LIBDIR = -PKG_CONFIG_PATH = /mingw64/lib/pkgconfig:/mingw64/share/pkgconfig -RANLIB = ranlib -SDL2_CONFIG = /mingw64/bin/pkg-config sdl2 -SDL2_FRAMEWORK = -SDL_CFLAGS = -IC:/msys64/mingw64/include/SDL2 -Dmain=SDL_main -SDL_LIBS = -lmingw32 -mwindows -lSDL2main -lSDL2 -SET_MAKE = -SHELL = /bin/sh -STRIP = -VERSION = 0.6.5 -WX_CFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_CFLAGS_ONLY = -WX_CONFIG_PATH = /mingw64/bin/wx-config -WX_CPPFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_CXXFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_CXXFLAGS_ONLY = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_LIBS = -L/mingw64/lib -Wl,--subsystem,windows -mwindows -lwx_mswu_core-3.2 -lwx_baseu-3.2 -WX_LIBS_STATIC = -LC:/msys64/mingw64/lib -pipe -Wl,--subsystem,windows -mwindows C:/msys64/mingw64/lib/libwx_mswu_adv-3.0.a C:/msys64/mingw64/lib/libwx_mswu_core-3.0.a C:/msys64/mingw64/lib/libwx_baseu-3.0.a -lwxregexu-3.0 -lwxexpat-3.0 -lwxtiff-3.0 -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 -lrpcrt4 -loleaut32 -lole32 -luuid -llzma -ljbig -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 -loleacc -WX_RESCOMP = windres --include-dir /mingw64/include/wx-3.2 --define __WIN32__ --define __GNUWIN32__ --define WX_CPU_AMD64 -WX_VERSION = 3.2.6 -WX_VERSION_MAJOR = 3 -WX_VERSION_MICRO = 6 -WX_VERSION_MINOR = 2 -abs_builddir = /c/Users/louwe/Desktop/soundofsortingfork -abs_srcdir = /c/Users/louwe/Desktop/soundofsortingfork -abs_top_builddir = /c/Users/louwe/Desktop/soundofsortingfork -abs_top_srcdir = /c/Users/louwe/Desktop/soundofsortingfork -ac_ct_CC = gcc -ac_ct_CXX = g++ -am__include = include -am__leading_dot = . -am__quote = -am__tar = $${TAR-tar} chof - "$$tardir" -am__untar = $${TAR-tar} xf - -bindir = ${exec_prefix}/bin -build = x86_64-w64-mingw32 -build_alias = x86_64-w64-mingw32 -build_cpu = x86_64 -build_os = mingw32 -build_vendor = w64 -builddir = . -datadir = ${datarootdir} -datarootdir = ${prefix}/share -docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} -dvidir = ${docdir} -exec_prefix = ${prefix} -host = x86_64-w64-mingw32 -host_alias = -host_cpu = x86_64 -host_os = mingw32 -host_vendor = w64 -htmldir = ${docdir} -includedir = ${prefix}/include -infodir = ${datarootdir}/info -install_sh = ${SHELL} /c/Users/louwe/Desktop/soundofsortingfork/acscripts/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -localedir = ${datarootdir}/locale -localstatedir = ${prefix}/var -mandir = ${datarootdir}/man -mkdir_p = $(MKDIR_P) -oldincludedir = /usr/include -pdfdir = ${docdir} -prefix = /mingw64 -program_transform_name = s,x,x, -psdir = ${docdir} -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -srcdir = . -sysconfdir = ${prefix}/etc -target = x86_64-w64-mingw32 -target_alias = -target_cpu = x86_64 -target_os = mingw32 -target_vendor = w64 -top_build_prefix = -top_builddir = . -top_srcdir = . -SUBDIRS = src -EXTRA_DIST = \ - README.md - -all: all-recursive - -.SUFFIXES: -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: # $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): # $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscope: cscope.files - test ! -s cscope.files \ - || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) -clean-cscope: - -rm -f cscope.files -cscope.files: clean-cscope cscopelist -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -rm -f cscope.out cscope.in.out cscope.po.out cscope.files -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz - $(am__post_remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 - $(am__post_remove_distdir) - -dist-lzip: distdir - tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz - $(am__post_remove_distdir) - -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz - $(am__post_remove_distdir) - -dist-zstd: distdir - tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst - $(am__post_remove_distdir) - -dist-tarZ: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__post_remove_distdir) - -dist-shar: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz - $(am__post_remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__post_remove_distdir) - -dist dist-all: - $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' - $(am__post_remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lz*) \ - lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - *.tar.zst*) \ - zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ - esac - chmod -R a-w $(distdir) - chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build/sub \ - && ../../configure \ - $(AM_DISTCHECK_CONFIGURE_FLAGS) \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=../.. --prefix="$$dc_install_base" \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__post_remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @test -n '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: trying to run $@ with an empty' \ - '$$(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - $(am__cd) '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(am__recursive_targets) install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ - am--refresh check check-am clean clean-cscope clean-generic \ - cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ - dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ - dist-zstd distcheck distclean distclean-generic distclean-tags \ - distcleancheck distdir distuninstallcheck dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs installdirs-am maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ - pdf-am ps ps-am tags tags-am uninstall uninstall-am - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: From edf11a585c761471d35d710241635ea7c0a7e0d8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 13:41:12 +0800 Subject: [PATCH 062/289] Regenerated Makefile.in From 5a2a157f7fc650d7176b976282e8d936c405f1b7 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 13:42:12 +0800 Subject: [PATCH 063/289] Regenerated Makefile.in From 8d632590b9554dfbb75f716e8f348fd8958c9686 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 13:44:16 +0800 Subject: [PATCH 064/289] Regenerated Makefile.in From ab02e700a40813c54af26dce1eb93caf5e406699 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 16:51:25 +0800 Subject: [PATCH 065/289] Fixed "undefined reference to SDL_main" FINALLY! This problem IS SO HARD TO FIX! I spent several hours trying to test every single solution I have found, and nothing worked. I knew that WMain.cpp is the main entry point, but no matter what combination of #include, #define, int main() definitions I did, nothing is working, I got so frustrated, but I knew I could solve it somehow. While reading how the build command works, I noticed this funky a** line "Dmain=SDL_main". This line apparently indicates that SDL_main must override the main() method of a program that uses SDL. At first I had absolutely no idea how to remove this line, as nothing in the build indicates this flag, until I found out in my configuration that this flag is included by default, removing it has finally removed the warning! After several hours worth of testing debugging. But wait, this first solution isn't really applicable for everyone, right? The location of sdl2.pc is in C:\msys64\mingw64\lib\pkgconfig and then removing the -Dmain=SDL_main flag in there, but obviously this global solution isn't very applicable for everyone, as much as possible, this change should be local to this project only, and thankfully there is a way to remove this flag in a localized manner, using filter-out in Makefile.am! There is also a way to exclude this problematic flag on configure.ac with SDL_CFLAGS=$(shell pkg-config --cflags sdl2 | sed 's/-Dmain=SDL_main//'), but this Makefile.am and Makefile.in workaround should be okay for now. The reason why ignoring this flag is better than doing something to it (trust me, I tried, NOTHING WORKED) is because the WMain.cpp already handles SDL quite enough with SDL_Init() and SDL_Quit() on the MyApp class, which is what SDL_main is also meant for. Since MyApp already does the job, there is absolutely no need for this method. That's all! Whew, finally, it is done! --- src/Makefile.am | 2 +- src/Makefile.in | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 847919064..4eb483489 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ @SDL_CFLAGS@ +AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = if GOT_RESCOMP diff --git a/src/Makefile.in b/src/Makefile.in index 37b8164a3..534055476 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.16.2 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -192,6 +192,8 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no @@ -374,7 +376,6 @@ am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` -AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log @@ -412,8 +413,6 @@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ -CSCOPE = @CSCOPE@ -CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ @@ -423,7 +422,6 @@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ -ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -545,7 +543,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ @SDL_CFLAGS@ +AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = $(am__append_1) @WX_LIBS@ @SDL_LIBS@ EXTRA_DIST = \ resources.rc sos.ico sos.xpm \ @@ -862,7 +860,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS) test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ @@ -917,6 +915,7 @@ sorting-test.log: sorting-test$(EXEEXT) @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am From 56529c37b118b9f2aea3b41d3e6681f95c5147e9 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 17:10:49 +0800 Subject: [PATCH 066/289] Updated Makefile.in --- src/Makefile.in | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 534055476..655db30c8 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -192,8 +192,6 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no @@ -376,6 +374,7 @@ am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log @@ -413,6 +412,8 @@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ @@ -422,6 +423,7 @@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -860,7 +862,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS) test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ @@ -915,7 +917,6 @@ sorting-test.log: sorting-test$(EXEEXT) @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am From 8546aa33afc9511d38ae8cd3b404cc1458061695 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 12 Oct 2024 19:10:12 +0800 Subject: [PATCH 067/289] Reduced array input types for sort testing Since "undefined reference for SDL_main" has been fixed, sorting-test.exe is able to compile now, and running it for the first time, I realized that large input sizes are not great here, so I reduced it to make sorting tests a lot more bearable. --- src/SortTest.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SortTest.cpp b/src/SortTest.cpp index 098ae2134..142cc1e96 100644 --- a/src/SortTest.cpp +++ b/src/SortTest.cpp @@ -53,8 +53,7 @@ bool SortTestApp::OnInit() } static size_t testsize[] = { - 10, 11, 12, 13, 14, 15, 16, 32, 100, 101, 102, 103, 200, 1024, 1337, 1600, 2048, 2500, - 3072, 3500, 4096, 4500, 5000, 5600, 6144, 6500, 7000, 7500, 8192, 0 + 10, 11, 12, 13, 14, 15, 16, 32, 100, 101, 102, 103, 200, 1024, 1337, 1600, 2048, 0 }; struct SortedCheck From baa4a2a3bea95fb76a45db499a545e2ca3241c42 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 13 Oct 2024 11:11:18 +0800 Subject: [PATCH 068/289] Modified extBuffer declaration to be more generic Based on the bug fix I performed on the C++ implementation of Grail Sort by @Morwenn, in which he suggested that extBuffer must be declared in a more generic manner. --- src/algorithms/grailsort.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 6cb19a65b..55ee1a5cf 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -1183,7 +1183,7 @@ namespace grailsort_detail return; } - BufferIterator extBuffer = 0; + BufferIterator extBuffer{}; int extBufferLen = 0; int blockLen = 1; @@ -1327,4 +1327,4 @@ void GrailSort(SortArray& A) { grailsort(MyIterator(&A, 0), MyIterator(&A, A.size())); } -// **************************************************************************** \ No newline at end of file +// **************************************************************************** From e905db86a866ed51a97c9c09abea5e9381b785ff Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 13 Oct 2024 20:40:48 +0800 Subject: [PATCH 069/289] Added Pairwise Sorting Network, both variants Credits to @aphitorite --- src/SortAlgo.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 2 ++ 2 files changed, 84 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 52bb5635e..d04f74595 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -65,6 +65,10 @@ const struct AlgoEntry g_algolist[] = { _("Merge Sort (iterative)"), &MergeSortIterative, UINT_MAX, 512, _("Merge sort variant which iteratively merges " "subarrays of sizes of powers of two.") }, + { _("Pairwise Merge Sort (Recursive)"), &PairwiseSort, UINT_MAX, 512, + wxEmptyString }, + { _("Pairwise Merge Sort (Iterative)"), &PairwiseIterativeSort, UINT_MAX, 512, + wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, _("Quick sort variant with left and right pointers.") }, { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, @@ -2040,3 +2044,81 @@ void CycleSort(SortArray& A) { CycleSort(A, A.size()); } + + +// **************************************************************************** +// *** Pairwise Sorting Network (Recursive and Iterative) +// Copyright (c) 2021 aphitorite + +void compSwap(SortArray& A, size_t a, size_t b) +{ + size_t n = A.size(); + if (b < n && A[a] > A[b]) { A.swap(a, b); } +} +void PairwiseMerge(SortArray& A, size_t a, size_t b) +{ + size_t m = (a + b) / 2, m1 = (a + m) / 2, g = m - m1; + for (size_t i = 0; m1 + i < m; ++i) + { + for (size_t j = m1, k = g; k > 0; k >>= 1, j -= k - (i & k)) + { + compSwap(A, j + i, j + i + k); + } + } + if (b - a > 4) { PairwiseMerge(A, m, b); } +} + +void PairwiseMergeSort(SortArray& A, size_t a, size_t b) +{ + size_t m = (a + b) / 2; + for (size_t i = a, j = m; i < m; ++i, ++j) + { + compSwap(A, i, j); + } + if (b - a > 2) + { + PairwiseMergeSort(A, a, m); + PairwiseMergeSort(A, m, b); + PairwiseMerge(A, a, b); + } +} + +void PairwiseSort(SortArray& A) +{ + size_t end = A.size(); + size_t n = 1; + for (; n < end; n <<= 1) {} + PairwiseMergeSort(A, 0, n); +} + +void PairwiseIterativeSort(SortArray& A) +{ + size_t end = A.size(), n = 1; + for (; n < end; n <<= 1) {} + for (size_t k = n >> 1; k > 0; k >>= 1) + { + for (size_t j = 0; j < end; j += k << 1) + { + for (size_t i = 0; i < k; ++i) + { + compSwap(A, j + i, j + i + k); + } + } + } + for (size_t k = 2; k < n; k <<= 1) + { + for (size_t j = k >> 1; j > 0; j >>= 1) + { + for (size_t i = 0; i < end; i += k << 1) + { + for (size_t m = j; m < ((k - j) << 1); m += j << 1) + { + for (size_t o = 0; o < j; ++o) + { + compSwap(A, i + m + o, i + m + j + o); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 96e4181f4..417720e2f 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -61,6 +61,8 @@ void BinaryInsertionSort(class SortArray& a); void MergeSort(class SortArray& a); void MergeSortIterative(class SortArray& a); +void PairwiseSort(class SortArray& a); +void PairwiseIterativeSort(class SortArray& a); wxArrayString QuickSortPivotText(); From 8d001b99eec6dd44af52a57e956e7659d31319ca Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 13 Oct 2024 20:50:58 +0800 Subject: [PATCH 070/289] Added some extra details on some other algorithms --- src/SortAlgo.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d04f74595..4f69ca99c 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -213,6 +213,10 @@ void SelectionSort(SortArray& A) A.unwatch_all(); } +// **************************************************************************** +// *** Sandpaper and Double Sandpaper Sort +// Double Sandpaper Sort by Taihennami + void DoubleSandpaperSort(SortArray& A) { for (size_t left = 0, right = A.size() - 1; left < right; ++left, --right) @@ -1226,6 +1230,10 @@ void shiftElement(SortArray& A, size_t start, size_t end) } } +// **************************************************************************** +// *** In-Place Radix Sort LSD +// Copyright (c) 2019 w0rthy + size_t maxLog(SortArray& A, size_t n, size_t base) { int max = A[0]; From 9d3948c80b1c71a2bd6377e7ed7ff3f0920b5f68 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 13 Oct 2024 21:06:08 +0800 Subject: [PATCH 071/289] Slightly improved Many Similar generation Fixed generation of Many Similar input type for array sizes less than or equal to 10 --- src/SortArray.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 402c63632..cb5814de8 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -347,7 +347,12 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) else if (size % 4 == 0) { group_count = 4; } else if (size % 2 != 0) { group_count = 3; } else { group_count = 2; } - + size_t n = m_array.size(); + if (n <= 10) + { + if (n % 2 != 0) { group_count = 3; } + else { group_count = 2; } + } size_t repeat = 1; int val = 1; for (size_t i = 0; i < size; ++i) From c425a16a64f0d3f22d5872cff4a12336553aab56 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 13 Oct 2024 23:54:29 +0800 Subject: [PATCH 072/289] Added notices --- src/SortAlgo.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 4f69ca99c..c9c9d37d8 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1232,8 +1232,26 @@ void shiftElement(SortArray& A, size_t start, size_t end) // **************************************************************************** // *** In-Place Radix Sort LSD -// Copyright (c) 2019 w0rthy - +/* +Copyright (c) 2019 w0rthy +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ size_t maxLog(SortArray& A, size_t n, size_t base) { int max = A[0]; @@ -2055,8 +2073,27 @@ void CycleSort(SortArray& A) // **************************************************************************** -// *** Pairwise Sorting Network (Recursive and Iterative) -// Copyright (c) 2021 aphitorite +// *** Pairwise Sorting Network (Recursive and Iterative) +/* +Copyright (c) 2021 aphitorite +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ void compSwap(SortArray& A, size_t a, size_t b) { @@ -2129,4 +2166,4 @@ void PairwiseIterativeSort(SortArray& A) } } } -} \ No newline at end of file +} From c8585c3d644ac6408e77c924555f9d1cc1a01860 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:07:51 +0800 Subject: [PATCH 073/289] Prepare files for Pattern-Defeating Quick Sort --- src/Makefile.am | 1 + src/Makefile.in | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 4eb483489..873bfcf3b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ COMMON = SortArray.cpp SortArray.h \ SortSound.cpp \ SortAlgo.cpp SortAlgo.h \ algorithms/grailsort.cpp \ + algorithms/pdqsort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp diff --git a/src/Makefile.in b/src/Makefile.in index 655db30c8..8d81830e6 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -109,7 +109,8 @@ PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = SortArray.$(OBJEXT) SortSound.$(OBJEXT) \ SortAlgo.$(OBJEXT) algorithms/grailsort.$(OBJEXT) \ - algorithms/timsort.$(OBJEXT) algorithms/wikisort.$(OBJEXT) + algorithms/pdqsort.$(OBJEXT) algorithms/timsort.$(OBJEXT) \ + algorithms/wikisort.$(OBJEXT) am_sorting_test_OBJECTS = SortTest.$(OBJEXT) $(am__objects_1) sorting_test_OBJECTS = $(am_sorting_test_OBJECTS) sorting_test_LDADD = $(LDADD) @@ -139,6 +140,7 @@ am__depfiles_remade = ./$(DEPDIR)/SortAlgo.Po ./$(DEPDIR)/SortArray.Po \ ./$(DEPDIR)/SortSound.Po ./$(DEPDIR)/SortTest.Po \ ./$(DEPDIR)/WMain.Po ./$(DEPDIR)/WSortView.Po \ ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/grailsort.Po \ + algorithms/$(DEPDIR)/pdqsort.Po \ algorithms/$(DEPDIR)/timsort.Po \ algorithms/$(DEPDIR)/wikisort.Po wxg/$(DEPDIR)/WAbout_wxg.Po \ wxg/$(DEPDIR)/WMain_wxg.Po @@ -530,6 +532,7 @@ COMMON = SortArray.cpp SortArray.h \ SortSound.cpp \ SortAlgo.cpp SortAlgo.h \ algorithms/grailsort.cpp \ + algorithms/pdqsort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp @@ -637,6 +640,8 @@ algorithms/$(DEPDIR)/$(am__dirstamp): @: > algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/grailsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/pdqsort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/timsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/wikisort.$(OBJEXT): algorithms/$(am__dirstamp) \ @@ -676,6 +681,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WSortView.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wxClickText.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/grailsort.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/pdqsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/timsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/wikisort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@wxg/$(DEPDIR)/WAbout_wxg.Po@am__quote@ # am--include-marker @@ -1009,6 +1015,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/WSortView.Po -rm -f ./$(DEPDIR)/wxClickText.Po -rm -f algorithms/$(DEPDIR)/grailsort.Po + -rm -f algorithms/$(DEPDIR)/pdqsort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po @@ -1066,6 +1073,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/WSortView.Po -rm -f ./$(DEPDIR)/wxClickText.Po -rm -f algorithms/$(DEPDIR)/grailsort.Po + -rm -f algorithms/$(DEPDIR)/pdqsort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po From cd3d8c17b07ee1b90a09ac8227d4abf5229b5ba2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:09:21 +0800 Subject: [PATCH 074/289] Update 3 files From 3d56fc5db22e3060f60f2cd4079d7b2afadc559e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:10:18 +0800 Subject: [PATCH 075/289] Added Pattern-Defeating Quick Sort Credits to @orlp --- src/algorithms/pdqsort.cpp | 542 +++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 src/algorithms/pdqsort.cpp diff --git a/src/algorithms/pdqsort.cpp b/src/algorithms/pdqsort.cpp new file mode 100644 index 000000000..2ed40d5fb --- /dev/null +++ b/src/algorithms/pdqsort.cpp @@ -0,0 +1,542 @@ +/* + pdqsort.h - Pattern-defeating quicksort. + + Copyright (c) 2021 Orson Peters + + This software is provided 'as-is', without any express or implied warranty. In no event will the + authors be held liable for any damages arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, including commercial + applications, and to alter it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the + original software. If you use this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as + being the original software. + + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef PDQSORT_H +#define PDQSORT_H + +#include "../SortAlgo.h" +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L + #include + #include + #define PDQSORT_PREFER_MOVE(x) std::move(x) +#else + #define PDQSORT_PREFER_MOVE(x) (x) +#endif + + +namespace pdqsort_detail { + enum { + // Partitions below this size are sorted using insertion sort. + insertion_sort_threshold = 24, + + // Partitions above this size use Tukey's ninther to select the pivot. + ninther_threshold = 128, + + // When we detect an already sorted partition, attempt an insertion sort that allows this + // amount of element moves before giving up. + partial_insertion_sort_limit = 8, + + // Must be multiple of 8 due to loop unrolling, and < 256 to fit in unsigned char. + block_size = 64, + + // Cacheline size, assumes power of two. + cacheline_size = 64 + + }; + +#if __cplusplus >= 201103L + template struct is_default_compare : std::false_type { }; + template struct is_default_compare> : std::true_type { }; + template struct is_default_compare> : std::true_type { }; +#endif + + // Returns floor(log2(n)), assumes n > 0. + template + inline int log2(T n) { + int log = 0; + while (n >>= 1) ++log; + return log; + } + + // Sorts [begin, end) using insertion sort with the given comparison function. + template + inline void insertion_sort(Iter begin, Iter end, Compare comp) { + typedef typename std::iterator_traits::value_type T; + if (begin == end) return; + + for (Iter cur = begin + 1; cur != end; ++cur) { + Iter sift = cur; + Iter sift_1 = cur - 1; + + // Compare first so we can avoid 2 moves for an element already positioned correctly. + if (comp(*sift, *sift_1)) { + T tmp = PDQSORT_PREFER_MOVE(*sift); + + do { *sift-- = PDQSORT_PREFER_MOVE(*sift_1); } + while (sift != begin && comp(tmp, *--sift_1)); + + *sift = PDQSORT_PREFER_MOVE(tmp); + } + } + } + + // Sorts [begin, end) using insertion sort with the given comparison function. Assumes + // *(begin - 1) is an element smaller than or equal to any element in [begin, end). + template + inline void unguarded_insertion_sort(Iter begin, Iter end, Compare comp) { + typedef typename std::iterator_traits::value_type T; + if (begin == end) return; + + for (Iter cur = begin + 1; cur != end; ++cur) { + Iter sift = cur; + Iter sift_1 = cur - 1; + + // Compare first so we can avoid 2 moves for an element already positioned correctly. + if (comp(*sift, *sift_1)) { + T tmp = PDQSORT_PREFER_MOVE(*sift); + + do { *sift-- = PDQSORT_PREFER_MOVE(*sift_1); } + while (comp(tmp, *--sift_1)); + + *sift = PDQSORT_PREFER_MOVE(tmp); + } + } + } + + // Attempts to use insertion sort on [begin, end). Will return false if more than + // partial_insertion_sort_limit elements were moved, and abort sorting. Otherwise it will + // successfully sort and return true. + template + inline bool partial_insertion_sort(Iter begin, Iter end, Compare comp) { + typedef typename std::iterator_traits::value_type T; + if (begin == end) return true; + + std::size_t limit = 0; + for (Iter cur = begin + 1; cur != end; ++cur) { + Iter sift = cur; + Iter sift_1 = cur - 1; + + // Compare first so we can avoid 2 moves for an element already positioned correctly. + if (comp(*sift, *sift_1)) { + T tmp = PDQSORT_PREFER_MOVE(*sift); + + do { *sift-- = PDQSORT_PREFER_MOVE(*sift_1); } + while (sift != begin && comp(tmp, *--sift_1)); + + *sift = PDQSORT_PREFER_MOVE(tmp); + limit += cur - sift; + } + + if (limit > partial_insertion_sort_limit) return false; + } + + return true; + } + + template + inline void sort2(Iter a, Iter b, Compare comp) { + if (comp(*b, *a)) std::iter_swap(a, b); + } + + // Sorts the elements *a, *b and *c using comparison function comp. + template + inline void sort3(Iter a, Iter b, Iter c, Compare comp) { + sort2(a, b, comp); + sort2(b, c, comp); + sort2(a, b, comp); + } + + template + inline T* align_cacheline(T* p) { +#if defined(UINTPTR_MAX) && __cplusplus >= 201103L + std::uintptr_t ip = reinterpret_cast(p); +#else + std::size_t ip = reinterpret_cast(p); +#endif + ip = (ip + cacheline_size - 1) & -cacheline_size; + return reinterpret_cast(ip); + } + + template + inline void swap_offsets(Iter first, Iter last, + unsigned char* offsets_l, unsigned char* offsets_r, + size_t num, bool use_swaps) { + typedef typename std::iterator_traits::value_type T; + if (use_swaps) { + // This case is needed for the descending distribution, where we need + // to have proper swapping for pdqsort to remain O(n). + for (size_t i = 0; i < num; ++i) { + std::iter_swap(first + offsets_l[i], last - offsets_r[i]); + } + } else if (num > 0) { + Iter l = first + offsets_l[0]; Iter r = last - offsets_r[0]; + T tmp(PDQSORT_PREFER_MOVE(*l)); *l = PDQSORT_PREFER_MOVE(*r); + for (size_t i = 1; i < num; ++i) { + l = first + offsets_l[i]; *r = PDQSORT_PREFER_MOVE(*l); + r = last - offsets_r[i]; *l = PDQSORT_PREFER_MOVE(*r); + } + *r = PDQSORT_PREFER_MOVE(tmp); + } + } + + // Partitions [begin, end) around pivot *begin using comparison function comp. Elements equal + // to the pivot are put in the right-hand partition. Returns the position of the pivot after + // partitioning and whether the passed sequence already was correctly partitioned. Assumes the + // pivot is a median of at least 3 elements and that [begin, end) is at least + // insertion_sort_threshold long. Uses branchless partitioning. + template + inline std::pair partition_right_branchless(Iter begin, Iter end, Compare comp) { + typedef typename std::iterator_traits::value_type T; + + // Move pivot into local for speed. + T pivot(PDQSORT_PREFER_MOVE(*begin)); + Iter first = begin; + Iter last = end; + + // Find the first element greater than or equal than the pivot (the median of 3 guarantees + // this exists). + while (comp(*++first, pivot)); + + // Find the first element strictly smaller than the pivot. We have to guard this search if + // there was no element before *first. + if (first - 1 == begin) while (first < last && !comp(*--last, pivot)); + else while ( !comp(*--last, pivot)); + + // If the first pair of elements that should be swapped to partition are the same element, + // the passed in sequence already was correctly partitioned. + bool already_partitioned = first >= last; + if (!already_partitioned) { + std::iter_swap(first, last); + ++first; + + // The following branchless partitioning is derived from "BlockQuicksort: How Branch + // Mispredictions don’t affect Quicksort" by Stefan Edelkamp and Armin Weiss, but + // heavily micro-optimized. + unsigned char offsets_l_storage[block_size + cacheline_size]; + unsigned char offsets_r_storage[block_size + cacheline_size]; + unsigned char* offsets_l = align_cacheline(offsets_l_storage); + unsigned char* offsets_r = align_cacheline(offsets_r_storage); + + Iter offsets_l_base = first; + Iter offsets_r_base = last; + size_t num_l, num_r, start_l, start_r; + num_l = num_r = start_l = start_r = 0; + + while (first < last) { + // Fill up offset blocks with elements that are on the wrong side. + // First we determine how much elements are considered for each offset block. + size_t num_unknown = last - first; + size_t left_split = num_l == 0 ? (num_r == 0 ? num_unknown / 2 : num_unknown) : 0; + size_t right_split = num_r == 0 ? (num_unknown - left_split) : 0; + + // Fill the offset blocks. + if (left_split >= block_size) { + for (size_t i = 0; i < block_size;) { + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + } + } else { + for (size_t i = 0; i < left_split;) { + offsets_l[num_l] = i++; num_l += !comp(*first, pivot); ++first; + } + } + + if (right_split >= block_size) { + for (size_t i = 0; i < block_size;) { + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + } + } else { + for (size_t i = 0; i < right_split;) { + offsets_r[num_r] = ++i; num_r += comp(*--last, pivot); + } + } + + // Swap elements and update block sizes and first/last boundaries. + size_t num = std::min(num_l, num_r); + swap_offsets(offsets_l_base, offsets_r_base, + offsets_l + start_l, offsets_r + start_r, + num, num_l == num_r); + num_l -= num; num_r -= num; + start_l += num; start_r += num; + + if (num_l == 0) { + start_l = 0; + offsets_l_base = first; + } + + if (num_r == 0) { + start_r = 0; + offsets_r_base = last; + } + } + + // We have now fully identified [first, last)'s proper position. Swap the last elements. + if (num_l) { + offsets_l += start_l; + while (num_l--) std::iter_swap(offsets_l_base + offsets_l[num_l], --last); + first = last; + } + if (num_r) { + offsets_r += start_r; + while (num_r--) std::iter_swap(offsets_r_base - offsets_r[num_r], first), ++first; + last = first; + } + } + + // Put the pivot in the right place. + Iter pivot_pos = first - 1; + *begin = PDQSORT_PREFER_MOVE(*pivot_pos); + *pivot_pos = PDQSORT_PREFER_MOVE(pivot); + + return std::make_pair(pivot_pos, already_partitioned); + } + + + + // Partitions [begin, end) around pivot *begin using comparison function comp. Elements equal + // to the pivot are put in the right-hand partition. Returns the position of the pivot after + // partitioning and whether the passed sequence already was correctly partitioned. Assumes the + // pivot is a median of at least 3 elements and that [begin, end) is at least + // insertion_sort_threshold long. + template + inline std::pair partition_right(Iter begin, Iter end, Compare comp) { + typedef typename std::iterator_traits::value_type T; + + // Move pivot into local for speed. + T pivot(PDQSORT_PREFER_MOVE(*begin)); + + Iter first = begin; + Iter last = end; + + // Find the first element greater than or equal than the pivot (the median of 3 guarantees + // this exists). + while (comp(*++first, pivot)); + + // Find the first element strictly smaller than the pivot. We have to guard this search if + // there was no element before *first. + if (first - 1 == begin) while (first < last && !comp(*--last, pivot)); + else while ( !comp(*--last, pivot)); + + // If the first pair of elements that should be swapped to partition are the same element, + // the passed in sequence already was correctly partitioned. + bool already_partitioned = first >= last; + + // Keep swapping pairs of elements that are on the wrong side of the pivot. Previously + // swapped pairs guard the searches, which is why the first iteration is special-cased + // above. + while (first < last) { + std::iter_swap(first, last); + while (comp(*++first, pivot)); + while (!comp(*--last, pivot)); + } + + // Put the pivot in the right place. + Iter pivot_pos = first - 1; + *begin = PDQSORT_PREFER_MOVE(*pivot_pos); + *pivot_pos = PDQSORT_PREFER_MOVE(pivot); + + return std::make_pair(pivot_pos, already_partitioned); + } + + // Similar function to the one above, except elements equal to the pivot are put to the left of + // the pivot and it doesn't check or return if the passed sequence already was partitioned. + // Since this is rarely used (the many equal case), and in that case pdqsort already has O(n) + // performance, no block quicksort is applied here for simplicity. + template + inline Iter partition_left(Iter begin, Iter end, Compare comp) { + typedef typename std::iterator_traits::value_type T; + + T pivot(PDQSORT_PREFER_MOVE(*begin)); + Iter first = begin; + Iter last = end; + + while (comp(pivot, *--last)); + + if (last + 1 == end) while (first < last && !comp(pivot, *++first)); + else while ( !comp(pivot, *++first)); + + while (first < last) { + std::iter_swap(first, last); + while (comp(pivot, *--last)); + while (!comp(pivot, *++first)); + } + + Iter pivot_pos = last; + *begin = PDQSORT_PREFER_MOVE(*pivot_pos); + *pivot_pos = PDQSORT_PREFER_MOVE(pivot); + + return pivot_pos; + } + + + template + inline void pdqsort_loop(Iter begin, Iter end, Compare comp, int bad_allowed, bool leftmost = true) { + typedef typename std::iterator_traits::difference_type diff_t; + + // Use a while loop for tail recursion elimination. + while (true) { + diff_t size = end - begin; + + // Insertion sort is faster for small arrays. + if (size < insertion_sort_threshold) { + if (leftmost) insertion_sort(begin, end, comp); + else unguarded_insertion_sort(begin, end, comp); + return; + } + + // Choose pivot as median of 3 or pseudomedian of 9. + diff_t s2 = size / 2; + if (size > ninther_threshold) { + sort3(begin, begin + s2, end - 1, comp); + sort3(begin + 1, begin + (s2 - 1), end - 2, comp); + sort3(begin + 2, begin + (s2 + 1), end - 3, comp); + sort3(begin + (s2 - 1), begin + s2, begin + (s2 + 1), comp); + std::iter_swap(begin, begin + s2); + } else sort3(begin + s2, begin, end - 1, comp); + + // If *(begin - 1) is the end of the right partition of a previous partition operation + // there is no element in [begin, end) that is smaller than *(begin - 1). Then if our + // pivot compares equal to *(begin - 1) we change strategy, putting equal elements in + // the left partition, greater elements in the right partition. We do not have to + // recurse on the left partition, since it's sorted (all equal). + if (!leftmost && !comp(*(begin - 1), *begin)) { + begin = partition_left(begin, end, comp) + 1; + continue; + } + + // Partition and get results. + std::pair part_result = + Branchless ? partition_right_branchless(begin, end, comp) + : partition_right(begin, end, comp); + Iter pivot_pos = part_result.first; + bool already_partitioned = part_result.second; + + // Check for a highly unbalanced partition. + diff_t l_size = pivot_pos - begin; + diff_t r_size = end - (pivot_pos + 1); + bool highly_unbalanced = l_size < size / 8 || r_size < size / 8; + + // If we got a highly unbalanced partition we shuffle elements to break many patterns. + if (highly_unbalanced) { + // If we had too many bad partitions, switch to heapsort to guarantee O(n log n). + if (--bad_allowed == 0) { + std::make_heap(begin, end, comp); + std::sort_heap(begin, end, comp); + return; + } + + if (l_size >= insertion_sort_threshold) { + std::iter_swap(begin, begin + l_size / 4); + std::iter_swap(pivot_pos - 1, pivot_pos - l_size / 4); + + if (l_size > ninther_threshold) { + std::iter_swap(begin + 1, begin + (l_size / 4 + 1)); + std::iter_swap(begin + 2, begin + (l_size / 4 + 2)); + std::iter_swap(pivot_pos - 2, pivot_pos - (l_size / 4 + 1)); + std::iter_swap(pivot_pos - 3, pivot_pos - (l_size / 4 + 2)); + } + } + + if (r_size >= insertion_sort_threshold) { + std::iter_swap(pivot_pos + 1, pivot_pos + (1 + r_size / 4)); + std::iter_swap(end - 1, end - r_size / 4); + + if (r_size > ninther_threshold) { + std::iter_swap(pivot_pos + 2, pivot_pos + (2 + r_size / 4)); + std::iter_swap(pivot_pos + 3, pivot_pos + (3 + r_size / 4)); + std::iter_swap(end - 2, end - (1 + r_size / 4)); + std::iter_swap(end - 3, end - (2 + r_size / 4)); + } + } + } else { + // If we were decently balanced and we tried to sort an already partitioned + // sequence try to use insertion sort. + if (already_partitioned && partial_insertion_sort(begin, pivot_pos, comp) + && partial_insertion_sort(pivot_pos + 1, end, comp)) return; + } + + // Sort the left partition first using recursion and do tail recursion elimination for + // the right-hand partition. + pdqsort_loop(begin, pivot_pos, comp, bad_allowed, leftmost); + begin = pivot_pos + 1; + leftmost = false; + } + } +} + + +template +inline void pdqsort(Iter begin, Iter end, Compare comp) { + if (begin == end) return; + +#if __cplusplus >= 201103L + pdqsort_detail::pdqsort_loop::type>::value && + std::is_arithmetic::value_type>::value>( + begin, end, comp, pdqsort_detail::log2(end - begin)); +#else + pdqsort_detail::pdqsort_loop( + begin, end, comp, pdqsort_detail::log2(end - begin)); +#endif +} + +template +inline void pdqsort(Iter begin, Iter end) { + typedef typename std::iterator_traits::value_type T; + pdqsort(begin, end, std::less()); +} + +template +inline void pdqsort_branchless(Iter begin, Iter end, Compare comp) { + if (begin == end) return; + pdqsort_detail::pdqsort_loop( + begin, end, comp, pdqsort_detail::log2(end - begin)); +} + +template +inline void pdqsort_branchless(Iter begin, Iter end) { + typedef typename std::iterator_traits::value_type T; + pdqsort_branchless(begin, end, std::less()); +} + +void PDQSort(SortArray& A) +{ + pdqsort(MyIterator(&A, 0), MyIterator(&A, A.size())); +} + +void PDQSortBranchless(SortArray& A) +{ + pdqsort_branchless(MyIterator(&A, 0), MyIterator(&A, A.size())); +} + +#undef PDQSORT_PREFER_MOVE + +#endif From 23ba1cf1f41d0cc37b8847d364ddf6832d11dd0b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:13:25 +0800 Subject: [PATCH 076/289] Updated files for Pattern Defeating Quick Sort --- src/SortAlgo.cpp | 52 ++++++++++-------------------------------------- src/SortAlgo.h | 2 ++ 2 files changed, 12 insertions(+), 42 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index c9c9d37d8..8d0a216df 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -83,6 +83,11 @@ const struct AlgoEntry g_algolist[] = { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " "two at left and one at right.") }, + { _("Pattern-Defeating Quick Sort"), &PDQSort, UINT_MAX, UINT_MAX, + _("Pattern-defeating quicksort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" + "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, + { _("Branchless Pattern-Defeating Quick Sort"), &PDQSortBranchless, UINT_MAX, UINT_MAX, + _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, @@ -1232,26 +1237,8 @@ void shiftElement(SortArray& A, size_t start, size_t end) // **************************************************************************** // *** In-Place Radix Sort LSD -/* -Copyright (c) 2019 w0rthy -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ +// Copyright (c) 2019 w0rthy + size_t maxLog(SortArray& A, size_t n, size_t base) { int max = A[0]; @@ -2073,27 +2060,8 @@ void CycleSort(SortArray& A) // **************************************************************************** -// *** Pairwise Sorting Network (Recursive and Iterative) -/* -Copyright (c) 2021 aphitorite -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ +// *** Pairwise Sorting Network (Recursive and Iterative) +// Copyright (c) 2021 aphitorite void compSwap(SortArray& A, size_t a, size_t b) { @@ -2166,4 +2134,4 @@ void PairwiseIterativeSort(SortArray& A) } } } -} +} \ No newline at end of file diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 417720e2f..9589dbac8 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -104,6 +104,8 @@ void StlHeapSort(class SortArray& a); void TimSort(class SortArray& a); void WikiSort(class SortArray& a); void GrailSort(class SortArray& a); +void PDQSort(class SortArray& a); +void PDQSortBranchless(class SortArray& a); void BadSort(class SortArray& a); void BogoSort(class SortArray& a); From 5eeadca5f5f1dbe9dd27dab16b39ddf9779f9b82 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:15:59 +0800 Subject: [PATCH 077/289] Readded notices --- src/SortAlgo.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 8d0a216df..0e3c6f376 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1237,7 +1237,24 @@ void shiftElement(SortArray& A, size_t start, size_t end) // **************************************************************************** // *** In-Place Radix Sort LSD -// Copyright (c) 2019 w0rthy +/* +Copyright (c) 2019 w0rthy +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ size_t maxLog(SortArray& A, size_t n, size_t base) { @@ -2061,7 +2078,24 @@ void CycleSort(SortArray& A) // **************************************************************************** // *** Pairwise Sorting Network (Recursive and Iterative) -// Copyright (c) 2021 aphitorite +/* +Copyright (c) 2021 aphitorite +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ void compSwap(SortArray& A, size_t a, size_t b) { From 834ca8ef81c9f51dd8a4a71aaa29f0c37fe4600a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:35:09 +0800 Subject: [PATCH 078/289] Fixed a specific section of Grail Sort being quiet InPlaceBufferReset() isn't yielding any sound, this fixes it. --- src/algorithms/grailsort.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 55ee1a5cf..de93124a9 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -52,6 +52,7 @@ #include #include #include +#include namespace grailsort_detail { @@ -509,11 +510,12 @@ namespace grailsort_detail static void InPlaceBufferReset(RandomAccessIterator array, int start, int length, int bufferOffset) { int index = start + length - 1; int buffer = index - bufferOffset; - + ArrayItem test = ArrayItem(index); while (index >= start) { + test.get(); std::swap(array[index], array[buffer]); - index--; - buffer--; + index--; buffer--; + test = ArrayItem(index); } } @@ -1327,4 +1329,4 @@ void GrailSort(SortArray& A) { grailsort(MyIterator(&A, 0), MyIterator(&A, A.size())); } -// **************************************************************************** +// **************************************************************************** \ No newline at end of file From b822fa3ca89b3c41248a13447102913393df0a22 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 03:54:54 +0800 Subject: [PATCH 079/289] Fixed Pattern-Defeating Quick Sort performing horribly This change also disables the pivot selection option for PDQ Sort, since the algorithm has its own way of selecting a pivot. --- src/SortAlgo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 0e3c6f376..b17754318 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -83,10 +83,10 @@ const struct AlgoEntry g_algolist[] = { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " "two at left and one at right.") }, - { _("Pattern-Defeating Quick Sort"), &PDQSort, UINT_MAX, UINT_MAX, + { _("PDQ Sort"), &PDQSort, UINT_MAX, inversion_count_instrumented, _("Pattern-defeating quicksort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, - { _("Branchless Pattern-Defeating Quick Sort"), &PDQSortBranchless, UINT_MAX, UINT_MAX, + { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, From baae0fb5863acb297b13ea123ca43bc7ceac03a2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 13:15:50 +0800 Subject: [PATCH 080/289] Fixed one more specific section of Grail Sort being quiet --- src/algorithms/grailsort.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index de93124a9..cbbcfc460 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -510,12 +510,12 @@ namespace grailsort_detail static void InPlaceBufferReset(RandomAccessIterator array, int start, int length, int bufferOffset) { int index = start + length - 1; int buffer = index - bufferOffset; - ArrayItem test = ArrayItem(index); + ArrayItem pos = ArrayItem(index); while (index >= start) { - test.get(); + pos.get(); std::swap(array[index], array[buffer]); index--; buffer--; - test = ArrayItem(index); + pos = ArrayItem(index); } } @@ -529,11 +529,12 @@ namespace grailsort_detail static void OutOfPlaceBufferReset(RandomAccessIterator array, int start, int length, int bufferOffset) { int index = start + length - 1; int buffer = index - bufferOffset; - + ArrayItem pos = ArrayItem(index); while (index >= start) { + pos.get(); array[index] = std::move(array[buffer]); - index--; - buffer--; + index--; buffer--; + pos = ArrayItem(index); } } From 14a5daa6b7a27e139df59f17e793e716c97663e8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 13:53:33 +0800 Subject: [PATCH 081/289] Changed NULL to nullptr This should avoid type ambiguity issues --- src/WMain.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 297d0a37a..7554b5ff7 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -29,7 +29,7 @@ WMain::WMain(wxWindow* parent) : WMain_wxg(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE) { - m_thread = NULL; + m_thread = nullptr; g_sound_on = false; recordButton->Hide(); @@ -88,7 +88,7 @@ WMain::WMain(wxWindow* parent) sdlaudiospec.userdata = sortview; // Open the audio device, forcing the desired format - if ( SDL_OpenAudio(&sdlaudiospec, NULL) < 0 ) { + if ( SDL_OpenAudio(&sdlaudiospec, nullptr) < 0 ) { wxLogError(_("Couldn't open audio: ") + wxString(SDL_GetError(), wxConvISO8859_1)); soundButton->Disable(); } @@ -174,7 +174,7 @@ void WMain::AbortAlgorithm() g_algo_running = false; delete m_thread; - m_thread = NULL; + m_thread = nullptr; } void WMain::OnRunButton(wxCommandEvent &event) @@ -186,7 +186,7 @@ void WMain::OnRunButton(wxCommandEvent &event) g_algo_running = false; delete m_thread; - m_thread = NULL; + m_thread = nullptr; } if (event.IsChecked()) @@ -221,7 +221,7 @@ void WMain::OnRunFinished(wxCommandEvent&) g_algo_running = false; delete m_thread; - m_thread = NULL; + m_thread = nullptr; } runButton->SetValue(false); @@ -455,7 +455,7 @@ class MyApp : public wxApp srand((int)wxGetLocalTime()); - WMain* wmain = new WMain(NULL); + WMain* wmain = new WMain(nullptr); SetTopWindow(wmain); wmain->Show(); From d4384c77ef0ed4fd1bb1255aedca011346e6b8fd Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 13:55:36 +0800 Subject: [PATCH 082/289] Changed NULL to nullptr --- src/SortArray.cpp | 4 ++-- src/WSortView.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index cb5814de8..bba007b12 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -55,7 +55,7 @@ void ArrayItem::OnComparison(const ArrayItem& a, const ArrayItem& b) SortArray::SortArray() : m_calc_inversions(false), - m_delay(NULL) + m_delay(nullptr) { } @@ -561,7 +561,7 @@ unsigned short SortArray::InWatchList(ssize_t idx) const { for (size_t i = 0; i < m_watch.size(); ++i) { - if (m_watch[i].first == NULL) continue; + if (m_watch[i].first == nullptr) continue; // compare watched value if (*m_watch[i].first != idx) continue; diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 1e9d731ba..4a27b2ee4 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -273,7 +273,7 @@ void* SortAlgoThread::Entry() wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, WMain::ID_RUN_FINISHED); m_wmain->GetEventHandler()->AddPendingEvent(evt); - return NULL; + return nullptr; } void SortAlgoThread::Exit() From db01e88f09d320ae02310497b461266c7f642391 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 14:02:19 +0800 Subject: [PATCH 083/289] Changed NULL to nullptr --- src/SortAlgo.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index b17754318..86dfdd67c 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -83,10 +83,10 @@ const struct AlgoEntry g_algolist[] = { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " "two at left and one at right.") }, - { _("PDQ Sort"), &PDQSort, UINT_MAX, inversion_count_instrumented, + { _("PDQ Sort"), &PDQSort, UINT_MAX, 128, _("Pattern-defeating quicksort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, - { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, + { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, 128, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, @@ -123,9 +123,9 @@ const struct AlgoEntry g_algolist[] = { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, _("Least significant digit radix sort, which copies item into a shadow " "array during counting.") }, - { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, UINT_MAX, + { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, 512, _("Least significant digit radix sort, performed in O(1) space.") }, - { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, + { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, 512, _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, wxEmptyString }, @@ -1402,7 +1402,7 @@ void BogoSort(SortArray& A) void BozoSort(SortArray& A) { - srand(time(NULL)); + srand(time(nullptr)); while (1) { From 0c3f400cc233b1c6da1b84f3fe103c25e008cc66 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 14:03:38 +0800 Subject: [PATCH 084/289] Reverted unnecessary changes --- src/SortAlgo.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 86dfdd67c..6965d27d7 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -83,10 +83,10 @@ const struct AlgoEntry g_algolist[] = { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " "two at left and one at right.") }, - { _("PDQ Sort"), &PDQSort, UINT_MAX, 128, + { _("PDQ Sort"), &PDQSort, UINT_MAX, inversion_count_instrumented, _("Pattern-defeating quicksort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, - { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, 128, + { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, @@ -123,9 +123,9 @@ const struct AlgoEntry g_algolist[] = { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, _("Least significant digit radix sort, which copies item into a shadow " "array during counting.") }, - { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, 512, + { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, UINT_MAX, _("Least significant digit radix sort, performed in O(1) space.") }, - { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, 512, + { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, wxEmptyString }, @@ -2168,4 +2168,4 @@ void PairwiseIterativeSort(SortArray& A) } } } -} \ No newline at end of file +} From 7b98306b6b69f00ebcb8ed1ae8a48dc415633779 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 14 Oct 2024 23:19:11 +0800 Subject: [PATCH 085/289] Add 2 new input types, Spike and Ribbon --- src/SortArray.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index bba007b12..fc85223ff 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -126,6 +126,8 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Reverse Sawtooth")); list.Add(_("Many Similar")); list.Add(_("Quicksort Killer")); + list.Add(_("Spike")); + list.Add(_("Ribbon")); } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -378,7 +380,40 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[j] = temp; } - } + } + else if (schema == 20) // Spike + { + int spike = 4; + int max = m_array.size() / (spike * 2); + int val = 1; + size_t n = m_array.size(); + for (size_t i = 0; i < n; ++i) + { + while (val <= max && i < n) + { + m_array[i] = ArrayItem(val); ++val; ++i; + } + if (max % 2 == 0) { val = max; } + else { val = max - 1; } + while (val > 0 && i < n) + { + m_array[i] = ArrayItem(val); --val; ++i; + } + val = 1; + if (i < n) { m_array[i] = ArrayItem(val); } + } + } + else if (schema == 21) // Ribbon + { + int min = 1; + int max = m_array.size(); + for (size_t i = 0; i < m_array.size(); ++i) + { + if (i % 2 == 0) { m_array[i] = ArrayItem(min); } + else { m_array[i] = ArrayItem(max); } + ++min; --max; + } + } else // fallback { return FillData(0, arraysize); From d405999345b8f9516f06479f141e511f0b5be391 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 01:32:58 +0800 Subject: [PATCH 086/289] Pipe Organ and Mirrored Organ for odd array sizes This change now allows Pipe Organ and Mirrored Organ to properly accommodate odd array sizes, this is inspired from my Spike array input implementation. --- src/SortArray.cpp | 61 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index fc85223ff..6730d26c5 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -278,28 +278,65 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } else if (schema == 13) // Pipe organ (1, 1, 2, 2, 1, 1) { - int val = 1; - for (size_t i = 0; i < m_array.size() / 2; ++i) + size_t n = m_array.size(); + + if (n % 2 == 0) { - m_array[i] = ArrayItem(val); ++val; + int val = 1; + for (size_t i = 0; i < n / 2; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + val = n / 2; + for (size_t i = n / 2; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); --val; + } } - val = m_array.size() / 2; - for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) + else { - m_array[i] = ArrayItem(val); --val; + int val = 1; + for (size_t i = 0; i <= n / 2; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + val = n / 2; + for (size_t i = (n / 2) + 1; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); --val; + } } } else if (schema == 14) // Mirrored organ (3, 2, 1, 1, 2, 3) { - int val = m_array.size() / 2; - for (size_t i = 0; i < m_array.size() / 2; ++i) + size_t n = m_array.size(); + + if (n % 2 == 0) { - m_array[i] = ArrayItem(val); --val; + int val = n / 2; + for (size_t i = 0; i < n / 2; ++i) + { + m_array[i] = ArrayItem(val); --val; + } + val = 1; + for (size_t i = n / 2; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } } - val = 1; - for (size_t i = m_array.size() / 2; i <= m_array.size() - 1; ++i) + else { - m_array[i] = ArrayItem(val); ++val; + int val = n / 2; + for (size_t i = 0; i <= n / 2; ++i) + { + m_array[i] = ArrayItem(val); + if (val >= 2) { --val; } + } + val = 1; + for (size_t i = (n / 2) + 1; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } } } else if (schema == 15) // Wave From 138711fc3250259327cf8bbfad3259f3ed0a1eb2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 03:24:25 +0800 Subject: [PATCH 087/289] Improved Sawtooth and Reverse Sawtooth The array generation of Sawtooth and Reverse Sawtooth is now made to be more adaptive and elegant looking for all possible array sizes. --- src/SortArray.cpp | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 6730d26c5..438eeb975 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -353,25 +353,57 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } else if (schema == 16) // Sawtooth { - int max = m_array.size() / 4; + size_t n = m_array.size(), teeth; + if (n % 5 == 0) { teeth = 5; } + else if (n % 4 == 0) { teeth = 4; } + else if (n % 3 == 0) { teeth = 3; } + else { teeth = 2; } + int max = n / teeth; int count = 1; - for (size_t i = 0; i < m_array.size(); ++i) + for (size_t i = 0; i < n; ++i) { if (count > max) { count = 1; } m_array[i] = ArrayItem(count); ++count; } + if (teeth == 2 && m_array[n - 1] == 1) + { + size_t m = n - 1; + while (m_array[m - 1] > m_array[m]) + { + ArrayItem temp = m_array[m - 1]; + m_array[m - 1] = m_array[m]; + m_array[m] = temp; + --m; + } + } } else if (schema == 17) // Reverse Sawtooth { - int max = m_array.size() / 4; + size_t n = m_array.size(), teeth; + if (n % 5 == 0) { teeth = 5; } + else if (n % 4 == 0) { teeth = 4; } + else if (n % 3 == 0) { teeth = 3; } + else { teeth = 2; } + int max = n / teeth; int count = max; - for (size_t i = 0; i < m_array.size(); ++i) + for (size_t i = 0; i < n; ++i) { if (count <= 0) { count = max; } m_array[i] = ArrayItem(count); --count; } + if (teeth == 2 && m_array[n - 1] == max) + { + size_t m = n - 1; + while (m_array[m - 1] < m_array[m]) + { + ArrayItem temp = m_array[m - 1]; + m_array[m - 1] = m_array[m]; + m_array[m] = temp; + --m; + } + } } else if (schema == 18) // Many Similar { From d24762bfe077066f8915695f4bcfe3d3e4a6e978 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 03:39:49 +0800 Subject: [PATCH 088/289] Improved Spike array input generation --- src/SortArray.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 438eeb975..b2f324c23 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -452,17 +452,21 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } else if (schema == 20) // Spike { - int spike = 4; - int max = m_array.size() / (spike * 2); - int val = 1; size_t n = m_array.size(); + int spike, val = 1; + if (n % 5 == 0) { spike = 5; } + else if (n % 4 == 0) { spike = 4; } + else if (n % 3 == 0) { spike = 3; } + else { spike = 2; } + int max = n / (spike * 2); + if (max == 1) { max = n / spike; } for (size_t i = 0; i < n; ++i) { while (val <= max && i < n) { m_array[i] = ArrayItem(val); ++val; ++i; } - if (max % 2 == 0) { val = max; } + if (max % 2 == 0 || (spike == 2 && max % 2 != 0)) { val = max; } else { val = max - 1; } while (val > 0 && i < n) { From 3a398d6314174459be4fd220014396f537ca455e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 08:45:07 +0800 Subject: [PATCH 089/289] Changed default teeth number --- src/SortArray.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b2f324c23..734488d78 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -356,8 +356,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) size_t n = m_array.size(), teeth; if (n % 5 == 0) { teeth = 5; } else if (n % 4 == 0) { teeth = 4; } - else if (n % 3 == 0) { teeth = 3; } - else { teeth = 2; } + else { teeth = 3; } int max = n / teeth; int count = 1; for (size_t i = 0; i < n; ++i) @@ -383,8 +382,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) size_t n = m_array.size(), teeth; if (n % 5 == 0) { teeth = 5; } else if (n % 4 == 0) { teeth = 4; } - else if (n % 3 == 0) { teeth = 3; } - else { teeth = 2; } + else { teeth = 3; } int max = n / teeth; int count = max; for (size_t i = 0; i < n; ++i) From 5480d3b306f7349dec82d1ccbfc6eb2186dd58d5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 21:57:41 +0800 Subject: [PATCH 090/289] Provided improvements to 3 array input types Reverted changes to Sawtooth and Reverse Sawtooth, Spike will now default to 2 spikes for prime array sizes. --- src/SortArray.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 734488d78..b2f324c23 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -356,7 +356,8 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) size_t n = m_array.size(), teeth; if (n % 5 == 0) { teeth = 5; } else if (n % 4 == 0) { teeth = 4; } - else { teeth = 3; } + else if (n % 3 == 0) { teeth = 3; } + else { teeth = 2; } int max = n / teeth; int count = 1; for (size_t i = 0; i < n; ++i) @@ -382,7 +383,8 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) size_t n = m_array.size(), teeth; if (n % 5 == 0) { teeth = 5; } else if (n % 4 == 0) { teeth = 4; } - else { teeth = 3; } + else if (n % 3 == 0) { teeth = 3; } + else { teeth = 2; } int max = n / teeth; int count = max; for (size_t i = 0; i < n; ++i) From aefdc4bdb2f3d10ad24dd7d0ec9dbf393d1ec36a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 22:11:53 +0800 Subject: [PATCH 091/289] Allowed usage of another Grail Sort method --- src/SortAlgo.cpp | 4 +++- src/SortAlgo.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 6965d27d7..7e557ce1b 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -137,8 +137,10 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, _("An O(1) place O(n log n) time stable merge sort.") }, - { _("Grail Sort"), &GrailSort, UINT_MAX, inversion_count_instrumented, + { _("Grail Sort (O(1) buffer)"), &GrailSort, UINT_MAX, inversion_count_instrumented, _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, + { _("Grail Sort (O(logn) buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, + _("A variant of Grail Sort that uses an external buffer for a potential speedup.") }, { _("Bead Sort"), &GravitySort, UINT_MAX, UINT_MAX, _("Also known as Gravity Sort. This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 9589dbac8..aa653f53f 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -104,6 +104,7 @@ void StlHeapSort(class SortArray& a); void TimSort(class SortArray& a); void WikiSort(class SortArray& a); void GrailSort(class SortArray& a); +void AuxGrailSort(class SortArray& a); void PDQSort(class SortArray& a); void PDQSortBranchless(class SortArray& a); From 4969712d9224edafa222a0645cfa17232c314c57 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 22:12:24 +0800 Subject: [PATCH 092/289] Another variant of Grail Sort can now be used --- src/algorithms/grailsort.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index cbbcfc460..da00ac744 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -1330,4 +1330,12 @@ void GrailSort(SortArray& A) { grailsort(MyIterator(&A, 0), MyIterator(&A, A.size())); } + +void AuxGrailSort(SortArray& A) +{ + size_t buf_size = log(A.size()); + if (buf_size == 0) { buf_size = 1; } + std::vector space_buf(buf_size, ArrayItem(0)); + grailsort(MyIterator(&A, 0), MyIterator(&A, A.size()), space_buf.begin(), space_buf.end()); +} // **************************************************************************** \ No newline at end of file From 85772bb7acff86b5fd284b91cdebf3515a3f465e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 22:26:16 +0800 Subject: [PATCH 093/289] Altered Auxilliary Grail Sort --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 7e557ce1b..fb5b52c85 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -139,7 +139,7 @@ const struct AlgoEntry g_algolist[] = _("An O(1) place O(n log n) time stable merge sort.") }, { _("Grail Sort (O(1) buffer)"), &GrailSort, UINT_MAX, inversion_count_instrumented, _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, - { _("Grail Sort (O(logn) buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, + { _("Grail Sort (10% array size buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, _("A variant of Grail Sort that uses an external buffer for a potential speedup.") }, { _("Bead Sort"), &GravitySort, UINT_MAX, UINT_MAX, _("Also known as Gravity Sort. This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, From 2b9892ff05f67100cd51a5149f4b061c3aa4fb61 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 15 Oct 2024 22:27:24 +0800 Subject: [PATCH 094/289] Improved Auxiliary Grail Sort O(logn) buffer apparently isn't going to take much effect, 10% array size buffer should provide some noticeable improvements without adding too much overhead. --- src/algorithms/grailsort.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index da00ac744..24b94e010 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -52,7 +52,6 @@ #include #include #include -#include namespace grailsort_detail { @@ -1333,7 +1332,7 @@ void GrailSort(SortArray& A) void AuxGrailSort(SortArray& A) { - size_t buf_size = log(A.size()); + size_t buf_size = A.size() / 10; if (buf_size == 0) { buf_size = 1; } std::vector space_buf(buf_size, ArrayItem(0)); grailsort(MyIterator(&A, 0), MyIterator(&A, A.size()), space_buf.begin(), space_buf.end()); From 5144288bba3b52bc4969f29bfb144b9904e76475 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 16 Oct 2024 01:28:06 +0800 Subject: [PATCH 095/289] Changed Grail Sort variant name I made this variant have a generic name rather than being too specific on how it creates the external buffer, that way I don't have to keep on modifying this file if I alter how this variant works --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index fb5b52c85..344e9218a 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -139,7 +139,7 @@ const struct AlgoEntry g_algolist[] = _("An O(1) place O(n log n) time stable merge sort.") }, { _("Grail Sort (O(1) buffer)"), &GrailSort, UINT_MAX, inversion_count_instrumented, _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, - { _("Grail Sort (10% array size buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, + { _("Grail Sort (external buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, _("A variant of Grail Sort that uses an external buffer for a potential speedup.") }, { _("Bead Sort"), &GravitySort, UINT_MAX, UINT_MAX, _("Also known as Gravity Sort. This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, From 315d147328abbeadc24102be03ce1c140f10e52c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 16 Oct 2024 01:37:44 +0800 Subject: [PATCH 096/289] Altered Auxiliary Grail Sort This should make the external buffer declaration to be as simple and performant as possible. Grail Sort doesn't really use that much memory, and I think higher fixed external buffer sizes wouldn't make much sense too. --- src/algorithms/grailsort.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 24b94e010..9db6175c6 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -1332,9 +1332,7 @@ void GrailSort(SortArray& A) void AuxGrailSort(SortArray& A) { - size_t buf_size = A.size() / 10; - if (buf_size == 0) { buf_size = 1; } - std::vector space_buf(buf_size, ArrayItem(0)); + std::vector space_buf(32, ArrayItem(0)); grailsort(MyIterator(&A, 0), MyIterator(&A, A.size()), space_buf.begin(), space_buf.end()); } // **************************************************************************** \ No newline at end of file From 903e128cd34437720a695b9a0464de3a2824d808 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 16 Oct 2024 10:24:39 +0800 Subject: [PATCH 097/289] Improved Spike array generation After further testing, this should be the finalized version of it. The Insertion Sort-like logic here is used to smoothen out partially generated spikes for some array length sizes, particularly if it is a prime number. --- src/SortArray.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b2f324c23..6ace6174e 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -454,9 +454,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { size_t n = m_array.size(); int spike, val = 1; - if (n % 5 == 0) { spike = 5; } - else if (n % 4 == 0) { spike = 4; } - else if (n % 3 == 0) { spike = 3; } + if (n % 10 == 0) { spike = 5; } + else if (n % 8 == 0) { spike = 4; } + else if (n % 6 == 0) { spike = 3; } else { spike = 2; } int max = n / (spike * 2); if (max == 1) { max = n / spike; } @@ -466,14 +466,29 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(val); ++val; ++i; } - if (max % 2 == 0 || (spike == 2 && max % 2 != 0)) { val = max; } + if (n % 2 == 0) { val = max; } else { val = max - 1; } while (val > 0 && i < n) { - m_array[i] = ArrayItem(val); --val; ++i; + m_array[i] = ArrayItem(val); --val; + if (val != 0) { ++i; } } val = 1; - if (i < n) { m_array[i] = ArrayItem(val); } + } + size_t start, end; + start = end = m_array.size() - 1; + while (m_array[start - 1] < m_array[start]) + { --start; } + for (; start <= end; ++start) + { + ArrayItem key = m_array[start]; + size_t j = start; + while (j >= 1 && m_array[j - 1] <= key) + { + m_array[j] = m_array[j - 1]; + --j; + } + m_array[j] = key; } } else if (schema == 21) // Ribbon From a58138102e600191071a2251cd270818376f5005 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 16 Oct 2024 11:53:48 +0800 Subject: [PATCH 098/289] Raised external buffer size for Grail Sort I take back what I said earlier. Based on my findings, Grail Sort uses at most sqrt(n) * 2 memory, so having a fixed size of 32 is bad for large arrays. The reason why I picked 512 is because, for reference, sqrt(65536) * 2 = 512, but TSoS won't be able to even display 16384 elements without any aggressive downscaling. I do know that visualizations today can't display more than 32768 elements, but the value of 512 is essentially a futureproof solution for me, in case either me, or someone else could allow the application to display such large array sizes. --- src/algorithms/grailsort.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 9db6175c6..7a581534e 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -1332,7 +1332,7 @@ void GrailSort(SortArray& A) void AuxGrailSort(SortArray& A) { - std::vector space_buf(32, ArrayItem(0)); + std::vector space_buf(512, ArrayItem(0)); grailsort(MyIterator(&A, 0), MyIterator(&A, A.size()), space_buf.begin(), space_buf.end()); } -// **************************************************************************** \ No newline at end of file +// **************************************************************************** From ef661e80435dbaef49b0932b352358ff99ca4fd2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 16 Oct 2024 11:59:40 +0800 Subject: [PATCH 099/289] Even more aggresive downscaling factor I changed the scaling factor from 0.1 to 0.05, this should allow the application to display larger arrays sizes even on a smaller window. I have tested this, and 8192 elements can now be displayed even if the application is not maximized. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 4a27b2ee4..8bf8e2937 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -173,7 +173,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) double wbar = (width - (size - 1)) / (double)size; double bstep = wbar + 1.0; if (size > width) { - wbar = wxMax(0.1, width / (double)size); // Scale down further if too many elements + wbar = wxMax(0.05, width / (double)size); // Scale down further if too many elements bstep = wbar; } From 75ddde7c133f4eeaaf90765f70713e2bd2321186 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 00:01:08 +0800 Subject: [PATCH 100/289] Visualization of elements with a step index This is a new strategy that I have discovered recently while I was asking how some other sorting algorithms are capable of displaying higher array sizes without the display being so dense. Apparently, only displaying elements based on a step index allows for displaying of higher array sizes while also making the visualization look relatively normal, and this change finally provides that "optimization". The application should now be able to render even higher array sizes than 8192 elements without the visualized array looking too compressed. There have been a few variants to this approach that I came with this final code. The previous approach involves skipping through element indices entirely using "i += step", but this breaks all sorting algorithms. Instead, this approach reads the entire array, but only visualizes elements that must be visualized using the step variable. This approach also avoids having to create unnecessary "dummy" element bars, it just reads the entire array but visualizes select elements. --- src/WSortView.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 8bf8e2937..76cd9f8eb 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -170,9 +170,11 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) //double bstep = 1.5 * wbar; // 2nd variant: one pixel between bars + size_t step = 1; double wbar = (width - (size - 1)) / (double)size; double bstep = wbar + 1.0; if (size > width) { + step = size / width; wbar = wxMax(0.05, width / (double)size); // Scale down further if too many elements bstep = wbar; } @@ -224,20 +226,23 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) wxMutexLocker lock(m_array.m_mutex); ASSERT(lock.IsOk()); + size_t i_step = step; for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); - - ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); - dc.SetPen(pens[clr]); - dc.SetBrush(brushes[clr]); - - dc.DrawRectangle(i * bstep, height, - wxMax(1, // draw at least 1 pixel - (wxCoord((i + 1) * bstep) - wxCoord(i * bstep)) // integral gap to next bar - - (bstep - wbar) // space between bars - ), - -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); + if (i == i_step) + { + ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); + dc.SetPen(pens[clr]); + dc.SetBrush(brushes[clr]); + dc.DrawRectangle(i * bstep, height, + wxMax(1, // draw at least 1 pixel + (wxCoord((i + 1) * bstep) - wxCoord(i * bstep)) // integral gap to next bar + - (bstep - wbar) // space between bars + ), + -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); + i_step += step; + } } }; From 051f96cf37b7f67cdf8852b0fac0982e33b8de10 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 01:04:44 +0800 Subject: [PATCH 101/289] Fixed step-based array element visualization This fixes a minor issue where the very first element is not displayed if no elements must be skipped during the visualization process. --- src/WSortView.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 76cd9f8eb..441db7bd5 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -226,12 +226,32 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) wxMutexLocker lock(m_array.m_mutex); ASSERT(lock.IsOk()); - size_t i_step = step; - for (size_t i = 0; i < size; ++i) + if (step > 1) { - int clr = m_array.GetIndexColor(i); - if (i == i_step) + size_t i_step = step; + for (size_t i = 0; i < size; ++i) { + int clr = m_array.GetIndexColor(i); + if (i == i_step) + { + ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); + dc.SetPen(pens[clr]); + dc.SetBrush(brushes[clr]); + dc.DrawRectangle(i * bstep, height, + wxMax(1, // draw at least 1 pixel + (wxCoord((i + 1) * bstep) - wxCoord(i * bstep)) // integral gap to next bar + - (bstep - wbar) // space between bars + ), + -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); + i_step += step; + } + } + } + else + { + for (size_t i = 0; i < size; ++i) + { + int clr = m_array.GetIndexColor(i); ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); dc.SetPen(pens[clr]); dc.SetBrush(brushes[clr]); @@ -241,7 +261,6 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) - (bstep - wbar) // space between bars ), -(double)height * m_array.direct(i).get_direct() / m_array.array_max()); - i_step += step; } } }; From 35dc317ad64a9e3279d9c7df697a07248cadf677 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 02:19:39 +0800 Subject: [PATCH 102/289] Allow array slider to go up to 16384 elements Since the new rendering change now allows displaying of large array sizes while the visualization will still look relatively normal, this means that the application should now be able to display up to 16384 elements without having a condensed display. Yes, loading up even more elements could take a while, but please take note that this is not because of "slow rendering", the step visualization is only rendering elements based on the dynamically calculated step, it never renders anything unnecessary. The reason why larger array sizes take a while to load is because the paint() method needs to scan the entire array, even if it only needs to display a select amount of elements. --- src/wxg/WMain_wxg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index 86f0b42b8..1fc79ab99 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -44,7 +44,7 @@ WMain_wxg::WMain_wxg(wxWindow* parent, int id, const wxString& title, const wxPo labelRunsCount = new wxClickText(splitter_0_pane_2, wxID_ANY, wxEmptyString); const wxString *inputTypeChoice_choices = NULL; inputTypeChoice = new wxChoice(splitter_0_pane_2, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, inputTypeChoice_choices, 0); - arraySizeSlider = new wxSlider(splitter_0_pane_2, ID_ARRAY_SIZE_SLIDER, 0, 1, 8192); + arraySizeSlider = new wxSlider(splitter_0_pane_2, ID_ARRAY_SIZE_SLIDER, 0, 1, 16384); labelArraySizeValue = new wxStaticText(splitter_0_pane_2, wxID_ANY, _("1024"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE|wxST_NO_AUTORESIZE); const wxString *algoList_choices = NULL; algoList = new wxListBox(splitter_0_pane_2, ID_ALGO_LIST, wxDefaultPosition, wxDefaultSize, 0, algoList_choices, wxLB_SINGLE); From 6f895a86da1014ce1c604b454c15236e46e49a7c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 02:27:16 +0800 Subject: [PATCH 103/289] More aggressive downscaling This change allows the application to display 16384 elements even on the minimum application window size. The application still needs the downscaling formula for the step visualization change to work. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 441db7bd5..9c86a209f 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -175,7 +175,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) double bstep = wbar + 1.0; if (size > width) { step = size / width; - wbar = wxMax(0.05, width / (double)size); // Scale down further if too many elements + wbar = wxMax(0.03, width / (double)size); // Scale down further if too many elements bstep = wbar; } From ce496dbfec09b92b8a1bfe52e92eae2426c59b49 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 03:03:32 +0800 Subject: [PATCH 104/289] Allow display of 5 digit array size The application can now display 5-digit array sizes with no problem at all. --- src/wxg/WMain_wxg.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index 1fc79ab99..b8888d703 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -135,6 +135,7 @@ void WMain_wxg::do_layout() grid_sizer_1->Add(labelArraySize, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 4); sizer_6->Add(arraySizeSlider, 1, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 4); sizer_6->Add(labelArraySizeValue, 0, wxLEFT|wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE, 4); + labelArraySizeValue->SetMinSize(wxSize(39, -1)); grid_sizer_1->Add(sizer_6, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->AddGrowableCol(1); sizerInputAlgorithm->Add(grid_sizer_1, 0, wxEXPAND, 0); From 437c48b970c52e47ecdbf70564803de0aa112624 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 09:43:08 +0800 Subject: [PATCH 105/289] Fixed Heap Sort crashing with step visualization This change allows Heap Sort to work with the visualized array where some of the elements are skipped during the rendering process. A portion of the array is in white color, but I believe that is better than Heap Sort making the program crash. --- src/WSortView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 9c86a209f..98566e761 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -234,7 +234,8 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) int clr = m_array.GetIndexColor(i); if (i == i_step) { - ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); + int numBrushes = sizeof(brushes) / sizeof(brushes[0]); + clr = clr % numBrushes; dc.SetPen(pens[clr]); dc.SetBrush(brushes[clr]); dc.DrawRectangle(i * bstep, height, From b39e8f78d4c9cd6be96263d6110a85de4f840c81 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 12:12:58 +0800 Subject: [PATCH 106/289] Fixed Heap Sort colors during sorting This fixes the white colored portion of Heap Sort during the sorting process when the visualized array skips some elements. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 98566e761..41e37b20a 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -235,7 +235,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) if (i == i_step) { int numBrushes = sizeof(brushes) / sizeof(brushes[0]); - clr = clr % numBrushes; + clr = (clr + numBrushes) % numBrushes; dc.SetPen(pens[clr]); dc.SetBrush(brushes[clr]); dc.DrawRectangle(i * bstep, height, From 2a2b1d709b6ed2c319ca50defe91c6811e092229 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 19:37:09 +0800 Subject: [PATCH 107/289] Fixed Heap Sort colors during sorting By adding more colors to the brush and pen array, Heap Sort finally doesn't have a white portion while sorting, even at the max element display of 16384! --- src/WSortView.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 41e37b20a..d7bdc6b56 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -201,6 +201,16 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) wxPen(wxColour(128,192,192)), // 14 dark cyan wxPen(wxColour(192,192,128)), // 15 dark yellow wxPen(wxColour(0,128,255)), // 16 blue/cyan mix + wxPen(wxColour(255,64,64)), // 17 bright red + wxPen(wxColour(64,255,64)), // 18 bright green + wxPen(wxColour(64,64,255)), // 19 bright blue + wxPen(wxColour(255,128,64)), // 20 coral + wxPen(wxColour(128,255,64)), // 21 lime green + wxPen(wxColour(64,255,255)), // 22 aqua + wxPen(wxColour(255,215,0)), // 23 gold + wxPen(wxColour(128,0,128)), // 24 purple + wxPen(wxColour(0,255,127)), // 25 spring green + wxPen(wxColour(255,69,0)), // 26 orange red }; static const wxBrush brushes[] = { @@ -221,6 +231,16 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) wxBrush(wxColour(128,192,192)), // 14 dark cyan wxBrush(wxColour(192,192,128)), // 15 dark yellow wxBrush(wxColour(0,128,255)), // 16 blue/cyan mix + wxBrush(wxColour(255,64,64)), // 17 bright red + wxBrush(wxColour(64,255,64)), // 18 bright green + wxBrush(wxColour(64,64,255)), // 19 bright blue + wxBrush(wxColour(255,128,64)), // 20 coral + wxBrush(wxColour(128,255,64)), // 21 lime green + wxBrush(wxColour(64,255,255)), // 22 aqua + wxBrush(wxColour(255,215,0)), // 23 bright yellow + wxBrush(wxColour(128,0,128)), // 24 purple + wxBrush(wxColour(0,255,127)), // 25 spring green + wxBrush(wxColour(255,69,0)), // 26 orange red }; wxMutexLocker lock(m_array.m_mutex); @@ -235,7 +255,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) if (i == i_step) { int numBrushes = sizeof(brushes) / sizeof(brushes[0]); - clr = (clr + numBrushes) % numBrushes; + clr = clr % numBrushes; dc.SetPen(pens[clr]); dc.SetBrush(brushes[clr]); dc.DrawRectangle(i * bstep, height, From 7103a46e8e1e37b557f7df12d58eac45fadd5ca8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 19:48:52 +0800 Subject: [PATCH 108/289] Removed deprecated warning This change avoids the deprecated constructor warning if the application is compiled with wxWidgets 3.1.6 and above, while still allowing for compatibility with older wxWidgets versions. From 6806bd093f8ea61007f07f2bf427a1fef05235ec Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 19:50:24 +0800 Subject: [PATCH 109/289] Removed deprecated warning This change avoids the deprecated constructor warning if the application is compiled with wxWidgets 3.1.6 and above, while still allowing for compatibility with older wxWidgets versions. --- src/wxg/WAbout_wxg.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wxg/WAbout_wxg.cpp b/src/wxg/WAbout_wxg.cpp index e581bbc47..588aa2284 100644 --- a/src/wxg/WAbout_wxg.cpp +++ b/src/wxg/WAbout_wxg.cpp @@ -34,7 +34,11 @@ void WAbout_wxg::set_properties() { // begin wxGlade: WAbout_wxg::set_properties SetTitle(_("About")); - labelTitle->SetFont(wxFont(14, wxDEFAULT, wxNORMAL, wxNORMAL, 0, wxT(""))); + #if wxCHECK_VERSION(3, 1, 6) + labelTitle->SetFont(wxFont(14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + #else + labelTitle->SetFont(wxFont(14, wxDEFAULT, wxNORMAL, wxNORMAL, 0, wxT(""))); + #endif // end wxGlade } From e133f4a3c4f5ed91b037862185a3578ea431ed7a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 20:54:00 +0800 Subject: [PATCH 110/289] Fixed minor bug on step visualization The very first item of the array during step visualization is ignored, which is not intended, this small change fixes that issue. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index d7bdc6b56..8bb21e2cb 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -252,7 +252,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); - if (i == i_step) + if (i == i_step || i == 0) { int numBrushes = sizeof(brushes) / sizeof(brushes[0]); clr = clr % numBrushes; From e479b0e40b9e8d06640f63656cedf60252466820 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 17 Oct 2024 21:58:32 +0800 Subject: [PATCH 111/289] Calculate brushes array size once This fixes one minor issue on the step visualization logic, in which it has to recalculate the brushes array size in each iteration. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 8bb21e2cb..b4494c447 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -249,12 +249,12 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) if (step > 1) { size_t i_step = step; + int numBrushes = sizeof(brushes) / sizeof(brushes[0]); for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); if (i == i_step || i == 0) { - int numBrushes = sizeof(brushes) / sizeof(brushes[0]); clr = clr % numBrushes; dc.SetPen(pens[clr]); dc.SetBrush(brushes[clr]); From 7df2a1a931b397d32fcb71cf53c90a7a87400295 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 08:04:17 +0800 Subject: [PATCH 112/289] Improve inversions calculation for set() After observing the inversions calculation for a while, I noticed that set() calls RecalcInversions() which counts inversions in O(n^2) time, which is unnecessary. This change makes it so that, first, the inversions of the old value will be counted by checking all numbers in the entire array, when the inversions of the old value are counted, the total number of inversions will now be subtracted with the inversions of the old value. When the old value has been overwritten with the new value, the inversions of the new value will be counted, and then it will be added on the total number of inversions. This should make set() only recount inversions in O(2n) time rather than O(n^2) time, massively reducing overhead. --- src/SortArray.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/SortArray.h | 7 +++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 6ace6174e..a9a6f8555 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -583,6 +583,44 @@ void SortArray::RecalcInversions() m_inversions = inversions; } +void SortArray::AddInversions(size_t pos) +{ + if (!m_calc_inversions) { + m_inversions = -1; + return; + } + + const ArrayItem& a = direct(pos); + unsigned int inverses = 0; + for (size_t i = 0; i < size(); ++i) + { + if (i == pos) { continue; } + const ArrayItem& b = direct(i); + if (a.greater_direct(b)) { ++inverses; } + } + + m_inversions += inverses; +} + +void SortArray::RemoveInversions(size_t pos) +{ + if (!m_calc_inversions) { + m_inversions = -1; + return; + } + + const ArrayItem& a = direct(pos); + unsigned int inverses = 0; + for (size_t i = 0; i < size(); ++i) + { + if (i == pos) { continue; } + const ArrayItem& b = direct(i); + if (a.greater_direct(b)) { ++inverses; } + } + + m_inversions -= inverses; +} + void SortArray::UpdateInversions(size_t i, size_t j) { if (!m_calc_inversions) { diff --git a/src/SortArray.h b/src/SortArray.h index 1093079cb..320dbc017 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -207,6 +207,9 @@ class SortArray /// turn on/off calculation of inversions void SetCalcInversions(bool on); + void AddInversions(size_t i); + void RemoveInversions(size_t i); + /// toggle boolean to calculate inversions void ToggleCalcInversions(); @@ -313,7 +316,6 @@ class SortArray OnAccess(); } - RecalcInversions(); return m_array[i]; } @@ -344,6 +346,7 @@ class SortArray void set(size_t i, const ArrayItem& v) { ASSERT(i < m_array.size()); + RemoveInversions(i); { wxMutexLocker lock(m_mutex); @@ -355,7 +358,7 @@ class SortArray m_array[i] = v; } - RecalcInversions(); + AddInversions(i); OnAccess(); } From 10836c1156108316e7d72e4649ba3ce2a685beeb Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 08:16:27 +0800 Subject: [PATCH 113/289] Reduced comparisons for inversions calculation I did realize that "i == pos" is not needed since greater_direct has a very strict rule for comparing 2 values. This should slightly improve the performance of the 2 inversions calculation methods. --- src/SortArray.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index a9a6f8555..b4df84b4d 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -594,7 +594,6 @@ void SortArray::AddInversions(size_t pos) unsigned int inverses = 0; for (size_t i = 0; i < size(); ++i) { - if (i == pos) { continue; } const ArrayItem& b = direct(i); if (a.greater_direct(b)) { ++inverses; } } @@ -613,7 +612,6 @@ void SortArray::RemoveInversions(size_t pos) unsigned int inverses = 0; for (size_t i = 0; i < size(); ++i) { - if (i == pos) { continue; } const ArrayItem& b = direct(i); if (a.greater_direct(b)) { ++inverses; } } From f14bb5d1f9b2907eb46ea7110643bb84bad9f962 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 08:57:49 +0800 Subject: [PATCH 114/289] Insertion Sort altered I have made the application now use InsertionSort2() for Insertion Sort, which I have improved so that it closely resembles the original Insertion Sort, this should make the sorting algorithm to be performant, since shifting isn't as heavy as swapping. --- src/SortAlgo.cpp | 16 ++++++++-------- src/SortAlgo.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 344e9218a..2d2680fcd 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -56,7 +56,7 @@ const struct AlgoEntry g_algolist[] = _("Also known as Exchange Sort.") }, { _("Double Sandpaper Sort"), &DoubleSandpaperSort, UINT_MAX, UINT_MAX, _("A variant of Exchange Sort that sorts the array bidirectionally.") }, - { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, + { _("Insertion Sort"), &InsertionSort2, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, wxEmptyString }, @@ -288,14 +288,14 @@ void InsertionSort2(SortArray& A) for (size_t i = 1; i < A.size(); ++i) { A.mark(i); - ssize_t j = i - 1; - value_type tmp = A[j], key = A[i]; - while (j >= 0 && tmp > key) + size_t j = i; + value_type key = A[i]; + while (j >= 1 && A[j - 1] > key) { - A.set(j + 1, tmp); - j--; + A.set(j, A[j - 1]); + --j; } - A.set(j + 1, key); + A.set(j, key); A.unmark(i); } @@ -2170,4 +2170,4 @@ void PairwiseIterativeSort(SortArray& A) } } } -} +} \ No newline at end of file diff --git a/src/SortAlgo.h b/src/SortAlgo.h index aa653f53f..64f6c00fe 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -56,7 +56,7 @@ void SelectionSort(class SortArray& a); void DoubleSelectionSort(class SortArray& a); void SandpaperSort(class SortArray& a); void DoubleSandpaperSort(class SortArray& a); -void InsertionSort(class SortArray& a); +void InsertionSort2(class SortArray& a); void BinaryInsertionSort(class SortArray& a); void MergeSort(class SortArray& a); From f2d50a440307907111af99112b0518e6c5b080f3 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 09:20:48 +0800 Subject: [PATCH 115/289] Altered Binary Insertion Sort Binary Insertion Sort now also uses shifting instead of swapping. The original implementation has been kept but simply "disabled". --- src/SortAlgo.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 2d2680fcd..3d71b0220 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -302,7 +302,7 @@ void InsertionSort2(SortArray& A) } // swaps every time (keeps all values visible) -void BinaryInsertionSort(SortArray& A) +void BinaryInsertionSort2(SortArray& A) { for (size_t i = 1; i < A.size(); ++i) { @@ -323,7 +323,7 @@ void BinaryInsertionSort(SortArray& A) ssize_t j = i - 1; while (j >= lo) { - A.swap(j, j+1); + A.swap(j, j + 1); j--; } @@ -331,6 +331,35 @@ void BinaryInsertionSort(SortArray& A) } } +void BinaryInsertionSort(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ++i) + { + value_type key = A[i]; + A.mark(i); + + size_t lo = 0, hi = i; + while (lo < hi) { + size_t mid = (lo + hi) / 2; + if (key < A[mid]) + hi = mid; + else + lo = mid + 1; + } + + // item has to go into position lo + + size_t j = i; + while (j > lo) + { + A.set(j, A[j - 1]); + j--; + } + A.set(lo, key); + A.unmark(i); + } +} + // **************************************************************************** // *** Merge Sort (out-of-place with sentinels) From fa2f574e38af08646edfb1249708f3c4a35d6a0a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 13:47:42 +0800 Subject: [PATCH 116/289] Fixed inversions calculation I realized that my initial inversions calculation is incorrect. In order to count the inversions properly, for example, in a sorted array, all numbers at the left side of n are lesser, while all numbers at the right side of n is greater. Using this information, to count the inversions, only either side of n (the number that will be used to "divide" the array) must be evaluated, rather than reading the entire array. In this approach, the left side of n will be evaluated to see if any numbers are greater than n, if a number is greater than n and it is on the left side of n, then this number is not on its correct position, because if the array is sorted, all numbers at the left side of n must be lesser than n, therefore, the inverses variable must be incremented by one. --- src/SortArray.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b4df84b4d..3d0044025 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -592,10 +592,10 @@ void SortArray::AddInversions(size_t pos) const ArrayItem& a = direct(pos); unsigned int inverses = 0; - for (size_t i = 0; i < size(); ++i) + for (size_t i = 0; i < pos; ++i) { const ArrayItem& b = direct(i); - if (a.greater_direct(b)) { ++inverses; } + if (b.greater_direct(a)) { ++inverses; } } m_inversions += inverses; @@ -610,10 +610,10 @@ void SortArray::RemoveInversions(size_t pos) const ArrayItem& a = direct(pos); unsigned int inverses = 0; - for (size_t i = 0; i < size(); ++i) + for (size_t i = 0; i < pos; ++i) { const ArrayItem& b = direct(i); - if (a.greater_direct(b)) { ++inverses; } + if (b.greater_direct(a)) { ++inverses; } } m_inversions -= inverses; From f47de870d336b8e3a9ff6b08bad6b675e0e32f50 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 19:55:21 +0800 Subject: [PATCH 117/289] Introduced an incredibly sensitive speed delay formula This speed delay formula will allow the application to reach speeds as low as 0.001 ms, but when this formula is used, the slider will never go past 0.005 ms. To ensure that such small values can be seen, the application must be able to display up to 3 decimal numbers at once, which is also included in this change, --- src/WMain.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 7554b5ff7..68cb4ee5f 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -316,20 +316,24 @@ void WMain::SetDelay(size_t pos) const double base = 4; // different slider scale for Linux/GTK: (faster) + // 0.001 ms formula, tested on Windows + // Warning! The slider will never go past 0.005 ms with this formula + // g_delay = pow(base, pos / 15000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 750.0; #if __WXGTK__ || MSW_PERFORMANCECOUNTER g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; #else // other systems probably have sucking real-time performance anyway g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0) / log(base)); + #endif if (pos == 0) g_delay = 0; if (g_delay > 10) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); else if (g_delay > 1) - labelDelayValue->SetLabel(wxString::Format(_("%.1f ms"), g_delay)); - else labelDelayValue->SetLabel(wxString::Format(_("%.2f ms"), g_delay)); + else + labelDelayValue->SetLabel(wxString::Format(_("%.3f ms"), g_delay)); } void WMain::OnSoundSustainSliderChange(wxScrollEvent &event) From 849330ae2af9c64d452fa2f642489cc51a8f176c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 20:07:50 +0800 Subject: [PATCH 118/289] Slightly raised 0.001 ms speed formula --- src/WMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 68cb4ee5f..f937a90a4 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -318,7 +318,7 @@ void WMain::SetDelay(size_t pos) // different slider scale for Linux/GTK: (faster) // 0.001 ms formula, tested on Windows // Warning! The slider will never go past 0.005 ms with this formula - // g_delay = pow(base, pos / 15000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 750.0; + // g_delay = pow(base, pos / 15000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 800.0; #if __WXGTK__ || MSW_PERFORMANCECOUNTER g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; #else From 3ef25f047d516882ae2b7c9282e5c6ad311fdcda Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 20:10:19 +0800 Subject: [PATCH 119/289] Relocated aggressive speed delay formula --- src/WMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index f937a90a4..1c880a0f0 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -316,10 +316,10 @@ void WMain::SetDelay(size_t pos) const double base = 4; // different slider scale for Linux/GTK: (faster) +#if __WXGTK__ || MSW_PERFORMANCECOUNTER // 0.001 ms formula, tested on Windows // Warning! The slider will never go past 0.005 ms with this formula // g_delay = pow(base, pos / 15000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 800.0; -#if __WXGTK__ || MSW_PERFORMANCECOUNTER g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; #else // other systems probably have sucking real-time performance anyway From 2e1da8528c46addbefc4825ba6e544210c612b49 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 18 Oct 2024 22:41:16 +0800 Subject: [PATCH 120/289] Readded RecalcInversions() call This is indeed a dilemma, but I did come up with an acceptable conclusion anyway. The get_mutable() method is an important method for the MyIterator class, as it allows modification of array elements for sorting algorithms that use iterators. However, get_mutable() calls RecalcInversions(), which is an O(n^2) method that counts for inversions of the array. One could say that "well, it just counts for inversions anyway so what's the problem?" but, as always, never underestimate how terrible O(n^2) can be, especially if this code is in a method that is called frequently, or it is a core method. At first, I thought that removing the RecalcInversions() call will make this method fast, and well yeah it is, since RecalcInversions() must finish first before get_mutable() returns an item. However, removing this call breaks inversions counting for iterator-based sorting algorithms, such as Grail Sort and Pattern-Defeating Quick Sort. Yes, this is also related to that one other commit I did where I disabled inversions counting for Pattern-Defeating Quick Sort because it performs horribly with it, and this is indeed the reason why, because of the RecalcInversions() call. So, what now? What can be done? Here is one thing I could say: It is pretty obvious that the RecalcInversions() call cannot be removed, since it is a "core" function. However, one thing to duly take note is that although manual, the application allows skipping of inversions counting for a specific sorting algorithm, so if one wishes to skip inversions counting for that specific algorithm, then all they have to do is go to SortAlgo.cpp and make the necessary changes. This will avoid the repeated O(n^2) call completely, and this is great if you don't really need inversions counting too. This is especially the case with Pattern-Defeating Quick Sort, in which it performs terribly if inversions counting is allowed for this algorithm. However, if you do need inversions counting, then you really have no choice but to put up with the repeated O(n^2) call. Removing the RecalcInversions() call completely is not a good idea at all, since you do have the choice of disabling inversions counting for a specific sorting algorithm if you wish. Well, that's it, at least I have still made set() to be faster, set() doesn't need to do an O(n^2) operation per call. --- src/SortArray.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SortArray.h b/src/SortArray.h index 320dbc017..e22141043 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -316,6 +316,7 @@ class SortArray OnAccess(); } + RecalcInversions(); return m_array[i]; } From 7cc2cba8ca5492dae2d7824d8d861d6872ee62e8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 19 Oct 2024 07:19:13 +0800 Subject: [PATCH 121/289] Added American Flag Sort --- src/SortAlgo.cpp | 181 ++++++++++++++++++++++++++++++++++++++--------- src/SortAlgo.h | 1 + 2 files changed, 149 insertions(+), 33 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 3d71b0220..16329483c 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -127,6 +127,8 @@ const struct AlgoEntry g_algolist[] = _("Least significant digit radix sort, performed in O(1) space.") }, { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, + { _("American Flag Sort"), &AmericanFlagSort, UINT_MAX, inversion_count_instrumented, + _("American Flag Sort is an efficient, in-place variant of radix sort that distributes items into hundreds of buckets.") }, { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, wxEmptyString }, { _("std::stable_sort (gcc)"), &StlStableSort, UINT_MAX, inversion_count_instrumented, @@ -1269,22 +1271,22 @@ void shiftElement(SortArray& A, size_t start, size_t end) // **************************************************************************** // *** In-Place Radix Sort LSD /* -Copyright (c) 2019 w0rthy -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Copyright (c) 2019 w0rthy + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ size_t maxLog(SortArray& A, size_t n, size_t base) @@ -2110,22 +2112,22 @@ void CycleSort(SortArray& A) // **************************************************************************** // *** Pairwise Sorting Network (Recursive and Iterative) /* -Copyright (c) 2021 aphitorite -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Copyright (c) 2021 aphitorite + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ void compSwap(SortArray& A, size_t a, size_t b) @@ -2199,4 +2201,117 @@ void PairwiseIterativeSort(SortArray& A) } } } -} \ No newline at end of file +} + +// **************************************************************************** +// *** American Flag Sort +// Adapted from https://en.wikipedia.org/wiki/American_flag_sort +/* + Copyright 2017 Justin Wetherell + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +int getMaxNumberOfDigits(SortArray& A, size_t len, int buckets) +{ + int max = std::numeric_limits::min(); + int temp = 0; + for (size_t i = 0; i < len; ++i) + { + int ele = A[i].get(); + temp = static_cast(log(ele) / log(buckets)) + 1; + if (temp > max) { max = temp; } + } + return max; +} + +size_t getDigit(size_t num, size_t divisor, size_t buckets) +{ + return (num / divisor) % buckets; +} + +void sort(SortArray& A, size_t start, size_t len, size_t divisor) +{ + size_t buckets = 128; + std::vector count(buckets, 0); + std::vector offset(buckets, 0); + size_t digit = 0; + + for (size_t i = start; i < len; ++i) + { + int d = A[i].get(); + size_t l = d; + digit = getDigit(l, divisor, buckets); + count[digit] = count[digit] + 1; + } + int s = start; + offset[0] = s; + + for (size_t i = 1; i < buckets; ++i) + { + offset[i] = count[i - 1] + offset[i - 1]; + } + + for (size_t b = 0; b < buckets; ++b) + { + while (count[b] > 0) + { + size_t origin = offset[b], from = origin; + int num = A[from]; + do + { + size_t m = num; + digit = getDigit(m, divisor, buckets); + size_t to = offset[digit]; + + offset[digit] = offset[digit] + 1; + count[digit] = count[digit] - 1; + + int temp = A[to].get(); + A.set(to, ArrayItem(num)); + + num = temp; + from = to; + } + while (from != origin); + } + } + if (divisor > 1) + { + for (size_t i = 0; i < buckets; ++i) + { + size_t begin = 0; + if (i > 0) { begin = offset[i - 1]; } + else { begin = start; } + size_t last = offset[i]; + + if (last - begin > 1) + { + sort(A, begin, last, divisor / buckets); + } + } + } +} + +void AmericanFlagSort(SortArray& A) +{ + size_t len = A.size(); + int buckets = 128, max = 1; + int numberOfDigits = getMaxNumberOfDigits(A, len, buckets); // Max number of digits + + for (int i = 0; i < numberOfDigits - 1; ++i) { max *= buckets; } + + size_t m = max; + sort(A, 0, len, m); +} + + diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 64f6c00fe..130076a1c 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -96,6 +96,7 @@ void BatcherSortNetwork(SortArray& a); void InPlaceRadixSortLSD(class SortArray& a); void RadixSortLSD(class SortArray& a); void RadixSortMSD(class SortArray& a); +void AmericanFlagSort(SortArray& a); void StlSort(class SortArray& a); void StlStableSort(class SortArray& a); From f1fdac4f3dfc168764070fe73577638107237073 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 19 Oct 2024 08:22:35 +0800 Subject: [PATCH 122/289] Added Weave Merge Sort --- src/SortAlgo.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 3 +- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 16329483c..58f9ea630 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -69,6 +69,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Pairwise Merge Sort (Iterative)"), &PairwiseIterativeSort, UINT_MAX, 512, wxEmptyString }, + { _("Weave Merge Sort"), &WeaveMergeSort, UINT_MAX, 512, + wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, _("Quick sort variant with left and right pointers.") }, { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, @@ -433,6 +435,91 @@ void MergeSortIterative(SortArray& A) } } +/* + MIT License + + Copyright (c) 2021 EmeraldBlock + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void weaveMerge(SortArray& A, std::vector tmp, size_t len, size_t residue, size_t modulus) +{ + if (residue + modulus >= len) { return; } + + size_t low = residue, high = residue + modulus, dmodulus = modulus << 1; + + weaveMerge(A, tmp, len, low, dmodulus); + weaveMerge(A, tmp, len, high, dmodulus); + + size_t next = residue; + for (; low < len && high < len; next += modulus) + { + int cmp = 0; + if (A[low] > A[high]) { cmp = 1; } + else if (A[low] < A[high]) { cmp = -1; } + + if (cmp == 1 || (cmp == 0 && low > high)) + { + tmp[next] = A[high]; + high += dmodulus; + } + else + { + tmp[next] = A[low]; + low += dmodulus; + } + } + + if (low >= len) + { + while (high < len) + { + tmp[next] = A[high]; + next += modulus; + high += dmodulus; + } + } + else + { + while (low < len) + { + tmp[next] = A[low]; + next += modulus; + low += dmodulus; + } + } + + for (size_t i = residue; i < len; i += modulus) + { + A.set(i, tmp[i]); + A[i].get(); + } +} + +void WeaveMergeSort(SortArray& A) +{ + size_t len = A.size(); + std::vector tmp(len); + weaveMerge(A, tmp, len, 0, 1); +} + // **************************************************************************** // *** Quick Sort Pivot Selection diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 130076a1c..d4d5f40fa 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -63,6 +63,7 @@ void MergeSort(class SortArray& a); void MergeSortIterative(class SortArray& a); void PairwiseSort(class SortArray& a); void PairwiseIterativeSort(class SortArray& a); +void WeaveMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); @@ -96,7 +97,7 @@ void BatcherSortNetwork(SortArray& a); void InPlaceRadixSortLSD(class SortArray& a); void RadixSortLSD(class SortArray& a); void RadixSortMSD(class SortArray& a); -void AmericanFlagSort(SortArray& a); +void AmericanFlagSort(class SortArray& a); void StlSort(class SortArray& a); void StlStableSort(class SortArray& a); From 36140f8c2f393a6586428982e274a607fcd8af10 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 19 Oct 2024 12:04:28 +0800 Subject: [PATCH 123/289] Added Strand Sort Weave Merge Sort now also takes just a reference of the temporary vector. --- src/SortAlgo.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++- src/SortAlgo.h | 1 + 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 58f9ea630..23183793a 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -71,6 +71,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Weave Merge Sort"), &WeaveMergeSort, UINT_MAX, 512, wxEmptyString }, + { _("Strand Sort"), &StrandSort, UINT_MAX, 512, + wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, _("Quick sort variant with left and right pointers.") }, { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, @@ -459,7 +461,7 @@ void MergeSortIterative(SortArray& A) SOFTWARE. */ -void weaveMerge(SortArray& A, std::vector tmp, size_t len, size_t residue, size_t modulus) +void weaveMerge(SortArray& A, std::vector& tmp, size_t len, size_t residue, size_t modulus) { if (residue + modulus >= len) { return; } @@ -2402,3 +2404,74 @@ void AmericanFlagSort(SortArray& A) } +// **************************************************************************** +// *** Strand Sort + +/* + MIT License + + Copyright (c) 2020-2021 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void mergeTo(SortArray& A, std::vector& subList, size_t a, size_t m, size_t b) +{ + size_t i = 0, s = m - a; + while (i < s && m < b) + { + if (subList[i] < A[m]) + { + A.set(a++, subList[i++]); + } + else + { + A.set(a++, A[m++]); + } + } + while (i < s) + { + A.set(a++, subList[i++]); + } +} + +void StrandSort(SortArray& A) +{ + size_t n = A.size(), j = n, k = j; + std::vector subList(n); + while (j > 0) + { + subList[0] = A[0]; + --k; + for (size_t i = 0, p = 0, m = 1; m < j; ++m) + { + if (A[m] >= subList[i]) + { + subList[++i] = A[m]; + --k; + } + else + { + A.set(p++, A[m]); + } + } + mergeTo(A, subList, k, j, n); + j = k; + } +} \ No newline at end of file diff --git a/src/SortAlgo.h b/src/SortAlgo.h index d4d5f40fa..310ac4d18 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -64,6 +64,7 @@ void MergeSortIterative(class SortArray& a); void PairwiseSort(class SortArray& a); void PairwiseIterativeSort(class SortArray& a); void WeaveMergeSort(class SortArray& a); +void StrandSort(class SortArray& a); wxArrayString QuickSortPivotText(); From e2fb589d232fb497fc29d6e15fad318693885e63 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 19 Oct 2024 16:46:13 +0800 Subject: [PATCH 124/289] Added a tooltip on array size slider Some sorting algorithms such as Weave Merge Sort might not immediately update the visualized array for smaller array sizes when the sorting process is about to be finished. This tooltip should hopefully let users know that when this issue arises, resizing the options panel will resolve the issue. --- src/wxg/WMain_wxg.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index b8888d703..65d3c81c4 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -65,6 +65,7 @@ void WMain_wxg::set_properties() SetTitle(_("The Sound of Sorting - http://panthema.net/2013/sound-of-sorting")); sortview->SetMinSize(wxSize(640, 480)); speedSlider->SetToolTip(_("Changes the animation speed by setting the delay for each array access.")); + arraySizeSlider->SetToolTip(_("Resize the options panel if a sorting algorithm doesn't update\nthe visualized array immediately when it's supposed to.")); soundSustainSlider->SetToolTip(_("Changes the duration of each access sound as a multiple of the delay.")); labelInversionCount->SetToolTip(_("Current number of inversions. Click to enable or disable.")); labelRunsCount->SetToolTip(_("Current number of runs.")); From 82b19638d4c057a7baaf802ac4e27601b128aeb3 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 19 Oct 2024 17:08:19 +0800 Subject: [PATCH 125/289] Update WMain_wxg.cpp --- src/wxg/WMain_wxg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index 65d3c81c4..6765c9d1c 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -65,7 +65,7 @@ void WMain_wxg::set_properties() SetTitle(_("The Sound of Sorting - http://panthema.net/2013/sound-of-sorting")); sortview->SetMinSize(wxSize(640, 480)); speedSlider->SetToolTip(_("Changes the animation speed by setting the delay for each array access.")); - arraySizeSlider->SetToolTip(_("Resize the options panel if a sorting algorithm doesn't update\nthe visualized array immediately when it's supposed to.")); + arraySizeSlider->SetToolTip(_("Resize the options panel if a sorting algorithm doesn't\nimmediately update the visualized array when it's supposed to.")); soundSustainSlider->SetToolTip(_("Changes the duration of each access sound as a multiple of the delay.")); labelInversionCount->SetToolTip(_("Current number of inversions. Click to enable or disable.")); labelRunsCount->SetToolTip(_("Current number of runs.")); From 65950af3cfdc920540d7f5c54e0e6404caee319c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 19 Oct 2024 23:01:45 +0800 Subject: [PATCH 126/289] Reimplemented Weave Merge Sort The previous implementation of Weave Merge Sort that I added could visually break on depending on the width of the application. This implementation of Weave Merge Sort is the optimized variant, and it works fully in-place, which should never be dependent on the width of the application now. I did not remove the previous implementation in case someone still wants to see it, it works completely fine, it could just "visually" break on smaller array sizes by basically not updating the visualized array when the sorting process is about to finish. --- src/SortAlgo.cpp | 147 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 7 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 23183793a..f537245ec 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -440,7 +440,7 @@ void MergeSortIterative(SortArray& A) /* MIT License - Copyright (c) 2021 EmeraldBlock + Copyright (c) 2020 aphitorite/2021 EmeraldBlock Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -461,18 +461,18 @@ void MergeSortIterative(SortArray& A) SOFTWARE. */ -void weaveMerge(SortArray& A, std::vector& tmp, size_t len, size_t residue, size_t modulus) +void weaveMerge2(SortArray& A, std::vector& tmp, size_t len, size_t residue, size_t modulus) { if (residue + modulus >= len) { return; } size_t low = residue, high = residue + modulus, dmodulus = modulus << 1; - weaveMerge(A, tmp, len, low, dmodulus); - weaveMerge(A, tmp, len, high, dmodulus); + weaveMerge2(A, tmp, len, low, dmodulus); + weaveMerge2(A, tmp, len, high, dmodulus); size_t next = residue; for (; low < len && high < len; next += modulus) - { + { int cmp = 0; if (A[low] > A[high]) { cmp = 1; } else if (A[low] < A[high]) { cmp = -1; } @@ -496,6 +496,7 @@ void weaveMerge(SortArray& A, std::vector& tmp, size_t len, size_t r tmp[next] = A[high]; next += modulus; high += dmodulus; + } } else @@ -515,13 +516,145 @@ void weaveMerge(SortArray& A, std::vector& tmp, size_t len, size_t r } } -void WeaveMergeSort(SortArray& A) +void WeaveMergeSort2(SortArray& A) { size_t len = A.size(); std::vector tmp(len); - weaveMerge(A, tmp, len, 0, 1); + weaveMerge2(A, tmp, len, 0, 1); +} + +void insertTo(SortArray& A, size_t a, size_t b) +{ + value_type temp = A[a]; + while (a > b) { A.set(a, A[a - 1]); --a; } + A.set(b, temp); +} + +void shiftValue(SortArray& A, size_t a, size_t b, size_t len) +{ + for (size_t i = 0; i < len; ++i) + { + A.swap(a + i, b + i); + } +} + +void rotate(SortArray& A, size_t a, size_t m, size_t b) +{ + size_t l = m - a, r = b - m; + while (l > 0 && r > 0) + { + if (r < l) + { + shiftValue(A, m - r, m, r); + b -= r; + m -= r; + l -= r; + } + + else + { + shiftValue(A, a, m, l); + a += l; + m += l; + r -= l; + } + } +} + +void bitReversal(SortArray& A, size_t a, size_t b) +{ + size_t len = b - a, m = 0; + size_t d1 = len >> 1, d2 = d1 + (d1 >> 1); + for (size_t i = 1; i < len - 1; ++i) + { + size_t j = d1; + for (size_t k = i, n = d2; (k & 1) == 0; j -= n, k >>= 1, n >>= 1) {} + m += j; + if (m > i) + { + A.swap(a + i, a + m); + } + } } +void weaveInsert(SortArray& A, size_t a, size_t b, bool right) +{ + size_t i = a, j = i + 1; + while (j < b) + { + while (i < j && ((right == true && A[i] <= A[j]) || (right == false && A[i] < A[j]))) { ++i; } + if (i == j) + { + right = !right; + ++j; + } + else + { + insertTo(A, j, i++); + j += 2; + } + } +} + +void weaveMerge(SortArray& A, size_t a, size_t m, size_t b) +{ + if (b - a < 2) { return; } + size_t a1 = a, b1 = b; + bool right = true; + if ((b - a) % 2 == 1) + { + if (m - a < b - m) + { + --a1; + right = false; + } + else { ++b1; } + } + + for (size_t e = b1, f; e - a1 > 2; e = f) + { + m = (a1 + e) / 2; + size_t p = 1 << static_cast(log(m - a1) / log(2)); + rotate(A, m - p, m, e - p); + + m = e - p; + f = m - p; + + bitReversal(A, f, m); + bitReversal(A, m, e); + bitReversal(A, f, e); + } + weaveInsert(A, a, b, right); +} + +void WeaveMergeSort(SortArray& A) +{ + size_t n = A.size(), d = 1 << static_cast(log(n - 1) / log(2) + 1); + while (d > 1) + { + size_t i = 0, dec = 0; + while (i < n) + { + size_t j = i; + dec += n; + while (dec >= d) + { + dec -= d; + ++j; + } + size_t k = j; + dec += n; + while (dec >= d) + { + dec -= d; + ++k; + } + weaveMerge(A, i, j, k); + i = k; + } + d /= 2; + } +} // **************************************************************************** // *** Quick Sort Pivot Selection From 8f5973398384b6e394fb11f2cde55cc39a8bb0f7 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 20 Oct 2024 16:12:47 +0800 Subject: [PATCH 127/289] Added New Shuffle Merge Sort --- src/SortAlgo.cpp | 288 ++++++++++++++++++++++++++++++++++++++++++++++- src/SortAlgo.h | 1 + 2 files changed, 287 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f537245ec..31cb46e4a 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -70,7 +70,9 @@ const struct AlgoEntry g_algolist[] = { _("Pairwise Merge Sort (Iterative)"), &PairwiseIterativeSort, UINT_MAX, 512, wxEmptyString }, { _("Weave Merge Sort"), &WeaveMergeSort, UINT_MAX, 512, - wxEmptyString }, + _("An in-place merge sort variant that interleaves 2 halves of the input array, and then uses Insertion Sort to sort the array.")}, + { _("New Shuffle Merge Sort"), &NewShuffleMergeSort, UINT_MAX, 512, + _("An improvement upon Weave Merge Sort, with faster weave time, and inserting now makes comparisons with a worst-case similar to Merge Sort.") }, { _("Strand Sort"), &StrandSort, UINT_MAX, 512, wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, @@ -2607,4 +2609,286 @@ void StrandSort(SortArray& A) mergeTo(A, subList, k, j, n); j = k; } -} \ No newline at end of file +} + +/* + MIT License + + Copyright (c) 2021 EmeraldBlock + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/* + * Implements https://www.sciencedirect.com/science/article/pii/S1877050910005478. + * + * The shuffle algorithm is at https://arxiv.org/abs/0805.1598. + * Note that the unshuffle algorithm is not the shuffle algorithm in reverse, + * but rather, it is a variation of the shuffle algorithm. + * + * See also a proof of the time complexity at https://arxiv.org/abs/1508.00292. + * The implementation is based on the pseudocode found in this. +*/ + +void rotateEqual(SortArray& A, size_t a, size_t b, size_t size) +{ + for (size_t i = 0; i < size; ++i) + { + A.swap(a + i, b + i); + } +} + +void rotateArray(SortArray& A, size_t mid, size_t a, size_t b) +{ + while (a > 0 && b > 0) + { + if (a > b) + { + rotateEqual(A, mid - b, mid, b); + mid -= b; + a -= b; + } + else + { + rotateEqual(A, mid - a, mid, a); + mid += a; + b -= a; + } + } +} + +void shuffleEasy(SortArray& A, size_t start, size_t size) +{ + for (size_t i = 1; i < size; i *= 3) + { + value_type val = A[start + i - 1]; + for (size_t j = i * 2 % size; j != i; j = j * 2 % size) + { + value_type nval = A[start + j - 1]; + A.set(start + j - 1, val); + val = nval; + } + A.set(start + i - 1, val); + } +} + +void shuffleArray(SortArray& A, size_t start, size_t end) +{ + while (end - start > 1) + { + size_t n = (end - start) / 2, l = 1; + while (l * 3 - 1 <= 2 * n) { l *= 3; } + size_t m = (l - 1) / 2; + rotateArray(A, start + n, n - m, m); + shuffleEasy(A, start, l); + start += l - 1; + } +} + +void rotateShuffledEqual(SortArray& A, size_t a, size_t b, size_t size) +{ + for (size_t i = 0; i < size; i += 2) + { + A.swap(a + i, b + i); + } +} + +void rotateShuffled(SortArray& A, size_t mid, size_t a, size_t b) +{ + while (a > 0 && b > 0) + { + if (a > b) + { + rotateShuffledEqual(A, mid - b, mid, b); + mid -= b; + a -= b; + } + else + { + rotateShuffledEqual(A, mid - a, mid, a); + mid += a; + b -= a; + } + } +} + +void rotateShuffledOuter(SortArray& A, size_t mid, size_t a, size_t b) +{ + if (a > b) + { + rotateShuffledEqual(A, mid - b, mid + 1, b); + mid -= b; + a -= b; + rotateShuffled(A, mid, a, b); + } + else + { + rotateShuffledEqual(A, mid - a, mid + 1, a); + mid += a + 1; + b -= a; + rotateShuffled(A, mid, a, b); + } +} + +void unshuffleEasy(SortArray& A, size_t start, size_t size) +{ + for (size_t i = 1; i < size; i *= 3) + { + size_t prev = i; + value_type val = A[start + i - 1]; + for (size_t j = i * 2 % size; j != i; j = j * 2 % size) { + A.set(start + prev - 1, A[start + j - 1]); + prev = j; + } + A.set(start + prev - 1, val); + } +} + +void unshuffle(SortArray& A, size_t start, size_t end) +{ + while (end - start > 1) + { + size_t n = (end - start) / 2, l = 1; + while (l * 3 - 1 <= 2 * n) { l *= 3; } + size_t m = (l - 1) / 2; + + rotateShuffledOuter(A, start + 2 * m, 2 * m, 2 * n - 2 * m); + unshuffleEasy(A, start, l); + start += l - 1; + } +} + +void mergeUp(SortArray& A, size_t start, size_t end, bool type) +{ + size_t i = start, j = i + 1; + while (j < end) + { + if (A[i] < A[j] || (!type && A[i] == A[j])) + { + ++i; + if (i == j) + { + ++j; + type = !type; + } + } + else if (end - j == 1) + { + rotateArray(A, j, j - i, 1); + break; + } + else + { + size_t r = 0; + if (type) + { + while (j + 2 * r < end && A[j + 2 * r] <= A[i]) { ++r; } + } + else + { + while (j + 2 * r < end && A[j + 2 * r] < A[i]) { ++r; } + } + --j; + unshuffle(A, j, j + 2 * r); + rotateArray(A, j, j - i, r); + i += r + 1; + j += 2 * r + 1; + } + } +} + +void mergeArray(SortArray& A, size_t start, size_t mid, size_t end) +{ + if (mid - start <= end - mid) + { + shuffleArray(A, start, end); + mergeUp(A, start, end, true); + } + else + { + shuffleArray(A, start + 1, end); + mergeUp(A, start, end, false); + } +} + +size_t ceilPowerOfTwo(size_t x) +{ + --x; + for (size_t i = 16; i > 0; i >>= 1) { x |= x >> i; } + return ++x; +} + +void sortLarge(SortArray& A, size_t len) +{ + for (size_t subarrayCount = ceilPowerOfTwo(len), wholeI = len / subarrayCount, fracI = len % subarrayCount; subarrayCount > 1; ) + { + for (size_t whole = 0, frac = 0; whole < len; ) + { + size_t start = whole; + whole += wholeI; + frac += fracI; + if (frac >= subarrayCount) + { + ++whole; + frac -= subarrayCount; + } + size_t mid = whole; + whole += wholeI; + frac += fracI; + if (frac >= subarrayCount) + { + ++whole; + frac -= subarrayCount; + } + mergeArray(A, start, mid, whole); + } + subarrayCount >>= 1; + wholeI <<= 1; + if (fracI >= subarrayCount) + { + ++wholeI; + fracI -= subarrayCount; + } + } +} + +void mergeSortArray(SortArray& A, size_t len) +{ + if (len < 1 << 15) + { + for (size_t subarrayCount = ceilPowerOfTwo(len); subarrayCount > 1; subarrayCount >>= 1) + { + for (size_t i = 0; i < subarrayCount; i += 2) + { + mergeArray(A, len * i / subarrayCount, len * (i + 1) / subarrayCount, len * (i + 2) / subarrayCount); + } + } + } + else + { + sortLarge(A, len); + } +} + +void NewShuffleMergeSort(SortArray& A) +{ + size_t len = A.size(); + mergeSortArray(A, len); +} + diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 310ac4d18..41917a772 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -65,6 +65,7 @@ void PairwiseSort(class SortArray& a); void PairwiseIterativeSort(class SortArray& a); void WeaveMergeSort(class SortArray& a); void StrandSort(class SortArray& a); +void NewShuffleMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); From 0858fa19495d249823fe89fca4b71727bafaf19b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 21 Oct 2024 16:40:21 +0800 Subject: [PATCH 128/289] Set SortAlgoThread to max priority, increased smallest allowed delay I have spent several hours trying to resolve the "cannot terminate thread" error, and I have not been able to come up with any good working solution. I have used several commands and other things to try and prevent the issue from happening, and while I did learn a lot from all of my attempts, I am actually sad that I still failed to fix the problem. The "cannot terminate thread" happens more prevalently on very small delays, so I decided to prevent the speed slider from going down to 0 ms. I also made the thread go to maximum priority in hopes of allowing the thread to execute (and end) faster, I have been able to deduce that using Delete() will make the TestDestroy() flag become true, and it might help in solving the problem, but I don't know what else I could do in the meantime. --- src/WMain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 1c880a0f0..4055439c0 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -153,6 +153,7 @@ bool WMain::RunAlgorithm() m_thread_terminate = false; m_thread->Create(); + m_thread->SetPriority(WXTHREAD_MAX_PRIORITY); g_algo_running = true; m_thread->Run(); @@ -326,7 +327,7 @@ void WMain::SetDelay(size_t pos) g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0) / log(base)); #endif - if (pos == 0) g_delay = 0; + if (pos == 0) g_delay = 0.1; if (g_delay > 10) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); From 5057e10975e1b0cf22fcdf9d586fbb06ef177b32 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 00:15:08 +0800 Subject: [PATCH 129/289] Reimplemented Radix Sort MSD The original implementation of Radix Sort MSD sadly performs horribly on larger array sizes, even with the vector -> array change that was shown to me in "The Studio" discord. I decided to port the Radix Sort MSD that ArrayV possesses instead, and now, Radix Sort MSD finally works great on large array sizes, I guess color markings can be tweaked a little, but at least this sorting algorithm will now work better since the application now allows large array sizes. --- src/SortAlgo.cpp | 158 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 117 insertions(+), 41 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 31cb46e4a..9e1a232db 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -112,7 +112,7 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Shell Sort"), &ShellSort, UINT_MAX, 1024, wxEmptyString }, - { _("Heap Sort"), &HeapSort, UINT_MAX, UINT_MAX, + { _("Heap Sort"), &HeapSort, UINT_MAX, inversion_count_instrumented, wxEmptyString }, { _("Smooth Sort"), &SmoothSort, UINT_MAX, 1024, wxEmptyString }, @@ -131,7 +131,7 @@ const struct AlgoEntry g_algolist[] = "array during counting.") }, { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, UINT_MAX, _("Least significant digit radix sort, performed in O(1) space.") }, - { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, UINT_MAX, + { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, 512, _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, { _("American Flag Sort"), &AmericanFlagSort, UINT_MAX, inversion_count_instrumented, _("American Flag Sort is an efficient, in-place variant of radix sort that distributes items into hundreds of buckets.") }, @@ -1360,7 +1360,7 @@ void HeapSort(SortArray& A) // by myself (Timo Bingmann) -void RadixSortMSD(SortArray& A, size_t lo, size_t hi, size_t depth) +void RadixSortMSD2(SortArray& A, size_t lo, size_t hi, size_t depth) { A.mark(lo); A.mark(hi-1); @@ -1412,14 +1412,109 @@ void RadixSortMSD(SortArray& A, size_t lo, size_t hi, size_t depth) for (size_t i = 0; i < RADIX; ++i) { if (count[i] > 1) - RadixSortMSD(A, sum, sum+count[i], depth+1); + RadixSortMSD2(A, sum, sum+count[i], depth+1); sum += count[i]; } } +void RadixSortMSD2(SortArray& A) +{ + return RadixSortMSD2(A, 0, A.size(), 0); +} + +/* + MIT License + + Copyright (c) 2019 w0rthy + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +size_t maxLog(SortArray& A, size_t n, size_t base) +{ + int max = A[0]; + for (size_t i = 1, j = n - 1; i <= j; ++i, --j) + { + int ele1 = A[i].get(), ele2 = A[j]; + if (ele1 > max) { max = A[i]; } + if (ele2 > max) { max = A[j]; } + } + size_t digit = static_cast(log(max) / log(base)); + return digit; +} + +int getDigit(int a, double power, int radix) +{ + double digit = (a / static_cast(pow(radix, power)) % radix); + return static_cast(digit); +} + +void transcribeMSD(SortArray& A, std::vector>& registers, size_t start, size_t min) +{ + size_t total = start, temp = 0; + for (const std::vector& arr : registers) + { + total += arr.size(); + } + + for (int i = registers.size() - 1; i >= 0; --i) + { + for (int j = registers[i].size() - 1; j >= 0; --j) + { + size_t loc = total + min - temp - 1; + A.set(loc, registers[i].at(j)); + A[loc].get(); + ++temp; + } + } +} + +void radixMSD(SortArray& A, size_t len, size_t min, size_t max, size_t radix, double pow) +{ + if (min >= max || pow < 0) { return; } + A.mark(min); A.mark(max - 1); + + std::vector> registers(radix, std::vector()); + + for (size_t i = min; i < max; ++i) + { + int ele = A[i].get(); + int digit = getDigit(ele, pow, radix); + registers[digit].push_back(A[i]); + } + + transcribeMSD(A, registers, 0, min); + A.unmark_all(); + + size_t sum = 0; + for (size_t i = 0; i < registers.size(); ++i) + { + radixMSD(A, len, sum + min, sum + min + registers[i].size(), radix, pow - 1); + sum += registers[i].size(); + registers[i].clear(); + } +} + void RadixSortMSD(SortArray& A) { - return RadixSortMSD(A, 0, A.size(), 0); + size_t n = A.size(), maxPow = maxLog(A, n, 4); + radixMSD(A, n, 0, n, 4, (double)maxPow); } // **************************************************************************** @@ -1470,28 +1565,6 @@ void RadixSortLSD(SortArray& A) } } -void shiftElement(SortArray& A, size_t start, size_t end) -{ - if (start < end) - { - while (start < end) - { - A[start].get(); - A.swap(start, start + 1); - ++start; - } - } - else - { - while (start > end) - { - A[start].get(); - A.swap(start, start - 1); - --start; - } - } -} - // **************************************************************************** // *** In-Place Radix Sort LSD /* @@ -1513,23 +1586,26 @@ void shiftElement(SortArray& A, size_t start, size_t end) SOFTWARE. */ -size_t maxLog(SortArray& A, size_t n, size_t base) +void shiftElement(SortArray& A, size_t start, size_t end) { - int max = A[0]; - for (size_t i = 1, j = n - 1; i <= j; ++i, --j) + if (start < end) { - int ele1 = A[i].get(), ele2 = A[j]; - if (ele1 > max) { max = A[i]; } - if (ele2 > max) { max = A[j]; } + while (start < end) + { + A[start].get(); + A.swap(start, start + 1); + ++start; + } + } + else + { + while (start > end) + { + A[start].get(); + A.swap(start, start - 1); + --start; + } } - size_t digit = static_cast(log(max) / log(base)); - return digit; -} - -int getDigit(int a, double power, int radix) -{ - double digit = (a / static_cast(pow(radix, power)) % radix); - return static_cast(digit); } void InPlaceRadixSortLSD(SortArray& A) From 0c4c7ff0774c89f4ebd001499926065b2b259f64 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 02:16:51 +0800 Subject: [PATCH 130/289] Added an experimental "swaps" counter It currently doesn't work on iterator-based sorting algorithms, since they utilize std::swap/std::iter_swap --- src/SortAlgo.cpp | 9 +++++++-- src/SortArray.cpp | 1 + src/SortArray.h | 8 ++++++++ src/WMain.cpp | 3 +++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 9e1a232db..48a9ceb18 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1452,8 +1452,8 @@ size_t maxLog(SortArray& A, size_t n, size_t base) for (size_t i = 1, j = n - 1; i <= j; ++i, --j) { int ele1 = A[i].get(), ele2 = A[j]; - if (ele1 > max) { max = A[i]; } - if (ele2 > max) { max = A[j]; } + if (ele1 > max) { max = ele1; } + if (ele2 > max) { max = ele2; } } size_t digit = static_cast(log(max) / log(base)); return digit; @@ -2687,6 +2687,9 @@ void StrandSort(SortArray& A) } } + +// **************************************************************************** +// *** New Shuffle Merge Sort /* MIT License @@ -2968,3 +2971,5 @@ void NewShuffleMergeSort(SortArray& A) mergeSortArray(A, len); } +// **************************************************************************** +// *** Andrey Astrelin's In-Place Merge Sort diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 3d0044025..01ed67c30 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -100,6 +100,7 @@ void SortArray::FinishFill() g_access_count = 0; g_compare_count = 0; m_calc_inversions = true; + m_swaps = 0; RecalcInversions(); } diff --git a/src/SortArray.h b/src/SortArray.h index e22141043..173d3d7e3 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -157,6 +157,9 @@ class SortArray /// the number of inversions in the array order ssize_t m_inversions; + /// number of swaps + size_t m_swaps; + /// access touch color struct Access { @@ -232,6 +235,10 @@ class SortArray ssize_t GetInversions() const { return m_inversions; } + /// return the number of swaps in the array + ssize_t GetSwaps() const + { return m_swaps; } + /// calculate the number of runs in the array size_t GetRuns() const; @@ -387,6 +394,7 @@ class SortArray std::swap(m_array[i], m_array[j]); OnAccess(); m_access2 = -1; + ++m_swaps; } /// Touch an item of the array: set color till next frame is outputted. diff --git a/src/WMain.cpp b/src/WMain.cpp index 4055439c0..e4db32bc5 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -430,6 +430,9 @@ void WMain::RefreshTimer::Notify() long int compares = g_compare_count; wm.labelComparisonsValue->SetLabel(wxString::Format(_("%ld"), compares)); + long int swaps = wm.sortview->m_array.GetSwaps(); + wm.labelSwapsCount->SetLabel(wxString::Format(_("%ld"), swaps)); + long int inversions = wm.sortview->m_array.GetInversions(); if (inversions >= 0) wm.labelInversionCount->SetLabel(wxString::Format(_("%ld"), inversions)); From f434e4c4566f5eb8e22880ac6e7ccf4c76e6af37 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 02:17:41 +0800 Subject: [PATCH 131/289] Added an experimental "swaps" counter --- src/wxg/WMain_wxg.cpp | 9 ++++++++- src/wxg/WMain_wxg.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index 6765c9d1c..0b4b0304c 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -42,6 +42,7 @@ WMain_wxg::WMain_wxg(wxWindow* parent, int id, const wxString& title, const wxPo labelAccessCount = new wxClickText(splitter_0_pane_2, wxID_ANY, wxEmptyString); labelInversionCount = new wxClickText(splitter_0_pane_2, ID_INVERSION_LABEL, wxEmptyString); labelRunsCount = new wxClickText(splitter_0_pane_2, wxID_ANY, wxEmptyString); + labelSwapsCount = new wxClickText(splitter_0_pane_2, wxID_ANY, wxEmptyString); const wxString *inputTypeChoice_choices = NULL; inputTypeChoice = new wxChoice(splitter_0_pane_2, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, inputTypeChoice_choices, 0); arraySizeSlider = new wxSlider(splitter_0_pane_2, ID_ARRAY_SIZE_SLIDER, 0, 1, 16384); @@ -69,6 +70,7 @@ void WMain_wxg::set_properties() soundSustainSlider->SetToolTip(_("Changes the duration of each access sound as a multiple of the delay.")); labelInversionCount->SetToolTip(_("Current number of inversions. Click to enable or disable.")); labelRunsCount->SetToolTip(_("Current number of runs.")); + labelSwapsCount->SetToolTip(_("Current number of swaps.")); panelQuickSortPivot->Hide(); splitter_0->SetSashGravity(1.0); // end wxGlade @@ -88,7 +90,7 @@ void WMain_wxg::do_layout() sizer_3_staticbox->Lower(); wxStaticBoxSizer* sizer_3 = new wxStaticBoxSizer(sizer_3_staticbox, wxVERTICAL); wxBoxSizer* sizerAnimationControls = new wxBoxSizer(wxVERTICAL); - wxFlexGridSizer* grid_sizer_3 = new wxFlexGridSizer(7, 2, 0, 0); + wxFlexGridSizer* grid_sizer_3 = new wxFlexGridSizer(8, 2, 0, 0); wxBoxSizer* sizerSoundSustain = new wxBoxSizer(wxHORIZONTAL); wxGridSizer* grid_sizer_2 = new wxGridSizer(3, 2, 0, 0); wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL); @@ -125,6 +127,11 @@ void WMain_wxg::do_layout() wxStaticText* labelRuns = new wxStaticText(splitter_0_pane_2, wxID_ANY, _("Runs: ")); grid_sizer_3->Add(labelRuns, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 4); grid_sizer_3->Add(labelRunsCount, 0, wxTOP|wxBOTTOM|wxEXPAND|wxALIGN_CENTER_VERTICAL, 4); + + wxStaticText* labelSwaps = new wxStaticText(splitter_0_pane_2, wxID_ANY, _("Swaps: ")); + grid_sizer_3->Add(labelSwaps, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 4); + grid_sizer_3->Add(labelSwapsCount, 0, wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER_VERTICAL, 4); + grid_sizer_3->AddGrowableCol(1); sizerAnimationControls->Add(grid_sizer_3, 1, wxEXPAND, 0); sizer_3->Add(sizerAnimationControls, 1, wxEXPAND, 0); diff --git a/src/wxg/WMain_wxg.h b/src/wxg/WMain_wxg.h index 7d433842d..cf58d0dd7 100644 --- a/src/wxg/WMain_wxg.h +++ b/src/wxg/WMain_wxg.h @@ -79,6 +79,7 @@ class WMain_wxg: public wxFrame { wxClickText* labelAccessCount; wxClickText* labelInversionCount; wxClickText* labelRunsCount; + wxClickText* labelSwapsCount; wxChoice* inputTypeChoice; wxSlider* arraySizeSlider; wxStaticText* labelArraySizeValue; From 55c87960607a8ec47d65b5e4467e861d962c8319 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:10:18 +0800 Subject: [PATCH 132/289] Made swaps counter work globally This is part of the other "fix" I am going to provide, which will allow algorithms using std::swap() and std::iter_swap() to also have a working swap counter --- src/SortArray.cpp | 2 ++ src/SortArray.h | 25 +++++++++++++++++-------- src/WMain.cpp | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 01ed67c30..a9bac8e84 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -37,6 +37,8 @@ size_t g_compare_count = 0; size_t g_access_count = 0; +size_t m_swaps = 0; + void ArrayItem::OnAccess(const ArrayItem& a) { SoundAccess(a.get_direct()); diff --git a/src/SortArray.h b/src/SortArray.h index 173d3d7e3..61c9eca41 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -50,6 +50,22 @@ extern size_t g_compare_count; /// globally count the number of array access extern size_t g_access_count; +extern size_t m_swaps; + +// Custom counted swap function +template +void counted_swap(T & a, T & b) { + std::swap(a, b); + ++m_swaps; +} + +// Custom counted iter_swap function +template +void counted_iter_swap(Iterator a, Iterator b) { + std::iter_swap(a, b); + ++m_swaps; +} + // custom struct for array items, which allows detailed counting of comparisons. class ArrayItem { @@ -157,9 +173,6 @@ class SortArray /// the number of inversions in the array order ssize_t m_inversions; - /// number of swaps - size_t m_swaps; - /// access touch color struct Access { @@ -235,10 +248,6 @@ class SortArray ssize_t GetInversions() const { return m_inversions; } - /// return the number of swaps in the array - ssize_t GetSwaps() const - { return m_swaps; } - /// calculate the number of runs in the array size_t GetRuns() const; @@ -382,7 +391,7 @@ class SortArray ASSERT(lock.IsOk()); m_access1 = i; - m_access2 = j; + m_access2 = j; m_access_list.push_back(i); m_access_list.push_back(j); diff --git a/src/WMain.cpp b/src/WMain.cpp index e4db32bc5..c87e1d50f 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -430,7 +430,7 @@ void WMain::RefreshTimer::Notify() long int compares = g_compare_count; wm.labelComparisonsValue->SetLabel(wxString::Format(_("%ld"), compares)); - long int swaps = wm.sortview->m_array.GetSwaps(); + long int swaps = m_swaps; wm.labelSwapsCount->SetLabel(wxString::Format(_("%ld"), swaps)); long int inversions = wm.sortview->m_array.GetInversions(); From 8c67cb014746f1fca3c63370dc618ff628439aac Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:31:42 +0800 Subject: [PATCH 133/289] Made swaps variable access through swap() "thread safe" --- src/SortArray.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SortArray.h b/src/SortArray.h index 61c9eca41..c6011991d 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -391,7 +391,8 @@ class SortArray ASSERT(lock.IsOk()); m_access1 = i; - m_access2 = j; + m_access2 = j; + ++m_swaps; m_access_list.push_back(i); m_access_list.push_back(j); @@ -402,8 +403,7 @@ class SortArray OnAccess(); std::swap(m_array[i], m_array[j]); OnAccess(); - m_access2 = -1; - ++m_swaps; + m_access2 = -1; } /// Touch an item of the array: set color till next frame is outputted. From d243e6a363b1fe5bf17470e3b1786409ccdd2622 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:36:03 +0800 Subject: [PATCH 134/289] Provided a std::swap_ranges() that works with the swap counter --- src/SortArray.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/SortArray.h b/src/SortArray.h index c6011991d..a73cb7a85 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -66,6 +66,18 @@ void counted_iter_swap(Iterator a, Iterator b) { ++m_swaps; } +// Custom counted swap_ranges function +template +ForwardIt2 counted_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) { + // Check that both ranges are of equal length + while (first1 != last1) { + counted_iter_swap(first1, first2); // Use counted iter_swap + ++first1; // Move to the next element in the first range + ++first2; // Move to the next element in the second range + } + return first2; // Return the end iterator of the second range +} + // custom struct for array items, which allows detailed counting of comparisons. class ArrayItem { From e18dea82f75dec2904519f3f8dbc3a82c43ba6df Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:40:51 +0800 Subject: [PATCH 135/289] Altered std::swap() and other related methods to wrapper methods All the algorithms that use std::swap() and anything similar will now use the wrapper method which counts swaps --- src/algorithms/grailsort.cpp | 44 +++++++++++++++++++----------------- src/algorithms/pdqsort.cpp | 40 ++++++++++++++++---------------- src/algorithms/wikisort.cpp | 14 ++++++------ 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 7a581534e..3e88bf9e6 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -53,6 +53,8 @@ #include #include +SortArray sortarray; + namespace grailsort_detail { // Credit to phoenixbound for this clever idea @@ -91,7 +93,7 @@ namespace grailsort_detail template static void BlockSwap(RandomAccessIterator array, int a, int b, int blockLen) { - std::swap_ranges(array + a, array + (a + blockLen), array + b); + counted_swap_ranges(array + a, array + (a + blockLen), array + b); } // Swaps the order of two adjacent blocks whose lengths may or may not be equal. @@ -120,7 +122,7 @@ namespace grailsort_detail int right = start + item; while (left >= start && comp(array[left], array[right]) > 0) { - std::iter_swap(array + left, array + right); + counted_iter_swap(array + left, array + right); left--; right--; } @@ -215,18 +217,18 @@ namespace grailsort_detail int right = start + index; if (comp(array[left], array[right]) > 0) { - std::swap(array[left - 2], array[right]); - std::swap(array[right - 2], array[left]); + counted_swap(array[left - 2], array[right]); + counted_swap(array[right - 2], array[left]); } else { - std::swap(array[left - 2], array[left]); - std::swap(array[right - 2], array[right]); + counted_swap(array[left - 2], array[left]); + counted_swap(array[right - 2], array[right]); } } int left = start + index - 1; if (left < start + length) { - std::swap(array[left - 2], array[left]); + counted_swap(array[left - 2], array[left]); } } @@ -267,18 +269,18 @@ namespace grailsort_detail while (right != end) { if (left == middle || comp(*left, *right) > 0) { - std::iter_swap(buffer, right); + counted_iter_swap(buffer, right); ++right; } else { - std::iter_swap(buffer, left); + counted_iter_swap(buffer, left); ++left; } ++buffer; } while (left != middle) { - std::iter_swap(buffer, left); + counted_iter_swap(buffer, left); ++buffer; ++left; } @@ -301,11 +303,11 @@ namespace grailsort_detail while (left > end) { if (right == middle || comp(array[left], array[right]) > 0) { - std::swap(array[buffer], array[left]); + counted_swap(array[buffer], array[left]); left--; } else { - std::swap(array[buffer], array[right]); + counted_swap(array[buffer], array[right]); right--; } buffer--; @@ -313,7 +315,7 @@ namespace grailsort_detail if (right != buffer) { while (right > middle) { - std::swap(array[buffer], array[right]); + counted_swap(array[buffer], array[right]); buffer--; right--; } @@ -482,7 +484,7 @@ namespace grailsort_detail BlockSwap(array, start + (firstBlock * blockLen), start + (selectBlock * blockLen), blockLen); // Swap the keys... - std::swap(array[firstKey + firstBlock], array[firstKey + selectBlock]); + counted_swap(array[firstKey + firstBlock], array[firstKey + selectBlock]); // ...and follow the 'medianKey' if it was swapped @@ -512,7 +514,7 @@ namespace grailsort_detail ArrayItem pos = ArrayItem(index); while (index >= start) { pos.get(); - std::swap(array[index], array[buffer]); + counted_swap(array[index], array[buffer]); index--; buffer--; pos = ArrayItem(index); } @@ -547,7 +549,7 @@ namespace grailsort_detail template static void InPlaceBufferRewind(RandomAccessIterator array, int start, int leftBlock, int buffer) { while (leftBlock >= start) { - std::swap(array[buffer], array[leftBlock]); + counted_swap(array[buffer], array[leftBlock]); leftBlock--; buffer--; } @@ -606,11 +608,11 @@ namespace grailsort_detail if (leftOrigin == Subarray::LEFT) { while (left != middle && right != end) { if (comp(*left, *right) <= 0) { - std::iter_swap(buffer, left); + counted_iter_swap(buffer, left); ++left; } else { - std::iter_swap(buffer, right); + counted_iter_swap(buffer, right); ++right; } ++buffer; @@ -619,11 +621,11 @@ namespace grailsort_detail else { while (left != middle && right != end) { if (comp(*left, *right) < 0) { - std::iter_swap(buffer, left); + counted_iter_swap(buffer, left); ++left; } else { - std::iter_swap(buffer, right); + counted_iter_swap(buffer, right); ++right; } ++buffer; @@ -1143,7 +1145,7 @@ namespace grailsort_detail int right = start + index; if (comp(array[left], array[right]) > 0) { - std::swap(array[left], array[right]); + counted_swap(array[left], array[right]); } } for (int mergeLen = 2; mergeLen < length; mergeLen *= 2) { diff --git a/src/algorithms/pdqsort.cpp b/src/algorithms/pdqsort.cpp index 2ed40d5fb..f12eb368a 100644 --- a/src/algorithms/pdqsort.cpp +++ b/src/algorithms/pdqsort.cpp @@ -150,7 +150,7 @@ namespace pdqsort_detail { template inline void sort2(Iter a, Iter b, Compare comp) { - if (comp(*b, *a)) std::iter_swap(a, b); + if (comp(*b, *a)) counted_iter_swap(a, b); } // Sorts the elements *a, *b and *c using comparison function comp. @@ -181,7 +181,7 @@ namespace pdqsort_detail { // This case is needed for the descending distribution, where we need // to have proper swapping for pdqsort to remain O(n). for (size_t i = 0; i < num; ++i) { - std::iter_swap(first + offsets_l[i], last - offsets_r[i]); + counted_iter_swap(first + offsets_l[i], last - offsets_r[i]); } } else if (num > 0) { Iter l = first + offsets_l[0]; Iter r = last - offsets_r[0]; @@ -221,7 +221,7 @@ namespace pdqsort_detail { // the passed in sequence already was correctly partitioned. bool already_partitioned = first >= last; if (!already_partitioned) { - std::iter_swap(first, last); + counted_iter_swap(first, last); ++first; // The following branchless partitioning is derived from "BlockQuicksort: How Branch @@ -301,12 +301,12 @@ namespace pdqsort_detail { // We have now fully identified [first, last)'s proper position. Swap the last elements. if (num_l) { offsets_l += start_l; - while (num_l--) std::iter_swap(offsets_l_base + offsets_l[num_l], --last); + while (num_l--) counted_iter_swap(offsets_l_base + offsets_l[num_l], --last); first = last; } if (num_r) { offsets_r += start_r; - while (num_r--) std::iter_swap(offsets_r_base - offsets_r[num_r], first), ++first; + while (num_r--) counted_iter_swap(offsets_r_base - offsets_r[num_r], first), ++first; last = first; } } @@ -353,7 +353,7 @@ namespace pdqsort_detail { // swapped pairs guard the searches, which is why the first iteration is special-cased // above. while (first < last) { - std::iter_swap(first, last); + counted_iter_swap(first, last); while (comp(*++first, pivot)); while (!comp(*--last, pivot)); } @@ -384,7 +384,7 @@ namespace pdqsort_detail { else while ( !comp(pivot, *++first)); while (first < last) { - std::iter_swap(first, last); + counted_iter_swap(first, last); while (comp(pivot, *--last)); while (!comp(pivot, *++first)); } @@ -419,7 +419,7 @@ namespace pdqsort_detail { sort3(begin + 1, begin + (s2 - 1), end - 2, comp); sort3(begin + 2, begin + (s2 + 1), end - 3, comp); sort3(begin + (s2 - 1), begin + s2, begin + (s2 + 1), comp); - std::iter_swap(begin, begin + s2); + counted_iter_swap(begin, begin + s2); } else sort3(begin + s2, begin, end - 1, comp); // If *(begin - 1) is the end of the right partition of a previous partition operation @@ -454,26 +454,26 @@ namespace pdqsort_detail { } if (l_size >= insertion_sort_threshold) { - std::iter_swap(begin, begin + l_size / 4); - std::iter_swap(pivot_pos - 1, pivot_pos - l_size / 4); + counted_iter_swap(begin, begin + l_size / 4); + counted_iter_swap(pivot_pos - 1, pivot_pos - l_size / 4); if (l_size > ninther_threshold) { - std::iter_swap(begin + 1, begin + (l_size / 4 + 1)); - std::iter_swap(begin + 2, begin + (l_size / 4 + 2)); - std::iter_swap(pivot_pos - 2, pivot_pos - (l_size / 4 + 1)); - std::iter_swap(pivot_pos - 3, pivot_pos - (l_size / 4 + 2)); + counted_iter_swap(begin + 1, begin + (l_size / 4 + 1)); + counted_iter_swap(begin + 2, begin + (l_size / 4 + 2)); + counted_iter_swap(pivot_pos - 2, pivot_pos - (l_size / 4 + 1)); + counted_iter_swap(pivot_pos - 3, pivot_pos - (l_size / 4 + 2)); } } if (r_size >= insertion_sort_threshold) { - std::iter_swap(pivot_pos + 1, pivot_pos + (1 + r_size / 4)); - std::iter_swap(end - 1, end - r_size / 4); + counted_iter_swap(pivot_pos + 1, pivot_pos + (1 + r_size / 4)); + counted_iter_swap(end - 1, end - r_size / 4); if (r_size > ninther_threshold) { - std::iter_swap(pivot_pos + 2, pivot_pos + (2 + r_size / 4)); - std::iter_swap(pivot_pos + 3, pivot_pos + (3 + r_size / 4)); - std::iter_swap(end - 2, end - (1 + r_size / 4)); - std::iter_swap(end - 3, end - (2 + r_size / 4)); + counted_iter_swap(pivot_pos + 2, pivot_pos + (2 + r_size / 4)); + counted_iter_swap(pivot_pos + 3, pivot_pos + (3 + r_size / 4)); + counted_iter_swap(end - 2, end - (1 + r_size / 4)); + counted_iter_swap(end - 3, end - (2 + r_size / 4)); } } } else { diff --git a/src/algorithms/wikisort.cpp b/src/algorithms/wikisort.cpp index 78a10b477..5a2b0b586 100644 --- a/src/algorithms/wikisort.cpp +++ b/src/algorithms/wikisort.cpp @@ -80,7 +80,7 @@ void InsertionSort(Iterator begin, Iterator end, const Comparison compare) { // swap a series of values in the array template void BlockSwap(Iterator start1, Iterator start2, const size_t block_size) { - std::swap_ranges(start1, start1 + block_size, start2); + counted_swap_ranges(start1, start1 + block_size, start2); } // rotate the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1) @@ -161,12 +161,12 @@ void Merge(const RangeI& buffer, const RangeI& A, const Rang if (B.length() > 0 && A.length() > 0) { while (true) { if (!compare(*B_index, *A_index)) { - std::swap(*insert_index, *A_index); + counted_swap(*insert_index, *A_index); A_index++; insert_index++; if (A_index == A_last) break; } else { - std::swap(*insert_index, *B_index); + counted_swap(*insert_index, *B_index); B_index++; insert_index++; if (B_index == B_last) break; @@ -174,7 +174,7 @@ void Merge(const RangeI& buffer, const RangeI& A, const Rang } } - std::swap_ranges(A_index, A_last, insert_index); + counted_swap_ranges(A_index, A_last, insert_index); } } @@ -438,7 +438,7 @@ void Sort(Iterator first, Iterator last, const Comparison compare) // swap the second value of each A block with the value in buffer1 for (Iterator index = buffer1.start, indexA = firstA.end + 1; indexA < blockA.end; index++, indexA += block_size) - std::swap(*index, *indexA); + counted_swap(*index, *indexA); // start rolling the A blocks through the B blocks! // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well @@ -453,7 +453,7 @@ void Sort(Iterator first, Iterator last, const Comparison compare) if (lastA.length() <= cache_size) std::copy(lastA.start, lastA.end, cache); else - std::swap_ranges(lastA.start, lastA.end, buffer2.start); + counted_swap_ranges(lastA.start, lastA.end, buffer2.start); while (true) { // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, @@ -468,7 +468,7 @@ void Sort(Iterator first, Iterator last, const Comparison compare) // we need to swap the second item of the previous A block back with its original value, which is stored in buffer1 // since the firstA block did not have its value swapped out, we need to make sure the previous A block is not unevenly sized - std::swap(*(blockA.start + 1), *(indexA++)); + counted_swap(*(blockA.start + 1), *(indexA++)); // locally merge the previous A block with the B values that follow it, using the buffer as swap space Merge(buffer2, lastA, Range(lastA.end, B_split), compare, cache, cache_size); From c990d202624a2192e9b3405363912b7a5e6d5d1f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:42:37 +0800 Subject: [PATCH 136/289] Update grailsort.cpp Removed unnecessary declaration --- src/algorithms/grailsort.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 3e88bf9e6..21093b862 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -53,8 +53,6 @@ #include #include -SortArray sortarray; - namespace grailsort_detail { // Credit to phoenixbound for this clever idea From a2704eec43413d9ce5d3585a46a2ec3cde815ab8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:45:50 +0800 Subject: [PATCH 137/289] Update SortArray.h --- src/SortArray.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/SortArray.h b/src/SortArray.h index a73cb7a85..4fb3b9015 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -69,13 +69,12 @@ void counted_iter_swap(Iterator a, Iterator b) { // Custom counted swap_ranges function template ForwardIt2 counted_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) { - // Check that both ranges are of equal length while (first1 != last1) { - counted_iter_swap(first1, first2); // Use counted iter_swap - ++first1; // Move to the next element in the first range - ++first2; // Move to the next element in the second range + counted_iter_swap(first1, first2); + ++first1; + ++first2; } - return first2; // Return the end iterator of the second range + return first2; } // custom struct for array items, which allows detailed counting of comparisons. From 34d6d9cc1c38a71ac3529b59ac765a2414e811c9 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 05:54:21 +0800 Subject: [PATCH 138/289] Cycle Sort will now use counted_swap() --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 48a9ceb18..aa6b68866 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -2392,7 +2392,7 @@ void CycleSort(SortArray& array, ssize_t n) rank++; // Put item into right place and colorize - std::swap(array.get_mutable(rank), item); + counted_swap(array.get_mutable(rank), item); array.mark(rank, 2); // Continue for rest of the cycle. From 71ac987fd3dbf9db23e94818562919e46296353c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 14:08:26 +0800 Subject: [PATCH 139/289] Added Heapified array input type --- src/SortArray.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index a9bac8e84..98dde7a3c 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -131,6 +131,21 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Quicksort Killer")); list.Add(_("Spike")); list.Add(_("Ribbon")); + list.Add(_("Heapified")); +} + +void heapify(std::vector& m_array, int n, int i) +{ + int largest = i, left = 2 * i + 1, right = 2 * i + 2; + if (left < n && m_array[left] > m_array[largest]) { largest = left; } + if (right < n && m_array[right] > m_array[largest]) { largest = right; } + if (largest != i) + { + ArrayItem temp = m_array[i]; + m_array[i] = m_array[largest]; + m_array[largest] = temp; + heapify(m_array, n, largest); + } } void SortArray::FillData(unsigned int schema, size_t arraysize) @@ -505,6 +520,20 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) ++min; --max; } } + else if (schema == 22) + { + int n = m_array.size(); + for (int i = 0; i < n; ++i) + { + m_array[i] = ArrayItem(i + 1); + } + std::shuffle(m_array.begin(), m_array.end(), g); + + for (int i = n / 2 - 1; i >= 0; --i) + { + heapify(m_array, n, i); + } + } else // fallback { return FillData(0, arraysize); From 177df44e0386f5fa6e7fa133b75ca8fb614e037f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 22:51:50 +0800 Subject: [PATCH 140/289] Added Flipped Min Heapified input type I also turned the if-else statements to case statements --- src/SortArray.cpp | 657 ++++++++++++++++++++++++---------------------- 1 file changed, 342 insertions(+), 315 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 98dde7a3c..37ec1bc8f 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -131,7 +131,21 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Quicksort Killer")); list.Add(_("Spike")); list.Add(_("Ribbon")); - list.Add(_("Heapified")); + list.Add(_("Max Heapified")); + list.Add(_("Flipped Min Heapified")); +} + +void minheapify(std::vector& m_array, int n, int i) { + int smallest = i, left = 2 * i + 1, right = 2 * i + 2; + if (left < n && m_array[left] < m_array[smallest]) { smallest = left; } + if (right < n && m_array[right] < m_array[smallest]) { smallest = right; } + if (smallest != i) + { + ArrayItem temp = m_array[i]; + m_array[i] = m_array[smallest]; + m_array[smallest] = temp; + minheapify(m_array, n, smallest); + } } void heapify(std::vector& m_array, int n, int i) @@ -154,391 +168,404 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { ResetArray(arraysize); } std::random_device rd; std::mt19937 g(rd()); - if (schema == 0) // Shuffle of [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - m_array[i] = ArrayItem(i+1); - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 1) // Ascending [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - m_array[i] = ArrayItem(i+1); - } - else if (schema == 2) // Descending + switch (schema) { - for (size_t i = 0; i < m_array.size(); ++i) - m_array[i] = ArrayItem(m_array.size() - i); - } - else if (schema == 3) // Near Sorted - { - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - } - ArrayItem temp = m_array[0]; - m_array[0] = m_array[m_array.size() - 1]; - m_array[m_array.size() - 1] = temp; - } - else if (schema == 4) // 25% Shuffled - { - std::vector::iterator it = m_array.begin(); - size_t half = m_array.size() / 2; - for (size_t i = 0; i < m_array.size(); ++i) + case 0: // Shuffle of [1,n] { - m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) - { ++it; } + for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); } + std::shuffle(m_array.begin(), m_array.end(), g); + break; } - std::shuffle(it, m_array.end(), g); - } - else if (schema == 5) // 25% Sorted, Head - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) + case 1: // Ascending [1,n] { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) - { ++it; } + for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); } + break; } - std::shuffle(m_array.begin(), it, g); - } - else if (schema == 6) // 50% Sorted - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) + case 2: // Descending { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) - { ++it; } + for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(m_array.size() - i); } + break; } - std::shuffle(it, m_array.end(), g); - } - else if (schema == 7) // 50% Sorted, Head - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) + case 3: // Near Sorted { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) - { ++it;} + for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); } + ArrayItem temp1 = m_array[0]; + m_array[0] = m_array[m_array.size() - 1]; + m_array[m_array.size() - 1] = temp1; + break; } - std::shuffle(m_array.begin(), it, g); - } - else if (schema == 8) // 75% Shuffled - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) + case 4: // 25% Shuffled { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) - { ++it; } + std::vector::iterator it1 = m_array.begin(); + size_t half = m_array.size() / 2; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= half + (half / 2)) + { ++it1; } + } + std::shuffle(it1, m_array.end(), g); + break; } - std::shuffle(it, m_array.end(), g); - } - else if (schema == 9) // 75% Shuffled, Head - { - std::vector::iterator it = m_array.begin(); - size_t half = m_array.size() / 2; - for (size_t i = 0; i < m_array.size(); ++i) + case 5: // 25% Sorted, Head { - m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) - { ++it; } - } - std::shuffle(m_array.begin(), it, g); - } - else if (schema == 10) // Cubic skew of [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) - { - // normalize to [-1,+1] - double x = (2.0 * (double)i / m_array.size()) - 1.0; - // calculate x^3 - double v = x * x * x; - // normalize to array size - double w = (v + 1.0) / 2.0 * arraysize + 1; - // decrease resolution for more equal values - w /= 3.0; - m_array[i] = ArrayItem(w + 1); + std::vector::iterator it = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4)) + { ++it; } + } + std::shuffle(m_array.begin(), it, g); + break; } - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 11) // Quintic skew of [1,n] - { - for (size_t i = 0; i < m_array.size(); ++i) + case 6: // 50% Sorted { - // normalize to [-1,+1] - double x = (2.0 * (double)i / m_array.size()) - 1.0; - // calculate x^5 - double v = x * x * x * x * x; - // normalize to array size - double w = (v + 1.0) / 2.0 * arraysize + 1; - // decrease resolution for more equal values - w /= 3.0; - m_array[i] = ArrayItem(w + 1); + std::vector::iterator it2 = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { ++it2; } + } + std::shuffle(it2, m_array.end(), g); + break; } - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 12) // shuffled n-2 equal values in [1,n] - { - m_array[0] = ArrayItem(1); - for (size_t i = 1; i < m_array.size()-1; ++i) + case 7: // 50% Sorted, Head { - m_array[i] = ArrayItem( arraysize / 2 + 1 ); + std::vector::iterator it3 = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { ++it3; } + } + std::shuffle(m_array.begin(), it3, g); + break; } - m_array[m_array.size()-1] = ArrayItem(arraysize); - - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 13) // Pipe organ (1, 1, 2, 2, 1, 1) - { - size_t n = m_array.size(); - - if (n % 2 == 0) + case 8: // 75% Shuffled { - int val = 1; - for (size_t i = 0; i < n / 2; ++i) + std::vector::iterator it4 = m_array.begin(); + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(val); ++val; + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4)) + { ++it4; } } - val = n / 2; - for (size_t i = n / 2; i <= n - 1; ++i) + std::shuffle(it4, m_array.end(), g); + break; + } + case 9: // 75% Shuffled, Head + { + std::vector::iterator it5 = m_array.begin(); + size_t half = m_array.size() / 2; + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(val); --val; + m_array[i] = ArrayItem(i + 1); + if (i <= half + (half / 2)) + { ++it5; } } + std::shuffle(m_array.begin(), it5, g); + break; } - else + case 10: // Cubic skew of [1,n] { - int val = 1; - for (size_t i = 0; i <= n / 2; ++i) + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(val); ++val; + // normalize to [-1,+1] + double x = (2.0 * (double)i / m_array.size()) - 1.0; + // calculate x^3 + double v = x * x * x; + // normalize to array size + double w = (v + 1.0) / 2.0 * arraysize + 1; + // decrease resolution for more equal values + w /= 3.0; + m_array[i] = ArrayItem(w + 1); } - val = n / 2; - for (size_t i = (n / 2) + 1; i <= n - 1; ++i) + std::shuffle(m_array.begin(), m_array.end(), g); + break; + } + case 11: // Quintic skew of [1,n] + { + for (size_t i = 0; i < m_array.size(); ++i) { - m_array[i] = ArrayItem(val); --val; + // normalize to [-1,+1] + double x = (2.0 * (double)i / m_array.size()) - 1.0; + // calculate x^5 + double v = x * x * x * x * x; + // normalize to array size + double w = (v + 1.0) / 2.0 * arraysize + 1; + // decrease resolution for more equal values + w /= 3.0; + m_array[i] = ArrayItem(w + 1); } + std::shuffle(m_array.begin(), m_array.end(), g); + break; } - } - else if (schema == 14) // Mirrored organ (3, 2, 1, 1, 2, 3) - { - size_t n = m_array.size(); - - if (n % 2 == 0) + case 12: // shuffled n-2 equal values in [1,n] { - int val = n / 2; - for (size_t i = 0; i < n / 2; ++i) + m_array[0] = ArrayItem(1); + for (size_t i = 1; i < m_array.size() - 1; ++i) { m_array[i] = ArrayItem(arraysize / 2 + 1); } + m_array[m_array.size() - 1] = ArrayItem(arraysize); + std::shuffle(m_array.begin(), m_array.end(), g); + break; + } + case 13: // Pipe organ (1, 1, 2, 2, 1, 1) + { + size_t n = m_array.size(); + if (n % 2 == 0) { - m_array[i] = ArrayItem(val); --val; + int val = 1; + for (size_t i = 0; i < n / 2; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + val = n / 2; + for (size_t i = n / 2; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); --val; + } } - val = 1; - for (size_t i = n / 2; i <= n - 1; ++i) + else { - m_array[i] = ArrayItem(val); ++val; + int val = 1; + for (size_t i = 0; i <= n / 2; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } + val = n / 2; + for (size_t i = (n / 2) + 1; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); --val; + } } + break; } - else + case 14: // Mirrored organ (3, 2, 1, 1, 2, 3) { - int val = n / 2; - for (size_t i = 0; i <= n / 2; ++i) + size_t n = m_array.size(); + if (n % 2 == 0) { - m_array[i] = ArrayItem(val); - if (val >= 2) { --val; } + int val = n / 2; + for (size_t i = 0; i < n / 2; ++i) + { + m_array[i] = ArrayItem(val); --val; + } + val = 1; + for (size_t i = n / 2; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } } - val = 1; - for (size_t i = (n / 2) + 1; i <= n - 1; ++i) + else { - m_array[i] = ArrayItem(val); ++val; + int val = n / 2; + for (size_t i = 0; i <= n / 2; ++i) + { + m_array[i] = ArrayItem(val); + if (val >= 2) { --val; } + } + val = 1; + for (size_t i = (n / 2) + 1; i <= n - 1; ++i) + { + m_array[i] = ArrayItem(val); ++val; + } } + break; } - } - else if (schema == 15) // Wave - { - double n = double(m_array.size()); - double pi = 3.14159265358979323846; - for (size_t i = 0; i < m_array.size(); ++i) - { - double x = i / n * 3 * pi * 5; - double sineVal = sin(x); - int val = std::round((sineVal + 1) * 100); - m_array[i] = ArrayItem(val + 1); - } - } - else if (schema == 16) // Sawtooth - { - size_t n = m_array.size(), teeth; - if (n % 5 == 0) { teeth = 5; } - else if (n % 4 == 0) { teeth = 4; } - else if (n % 3 == 0) { teeth = 3; } - else { teeth = 2; } - int max = n / teeth; - int count = 1; - for (size_t i = 0; i < n; ++i) - { - if (count > max) { count = 1; } - m_array[i] = ArrayItem(count); - ++count; - } - if (teeth == 2 && m_array[n - 1] == 1) + case 15: // Wave { - size_t m = n - 1; - while (m_array[m - 1] > m_array[m]) + double n = double(m_array.size()); + double pi = 3.14159265358979323846; + for (size_t i = 0; i < m_array.size(); ++i) { - ArrayItem temp = m_array[m - 1]; - m_array[m - 1] = m_array[m]; - m_array[m] = temp; - --m; + double x = i / n * 3 * pi * 5; + double sineVal = sin(x); + int val = std::round((sineVal + 1) * 100); + m_array[i] = ArrayItem(val + 1); } + break; } - } - else if (schema == 17) // Reverse Sawtooth - { - size_t n = m_array.size(), teeth; - if (n % 5 == 0) { teeth = 5; } - else if (n % 4 == 0) { teeth = 4; } - else if (n % 3 == 0) { teeth = 3; } - else { teeth = 2; } - int max = n / teeth; - int count = max; - for (size_t i = 0; i < n; ++i) + case 16: // Sawtooth { - if (count <= 0) { count = max; } - m_array[i] = ArrayItem(count); - --count; + size_t n = m_array.size(), teeth; + if (n % 5 == 0) { teeth = 5; } + else if (n % 4 == 0) { teeth = 4; } + else if (n % 3 == 0) { teeth = 3; } + else { teeth = 2; } + int max = n / teeth; + int count = 1; + for (size_t i = 0; i < n; ++i) + { + if (count > max) { count = 1; } + m_array[i] = ArrayItem(count); + ++count; + } + if (teeth == 2 && m_array[n - 1] == 1) + { + size_t m = n - 1; + while (m_array[m - 1] > m_array[m]) + { + ArrayItem temp5 = m_array[m - 1]; + m_array[m - 1] = m_array[m]; + m_array[m] = temp5; + --m; + } + } + break; } - if (teeth == 2 && m_array[n - 1] == max) + case 17: // Reverse Sawtooth { - size_t m = n - 1; - while (m_array[m - 1] < m_array[m]) + size_t n = m_array.size(), teeth; + if (n % 5 == 0) { teeth = 5; } + else if (n % 4 == 0) { teeth = 4; } + else if (n % 3 == 0) { teeth = 3; } + else { teeth = 2; } + int max = n / teeth; + int count = max; + for (size_t i = 0; i < n; ++i) { - ArrayItem temp = m_array[m - 1]; - m_array[m - 1] = m_array[m]; - m_array[m] = temp; - --m; + if (count <= 0) { count = max; } + m_array[i] = ArrayItem(count); + --count; } + if (teeth == 2 && m_array[n - 1] == max) + { + size_t m = n - 1; + while (m_array[m - 1] < m_array[m]) + { + ArrayItem temp4 = m_array[m - 1]; + m_array[m - 1] = m_array[m]; + m_array[m] = temp4; + --m; + } + } + break; } - } - else if (schema == 18) // Many Similar - { - size_t group_count = 0; - size_t size = m_array.size(); - if (size % 10 == 0) { group_count = 10; } - else if (size % 9 == 0) { group_count = 9; } - else if (size % 8 == 0) { group_count = 8; } - else if (size % 7 == 0) { group_count = 7; } - else if (size % 6 == 0) { group_count = 6; } - else if (size % 5 == 0) { group_count = 5; } - else if (size % 4 == 0) { group_count = 4; } - else if (size % 2 != 0) { group_count = 3; } - else { group_count = 2; } - size_t n = m_array.size(); - if (n <= 10) + case 18: // Many Similar { - if (n % 2 != 0) { group_count = 3; } + size_t group_count = 0, size = m_array.size(); + if (size % 10 == 0) { group_count = 10; } + else if (size % 9 == 0) { group_count = 9; } + else if (size % 8 == 0) { group_count = 8; } + else if (size % 7 == 0) { group_count = 7; } + else if (size % 6 == 0) { group_count = 6; } + else if (size % 5 == 0) { group_count = 5; } + else if (size % 4 == 0) { group_count = 4; } + else if (size % 2 != 0) { group_count = 3; } else { group_count = 2; } + size_t n = m_array.size(); + if (n <= 10) + { + if (n % 2 != 0) { group_count = 3; } + else { group_count = 2; } + } + size_t repeat = 1; + int val = 1; + for (size_t i = 0; i < size; ++i) + { + if (repeat > group_count) + { + ++val; repeat = 1; + } + m_array[i] = ArrayItem(val); + ++repeat; + } + std::shuffle(m_array.begin(), m_array.end(), g); + break; } - size_t repeat = 1; - int val = 1; - for (size_t i = 0; i < size; ++i) - { - if (repeat > group_count) - { ++val; repeat = 1; } - m_array[i] = ArrayItem(val); - ++repeat; - } - std::shuffle(m_array.begin(), m_array.end(), g); - } - else if (schema == 19) // Quicksort Killer - { - int currentLen = m_array.size(); - for (int i = 0; i < currentLen; ++i) - { - m_array[i] = ArrayItem(i + 1); - } - for (int j = currentLen - currentLen % 2 - 2, i = j - 1; i >= 0; i -= 2, j--) - { - ArrayItem temp = m_array[i]; - m_array[i] = m_array[j]; - m_array[j] = temp; - } - - } - else if (schema == 20) // Spike - { - size_t n = m_array.size(); - int spike, val = 1; - if (n % 10 == 0) { spike = 5; } - else if (n % 8 == 0) { spike = 4; } - else if (n % 6 == 0) { spike = 3; } - else { spike = 2; } - int max = n / (spike * 2); - if (max == 1) { max = n / spike; } - for (size_t i = 0; i < n; ++i) + case 19: // Quicksort Killer { - while (val <= max && i < n) + int currentLen = m_array.size(); + for (int i = 0; i < currentLen; ++i) { - m_array[i] = ArrayItem(val); ++val; ++i; + m_array[i] = ArrayItem(i + 1); } - if (n % 2 == 0) { val = max; } - else { val = max - 1; } - while (val > 0 && i < n) + for (int j = currentLen - currentLen % 2 - 2, i = j - 1; i >= 0; i -= 2, j--) { - m_array[i] = ArrayItem(val); --val; - if (val != 0) { ++i; } + ArrayItem temp3 = m_array[i]; + m_array[i] = m_array[j]; + m_array[j] = temp3; } - val = 1; + break; } - size_t start, end; - start = end = m_array.size() - 1; - while (m_array[start - 1] < m_array[start]) - { --start; } - for (; start <= end; ++start) + case 20: // Spike { - ArrayItem key = m_array[start]; - size_t j = start; - while (j >= 1 && m_array[j - 1] <= key) + size_t n = m_array.size(); + int spike, val = 1; + if (n % 10 == 0) { spike = 5; } + else if (n % 8 == 0) { spike = 4; } + else if (n % 6 == 0) { spike = 3; } + else { spike = 2; } + int max = n / (spike * 2); + if (max == 1) { max = n / spike; } + for (size_t i = 0; i < n; ++i) + { + while (val <= max && i < n) + { + m_array[i] = ArrayItem(val); ++val; ++i; + } + if (n % 2 == 0) { val = max; } + else { val = max - 1; } + while (val > 0 && i < n) + { + m_array[i] = ArrayItem(val); --val; + if (val != 0) { ++i; } + } + val = 1; + } + size_t start, end; + start = end = m_array.size() - 1; + while (m_array[start - 1] < m_array[start]) { - m_array[j] = m_array[j - 1]; - --j; + --start; } - m_array[j] = key; + for (; start <= end; ++start) + { + ArrayItem key = m_array[start]; + size_t j = start; + while (j >= 1 && m_array[j - 1] <= key) + { + m_array[j] = m_array[j - 1]; + --j; + } + m_array[j] = key; + } + break; } - } - else if (schema == 21) // Ribbon - { - int min = 1; - int max = m_array.size(); - for (size_t i = 0; i < m_array.size(); ++i) + case 21: // Ribbon { - if (i % 2 == 0) { m_array[i] = ArrayItem(min); } - else { m_array[i] = ArrayItem(max); } - ++min; --max; + int min = 1; + int max = m_array.size(); + for (size_t i = 0; i < m_array.size(); ++i) + { + if (i % 2 == 0) { m_array[i] = ArrayItem(min); } + else { m_array[i] = ArrayItem(max); } + ++min; --max; + } + break; } - } - else if (schema == 22) - { - int n = m_array.size(); - for (int i = 0; i < n; ++i) + case 22: // Max Heapified { - m_array[i] = ArrayItem(i + 1); + int n = m_array.size(); + for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } + std::shuffle(m_array.begin(), m_array.end(), g); + for (int i = n / 2 - 1; i >= 0; --i) { heapify(m_array, n, i); } + break; } - std::shuffle(m_array.begin(), m_array.end(), g); - - for (int i = n / 2 - 1; i >= 0; --i) + case 23: // Flipped Min Heapified { - heapify(m_array, n, i); + int n = m_array.size(); + for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } + std::shuffle(m_array.begin(), m_array.end(), g); + for (int i = n / 2 - 1; i >= 0; --i) { minheapify(m_array, n, i); } + std::reverse(m_array.begin(), m_array.end()); + break; } + default: + return FillData(0, arraysize); + break; } - else // fallback - { - return FillData(0, arraysize); - } - FinishFill(); } From a9a66873b93168d9e4e29295bae6888066546fb0 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 22:53:17 +0800 Subject: [PATCH 141/289] Update SortArray.cpp --- src/SortArray.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 37ec1bc8f..c3e2678eb 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -564,7 +564,6 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } default: return FillData(0, arraysize); - break; } FinishFill(); } From 2d3a5b2c46da2a6d824a482b0106604bd9274b74 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 22:59:05 +0800 Subject: [PATCH 142/289] Added a counted_rotate() method --- src/SortArray.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/SortArray.h b/src/SortArray.h index 4fb3b9015..d39e7f456 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -71,12 +71,35 @@ template ForwardIt2 counted_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) { while (first1 != last1) { counted_iter_swap(first1, first2); - ++first1; + ++first1; ++first2; } return first2; } +template +ForwardIt counted_rotate(ForwardIt first, ForwardIt middle, ForwardIt last) +{ + if (first == middle) + return last; + + if (middle == last) + return first; + + ForwardIt write = first; + ForwardIt next_read = first; + + for (ForwardIt read = middle; read != last; ++write, ++read) + { + if (write == next_read) + next_read = read; + counted_iter_swap(write, read); + } + + counted_rotate(write, next_read, last); + return write; +} + // custom struct for array items, which allows detailed counting of comparisons. class ArrayItem { From 1581878d5f53a744a77992e0939d89cae7250e04 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 22 Oct 2024 23:01:35 +0800 Subject: [PATCH 143/289] WikiSort will now use counted_rotate() --- src/algorithms/wikisort.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/wikisort.cpp b/src/algorithms/wikisort.cpp index 5a2b0b586..038df4418 100644 --- a/src/algorithms/wikisort.cpp +++ b/src/algorithms/wikisort.cpp @@ -73,7 +73,7 @@ size_t FloorPowerOfTwo (const size_t value) { template void InsertionSort(Iterator begin, Iterator end, const Comparison compare) { for (Iterator it = begin; it != end; ++it) { - std::rotate(std::upper_bound(begin, it, *it, compare), it, it+1); + counted_rotate(std::upper_bound(begin, it, *it, compare), it, it+1); } } @@ -117,7 +117,7 @@ void Rotate(Iterator begin, Iterator end, const ssize_t amount, } } - std::rotate(begin, split, end); + counted_rotate(begin, split, end); } // standard merge operation using an internal or external buffer From 84c43b1d0d816917c57ee0a9af4fe05296576bf2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 03:31:49 +0800 Subject: [PATCH 144/289] Added Andrey Astrelin's In-Place Merge Sort --- src/SortAlgo.cpp | 133 +++++++++++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 1 + 2 files changed, 134 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index aa6b68866..111225583 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -75,6 +75,8 @@ const struct AlgoEntry g_algolist[] = _("An improvement upon Weave Merge Sort, with faster weave time, and inserting now makes comparisons with a worst-case similar to Merge Sort.") }, { _("Strand Sort"), &StrandSort, UINT_MAX, 512, wxEmptyString }, + { _("Andrey's In-Place Merge Sort"), &AndreyMergeSort, UINT_MAX, 512, + wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, _("Quick sort variant with left and right pointers.") }, { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, @@ -2973,3 +2975,134 @@ void NewShuffleMergeSort(SortArray& A) // **************************************************************************** // *** Andrey Astrelin's In-Place Merge Sort +void sortVector(SortArray& A, size_t a, size_t b) +{ + while (b > 1) + { + size_t k = 0; + for (size_t i = 1; i < b; ++i) + { + if (A[a + k] > A[a + i]) { k = i; } + } + A.swap(a, a + k); + ++a; --b; + } +} + +void aswap(SortArray& A, size_t arr1, size_t arr2, size_t l) +{ + while (l-- > 0) + { + A.swap(arr1, arr2); + ++arr1; ++arr2; + } +} + +int backMerge(SortArray& A, size_t arr1, size_t l1, size_t arr2, size_t l2) +{ + size_t arr0 = arr2 + l1; + for (;;) + { + if (A[arr1] > A[arr2]) + { + A.swap(arr1, arr0); + --arr1; --arr0; + if (--l1 == 0) { return 0; } + } + else + { + A.swap(arr2, arr0); + --arr2; --arr0; + if (--l2 == 0) { break; } + } + } + size_t res = l1; + do + { + A.swap(arr1, arr0); + --arr1; --arr0; + } + while (--l1 != 0); + return res; +} + +void rMerge(SortArray& A, size_t a, size_t l, size_t r) +{ + for (size_t i = 0; i < l; i += r) + { + size_t q = i; + for (size_t j = i + r; j < l; j += r) + { + if (A[a + q] > A[a + j]) { q = j; } + } + if (q != i) { aswap(A, a + i, a + q, r); } + if (i != 0) + { + aswap(A, a + l, a + i, r); + backMerge(A, a + (l + r - 1), r, a + (i - 1), r); + } + } +} + +size_t rbnd(size_t len) +{ + len = len / 2; + size_t k = 0; + for (size_t i = 1; i < len; i *= 2) { ++k; } + len /= k; + for (k = 1; k <= len; k *= 2) {} + return k; +} + +void msort(SortArray& A, size_t a, size_t len) +{ + if (len < 12) { sortVector(A, a, len); return; } + size_t r = rbnd(len), lr = (len / r - 1) * r; + for (size_t p = 2; p <= lr; p += 2) + { + if (A[a + (p - 2)] > A[a + (p - 1)]) + { A.swap(a + (p - 2), a + (p - 1)); } + if ((p & 2) != 0) { continue; } + aswap(A, a + (p - 2), a + p, 2); + size_t m = len - p, q = 2; + for (;;) + { + size_t q0 = 2 * q; + if (q0 > m || (p & q0) != 0) { break; } + backMerge(A, a + (p - q - 1), q, a + (p + q - 1), q); + q = q0; + } + backMerge(A, a + (p + q - 1), q, a + (p - q - 1), q); + size_t q1 = q; + q *= 2; + while ((q & p) == 0) + { + q *= 2; + rMerge(A, a + (p - q), q, q1); + } + } + + size_t q1 = 0; + for (size_t q = r; q < lr; q *= 2) + { + if ((lr & q) != 0) + { + q1 += q; + if (q1 != q) + { + rMerge(A, a + (lr - q1), q1, r); + } + } + } + + size_t s = len - lr; + msort(A, a + lr, s); + aswap(A, a, a + lr, s); + s += backMerge(A, a + (s - 1), s, a + (lr - 1), lr - s); + msort(A, a, s); +} + +void AndreyMergeSort(SortArray& A) +{ + msort(A, 0, A.size()); +} diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 41917a772..c0fc4095d 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -66,6 +66,7 @@ void PairwiseIterativeSort(class SortArray& a); void WeaveMergeSort(class SortArray& a); void StrandSort(class SortArray& a); void NewShuffleMergeSort(class SortArray& a); +void AndreyMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); From e282219259b5ac3592a3519cace7e1bc73add9d5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 13:24:40 +0800 Subject: [PATCH 145/289] Removed Yield() and TestDestroy() call Using Yield() to "pause" the thread to allow other threads to run is not recommended, as the "pause" provided by Yield() is reliant on the OS scheduler and this could lead to unpredictable behavior. Instead, using wxMilliSleep() allows for a more consistent and predictable pausing, while also allowing other threads to do their tasks. Calling TestDestroy() on its own is not going to take any effect. Since the thread is signaled with Wait(), rather than Delete(), when the thread is done executing something, TestDestroy() has no value here, since it would never become true when used as a condition [if (TestDestroy())], even more so if it is called on its own. Unless the thread will be signaled with Delete(), TestDestroy() here is unnecessary. I also think that if the thread is signaled to terminate using the boolean flag, not only should the DoDelay() method call the Exit() method of the thread, any other code below this should not be executed anymore since the thread has been signaled to stop, hence the added return statement. The numBrushes change will now be consistent for both step and non-step visualization rendering. --- src/WSortView.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index b4494c447..7849174a8 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -81,7 +81,10 @@ void WSortView::DoDelay(double delay) ASSERT(wxThread::GetCurrentId() == wmain->m_thread->GetId()); if (wmain->m_thread_terminate) + { wmain->m_thread->Exit(); + return; + } // idle until main thread signals a condition while (m_stepwise) @@ -90,12 +93,9 @@ void WSortView::DoDelay(double delay) if (se == wxSEMA_NO_ERROR) break; // else timeout, recheck m_stepwise and loop - wmain->m_thread->TestDestroy(); - wmain->m_thread->Yield(); + wxMilliSleep(1); } - wmain->m_thread->TestDestroy(); - #if __WXGTK__ wxMicroSleep(delay * 1000.0); #elif MSW_PERFORMANCECOUNTER @@ -245,11 +245,10 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) wxMutexLocker lock(m_array.m_mutex); ASSERT(lock.IsOk()); - + int numBrushes = sizeof(brushes) / sizeof(brushes[0]); if (step > 1) { size_t i_step = step; - int numBrushes = sizeof(brushes) / sizeof(brushes[0]); for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); @@ -273,7 +272,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); - ASSERT(clr < (int)(sizeof(brushes) / sizeof(brushes[0]))); + ASSERT(clr < numBrushes); dc.SetPen(pens[clr]); dc.SetBrush(brushes[clr]); dc.DrawRectangle(i * bstep, height, From b9c1a0b5ef0d4a09b8ddea3bde9bcae95f1a14b3 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 13:45:40 +0800 Subject: [PATCH 146/289] Altered the speed slider description --- src/wxg/WMain_wxg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wxg/WMain_wxg.cpp b/src/wxg/WMain_wxg.cpp index 0b4b0304c..c9cf11bbf 100644 --- a/src/wxg/WMain_wxg.cpp +++ b/src/wxg/WMain_wxg.cpp @@ -66,7 +66,7 @@ void WMain_wxg::set_properties() SetTitle(_("The Sound of Sorting - http://panthema.net/2013/sound-of-sorting")); sortview->SetMinSize(wxSize(640, 480)); speedSlider->SetToolTip(_("Changes the animation speed by setting the delay for each array access.")); - arraySizeSlider->SetToolTip(_("Resize the options panel if a sorting algorithm doesn't\nimmediately update the visualized array when it's supposed to.")); + arraySizeSlider->SetToolTip(_("Resize the options panel if the visualized array doesn't seem to update.")); soundSustainSlider->SetToolTip(_("Changes the duration of each access sound as a multiple of the delay.")); labelInversionCount->SetToolTip(_("Current number of inversions. Click to enable or disable.")); labelRunsCount->SetToolTip(_("Current number of runs.")); From b934c34d23fed40a05cfc9a79f076ee32d5134a8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 17:01:57 +0800 Subject: [PATCH 147/289] Provided high-level implementations of std::sort and std::sort_heap Since std::sort and std::sort_heap are standard library implementations, it is difficult to track the swaps performed by these sorting algorithms, therefore, I provided a high-level implementation of these methods in order to count the swaps they perform. Introsort (std::sort) with its Heap Sort fallback has been confirmed to work properly thanks to the Quicksort Killer input. The only problem now is using the high-level Max Heap Sort with boundaries on PDQ Sort. --- src/SortAlgo.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 111225583..96cb70e20 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1640,20 +1640,162 @@ void InPlaceRadixSortLSD(SortArray& A) // **************************************************************************** // *** Use STL Sorts via Iterator Adapters +void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) +{ + int compareVal = 0; + if (isMax) { compareVal = -1; } + else { compareVal = 1; } + while (root <= dist / 2) + { + size_t leaf = 2 * root; + int compVal = 0; + if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } + else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } + + if (leaf < dist && compVal == compareVal) { ++leaf; } + + if (A[start + root - 1] < A[start + leaf - 1]) { compVal = -1; } + else if (A[start + root - 1] > A[start + leaf - 1]) { compVal = 1; } + else { compVal = 0; } + + if (compVal == compareVal) + { + A.swap(start + root - 1, start + leaf - 1); + root = leaf; + } + else { break; } + } +} + +void heapifyArr(SortArray& A, size_t low, size_t high, bool isMax) +{ + size_t len = high - low; + for (size_t i = len / 2; i >= 1; --i) + { + siftDown(A, i, len, low, isMax); + } +} + +void reverseArr(SortArray& A, size_t start, size_t len) +{ + for (size_t i = start; i < start + ((len - start + 1) / 2); ++i) + { + A.swap(i, start + len - 1); + } +} + +void HeapSort2(SortArray& A, size_t start, size_t len, bool isMax) +{ + heapifyArr(A, start, len, isMax); + for (size_t i = len - start; i > 1; --i) + { + A.swap(start, start + i - 1); + siftDown(A, 1, i - 1, start, isMax); + } + + if (!isMax) + { + reverseArr(A, start, start + len - 1); + } +} + +size_t floorLogBaseTwo(size_t a) +{ + return static_cast(floor(log(a) / log(2))); +} + +value_type gccmedianof3(SortArray& A, size_t left, size_t mid, size_t right) +{ + if (A[left] < A[mid]) + { + if (A[mid] < A[right]) + { + A.swap(left, mid); + } + else if (A[left] < A[right]) + { + A.swap(left, right); + } + } + else if (A[left] < A[right]) { return A[left]; } + else if (A[mid] < A[right]) + { + A.swap(left, right); + } + else + { + A.swap(mid, right); + } + return A[left]; +} + +value_type medianof3(SortArray& A, size_t left, size_t mid, size_t right) +{ + if (A[right] < A[left]) { A.swap(left, right); } + if (A[mid] < A[left]) { A.swap(mid, left); } + if (A[right] < A[mid]) { A.swap(right, mid); } + return A[mid]; +} + +size_t partitionArr(SortArray& A, size_t lo, size_t hi, value_type x) +{ + size_t i = lo, j = hi; + while (true) + { + while (A[i] < x) { ++i; } + --j; + while (x < A[j]) { --j; } + + if (!(i < j)) { return i; } + A.swap(i, j); + ++i; + } +} + +void introsortLoop(SortArray& A, size_t lo, size_t hi, size_t depth) +{ + size_t threshold = 16; + while (hi - lo > threshold) + { + if (depth == 0) + { + HeapSort2(A, lo, hi, true); + return; + } + --depth; + size_t p = partitionArr(A, lo, hi, medianof3(A, lo, lo + ((hi - lo) / 2), hi - 1)); + introsortLoop(A, p, hi, depth); + hi = p; + } + return; +} + void StlSort(SortArray& A) { - std::sort(MyIterator(&A,0), MyIterator(&A,A.size())); + size_t n = A.size(); + introsortLoop(A, 0, n, 2 * floorLogBaseTwo(n)); + InsertionSort(A); +} + +void StlSort2(SortArray& A) +{ + std::sort(MyIterator(&A, 0), MyIterator(&A, A.size())); } void StlStableSort(SortArray& A) { - std::stable_sort(MyIterator(&A,0), MyIterator(&A,A.size())); + std::stable_sort(MyIterator(&A, 0), MyIterator(&A, A.size())); +} + +void StlHeapSort2(SortArray& A) +{ + std::make_heap(MyIterator(&A, 0), MyIterator(&A, A.size())); + std::sort_heap(MyIterator(&A, 0), MyIterator(&A, A.size())); } void StlHeapSort(SortArray& A) { - std::make_heap(MyIterator(&A,0), MyIterator(&A,A.size())); - std::sort_heap(MyIterator(&A,0), MyIterator(&A,A.size())); + HeapSort2(A, 0, A.size(), true); } // **************************************************************************** From 434d872200a162cb9de64f2f4f351789d8711a3a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 17:32:17 +0800 Subject: [PATCH 148/289] Fixed high level implementation of std::sort_heap crashing on even size arrays --- src/SortAlgo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 96cb70e20..5fb8502f4 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1647,7 +1647,7 @@ void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) else { compareVal = 1; } while (root <= dist / 2) { - size_t leaf = 2 * root; + size_t leaf = 2 * root - 1; int compVal = 0; if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } @@ -1670,7 +1670,7 @@ void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) void heapifyArr(SortArray& A, size_t low, size_t high, bool isMax) { size_t len = high - low; - for (size_t i = len / 2; i >= 1; --i) + for (size_t i = len; i >= 1; --i) { siftDown(A, i, len, low, isMax); } From e5c8785a41eb36d47750cba1b5cfb8407ec8f676 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 17:35:01 +0800 Subject: [PATCH 149/289] Fixed std::sort_heap heapify() --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 5fb8502f4..0bb41eb78 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1670,7 +1670,7 @@ void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) void heapifyArr(SortArray& A, size_t low, size_t high, bool isMax) { size_t len = high - low; - for (size_t i = len; i >= 1; --i) + for (size_t i = len / 2; i >= 1; --i) { siftDown(A, i, len, low, isMax); } From 857cd3d2c670fa521719e1d8f2d7996a033f4566 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 19:21:13 +0800 Subject: [PATCH 150/289] Fixed std::sort_heap high level implementation This fix should be even more consistent than the previous one. --- src/SortAlgo.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 0bb41eb78..9c2c59081 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1645,10 +1645,12 @@ void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) int compareVal = 0; if (isMax) { compareVal = -1; } else { compareVal = 1; } + size_t n = A.size(); while (root <= dist / 2) { - size_t leaf = 2 * root - 1; + size_t leaf = 2 * root; int compVal = 0; + if (leaf >= n) { --leaf; } if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } From e3effd5f6203289730aa0332dddb1769b38dae90 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 19:37:43 +0800 Subject: [PATCH 151/289] Fixed high-level std::sort_heap() Sorry, this should be the final fix, I have made sure that this will work for every test case I can think of. --- src/SortAlgo.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 9c2c59081..c0261ca3d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1645,16 +1645,17 @@ void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) int compareVal = 0; if (isMax) { compareVal = -1; } else { compareVal = 1; } - size_t n = A.size(); while (root <= dist / 2) { size_t leaf = 2 * root; int compVal = 0; - if (leaf >= n) { --leaf; } - if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } - else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } - if (leaf < dist && compVal == compareVal) { ++leaf; } + if (leaf < dist) + { + if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } + else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } + if (compVal == compareVal) { ++leaf; } + } if (A[start + root - 1] < A[start + leaf - 1]) { compVal = -1; } else if (A[start + root - 1] > A[start + leaf - 1]) { compVal = 1; } From 4c54a650b70385895161de4425eff3eecf2b0fb8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 19:51:54 +0800 Subject: [PATCH 152/289] Introsort will now use InsertionSort2() --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index c0261ca3d..ceaa78feb 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1777,7 +1777,7 @@ void StlSort(SortArray& A) { size_t n = A.size(); introsortLoop(A, 0, n, 2 * floorLogBaseTwo(n)); - InsertionSort(A); + InsertionSort2(A); } void StlSort2(SortArray& A) From fd221194d92c98736bc340b82aff37dbfd4e5ef8 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 20:32:52 +0800 Subject: [PATCH 153/289] Optimized Flipped Min Heapified array generation Adapted from Flipped Min Heap Sort of ArrayV, yes, this code can also be used to make Flipped Min Heap Sort. The difference between this and the previous implementation is that now, less work is needed to generate this array input type, no more std::reverse() --- src/SortArray.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index c3e2678eb..8844797f0 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -135,16 +135,20 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Flipped Min Heapified")); } -void minheapify(std::vector& m_array, int n, int i) { - int smallest = i, left = 2 * i + 1, right = 2 * i + 2; - if (left < n && m_array[left] < m_array[smallest]) { smallest = left; } - if (right < n && m_array[right] < m_array[smallest]) { smallest = right; } - if (smallest != i) +void flippedminheapify(std::vector& m_array, int len, int root, int dist) +{ + while (root <= dist / 2) { - ArrayItem temp = m_array[i]; - m_array[i] = m_array[smallest]; - m_array[smallest] = temp; - minheapify(m_array, n, smallest); + int leaf = 2 * root; + if (leaf < dist && m_array[len - leaf] > m_array[len - leaf - 1]) { ++leaf; } + if (m_array[len - root] > m_array[len - leaf]) + { + ArrayItem temp = m_array[len - root]; + m_array[len - root] = m_array[len - leaf]; + m_array[len - leaf] = temp; + root = leaf; + } + else { break; } } } @@ -558,8 +562,8 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) int n = m_array.size(); for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } std::shuffle(m_array.begin(), m_array.end(), g); - for (int i = n / 2 - 1; i >= 0; --i) { minheapify(m_array, n, i); } - std::reverse(m_array.begin(), m_array.end()); + for (int i = n / 2; i >= 1; --i) + { flippedminheapify(m_array, n, i, n); } break; } default: From 575d7e7ac2e79b58d83c949e6ca490e47950bda6 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 23:05:12 +0800 Subject: [PATCH 154/289] Enable optimized build I noticed that the application is built on debug mode, so I decided to now ensure that when the application is being compiled, it will now be in optimized mode --- src/Makefile | 1123 +++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 2 +- src/Makefile.in | 2 +- 3 files changed, 1125 insertions(+), 2 deletions(-) create mode 100644 src/Makefile diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 000000000..4f9342605 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,1123 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# src/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +# $Id: Makefile.am 2 2007-01-05 14:04:27Z tb $ + + +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/sound-of-sorting +pkgincludedir = $(includedir)/sound-of-sorting +pkglibdir = $(libdir)/sound-of-sorting +pkglibexecdir = $(libexecdir)/sound-of-sorting +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-w64-mingw32 +host_triplet = x86_64-w64-mingw32 +target_triplet = x86_64-w64-mingw32 +bin_PROGRAMS = sound-of-sorting$(EXEEXT) +noinst_PROGRAMS = sorting-test$(EXEEXT) +TESTS = sorting-test$(EXEEXT) +am__append_1 = resources.o +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am__dirstamp = $(am__leading_dot)dirstamp +am__objects_1 = SortArray.$(OBJEXT) SortSound.$(OBJEXT) \ + SortAlgo.$(OBJEXT) algorithms/grailsort.$(OBJEXT) \ + algorithms/pdqsort.$(OBJEXT) algorithms/timsort.$(OBJEXT) \ + algorithms/wikisort.$(OBJEXT) +am_sorting_test_OBJECTS = SortTest.$(OBJEXT) $(am__objects_1) +sorting_test_OBJECTS = $(am_sorting_test_OBJECTS) +sorting_test_LDADD = $(LDADD) +sorting_test_DEPENDENCIES = $(am__append_1) +am_sound_of_sorting_OBJECTS = WMain.$(OBJEXT) wxg/WMain_wxg.$(OBJEXT) \ + wxg/WAbout_wxg.$(OBJEXT) WSortView.$(OBJEXT) \ + wxClickText.$(OBJEXT) $(am__objects_1) +sound_of_sorting_OBJECTS = $(am_sound_of_sorting_OBJECTS) +sound_of_sorting_LDADD = $(LDADD) +sound_of_sorting_DEPENDENCIES = $(am__append_1) +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I. +depcomp = $(SHELL) $(top_srcdir)/acscripts/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/SortAlgo.Po ./$(DEPDIR)/SortArray.Po \ + ./$(DEPDIR)/SortSound.Po ./$(DEPDIR)/SortTest.Po \ + ./$(DEPDIR)/WMain.Po ./$(DEPDIR)/WSortView.Po \ + ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/grailsort.Po \ + algorithms/$(DEPDIR)/pdqsort.Po \ + algorithms/$(DEPDIR)/timsort.Po \ + algorithms/$(DEPDIR)/wikisort.Po wxg/$(DEPDIR)/WAbout_wxg.Po \ + wxg/$(DEPDIR)/WMain_wxg.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_$(V)) +am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY)) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_CXXLD = $(am__v_CXXLD_$(V)) +am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(sorting_test_SOURCES) $(sound_of_sorting_SOURCES) +DIST_SOURCES = $(sorting_test_SOURCES) $(sound_of_sorting_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = .exe .test +LOG_DRIVER = $(SHELL) $(top_srcdir)/acscripts/test-driver +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:.exe.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/acscripts/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/acscripts/depcomp \ + $(top_srcdir)/acscripts/test-driver +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' aclocal-1.16 +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 1 +AUTOCONF = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoconf +AUTOHEADER = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoheader +AUTOMAKE = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' automake-1.16 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -Wno-unused-local-typedefs +CPPFLAGS = +CSCOPE = cscope +CTAGS = ctags +CXX = g++ +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -O2 -Wno-unused-local-typedefs +CYGPATH_W = cygpath -w +DEFS = -DPACKAGE_NAME=\"sound-of-sorting\" -DPACKAGE_TARNAME=\"sound-of-sorting\" -DPACKAGE_VERSION=\"0.6.5\" -DPACKAGE_STRING=\"sound-of-sorting\ 0.6.5\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"sound-of-sorting\" -DVERSION=\"0.6.5\" -DMSW_PERFORMANCECOUNTER=1 +DEPDIR = .deps +ECHO_C = +ECHO_N = -n +ECHO_T = +ETAGS = etags +EXEEXT = .exe +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LDFLAGS = +LIBOBJS = +LIBS = +LTLIBOBJS = +MAINT = # +MAKEINFO = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' makeinfo +MKDIR_P = /usr/bin/mkdir -p +OBJEXT = o +PACKAGE = sound-of-sorting +PACKAGE_BUGREPORT = +PACKAGE_NAME = sound-of-sorting +PACKAGE_STRING = sound-of-sorting 0.6.5 +PACKAGE_TARNAME = sound-of-sorting +PACKAGE_URL = +PACKAGE_VERSION = 0.6.5 +PATH_SEPARATOR = : +PKG_CONFIG = /mingw64/bin/pkg-config +PKG_CONFIG_LIBDIR = +PKG_CONFIG_PATH = /mingw64/lib/pkgconfig:/mingw64/share/pkgconfig +RANLIB = ranlib +SDL2_CONFIG = /mingw64/bin/pkg-config sdl2 +SDL2_FRAMEWORK = +SDL_CFLAGS = -IC:/msys64/mingw64/include/SDL2 -Dmain=SDL_main +SDL_LIBS = -lmingw32 -lSDL2main -lSDL2 -mwindows +SET_MAKE = +SHELL = /bin/sh +STRIP = +VERSION = 0.6.5 +WX_CFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_CFLAGS_ONLY = +WX_CONFIG_PATH = /mingw64/bin/wx-config +WX_CPPFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_CXXFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_CXXFLAGS_ONLY = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ +WX_LIBS = -L/mingw64/lib -Wl,--subsystem,windows -mwindows -lwx_mswu_core-3.2 -lwx_baseu-3.2 +WX_LIBS_STATIC = -LC:/msys64/mingw64/lib -pipe -Wl,--subsystem,windows -mwindows C:/msys64/mingw64/lib/libwx_mswu_adv-3.0.a C:/msys64/mingw64/lib/libwx_mswu_core-3.0.a C:/msys64/mingw64/lib/libwx_baseu-3.0.a -lwxregexu-3.0 -lwxexpat-3.0 -lwxtiff-3.0 -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 -lrpcrt4 -loleaut32 -lole32 -luuid -llzma -ljbig -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 -loleacc +WX_RESCOMP = windres --include-dir /mingw64/include/wx-3.2 --define __WIN32__ --define __GNUWIN32__ --define WX_CPU_AMD64 +WX_VERSION = 3.2.6 +WX_VERSION_MAJOR = 3 +WX_VERSION_MICRO = 6 +WX_VERSION_MINOR = 2 +abs_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master/src +abs_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master/src +abs_top_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master +abs_top_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master +ac_ct_CC = gcc +ac_ct_CXX = g++ +am__include = include +am__leading_dot = . +am__quote = +am__tar = $${TAR-tar} chof - "$$tardir" +am__untar = $${TAR-tar} xf - +bindir = ${exec_prefix}/bin +build = x86_64-w64-mingw32 +build_alias = x86_64-w64-mingw32 +build_cpu = x86_64 +build_os = mingw32 +build_vendor = w64 +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +host = x86_64-w64-mingw32 +host_alias = +host_cpu = x86_64 +host_os = mingw32 +host_vendor = w64 +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +prefix = /mingw64 +program_transform_name = s,x,x, +psdir = ${docdir} +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = ${prefix}/etc +target = x86_64-w64-mingw32 +target_alias = +target_cpu = x86_64 +target_os = mingw32 +target_vendor = w64 +top_build_prefix = ../ +top_builddir = .. +top_srcdir = .. +COMMON = SortArray.cpp SortArray.h \ + SortSound.cpp \ + SortAlgo.cpp SortAlgo.h \ + algorithms/grailsort.cpp \ + algorithms/pdqsort.cpp \ + algorithms/timsort.cpp \ + algorithms/wikisort.cpp + +sound_of_sorting_SOURCES = \ + WMain.cpp WMain.h \ + wxg/WMain_wxg.cpp wxg/WMain_wxg.h \ + wxg/WAbout_wxg.cpp wxg/WAbout_wxg.h \ + WSortView.cpp WSortView.h \ + wxClickText.cpp wxClickText.h \ + $(COMMON) + +sorting_test_SOURCES = \ + SortTest.cpp \ + $(COMMON) + +AM_CXXFLAGS = -W -Wall -O2 $(filter-out -g, -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ ) $(filter-out -Dmain=SDL_main, -IC:/msys64/mingw64/include/SDL2 -Dmain=SDL_main) +LDADD = $(am__append_1) -L/mingw64/lib -Wl,--subsystem,windows -mwindows -lwx_mswu_core-3.2 -lwx_baseu-3.2 -lmingw32 -lSDL2main -lSDL2 -mwindows +EXTRA_DIST = \ + resources.rc sos.ico sos.xpm \ + wxg/sos.wxg + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .log .o .obj .test .test$(EXEEXT) .trs +$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: # $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): # $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +algorithms/$(am__dirstamp): + @$(MKDIR_P) algorithms + @: > algorithms/$(am__dirstamp) +algorithms/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) algorithms/$(DEPDIR) + @: > algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/grailsort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/pdqsort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/timsort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/wikisort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) + +sorting-test$(EXEEXT): $(sorting_test_OBJECTS) $(sorting_test_DEPENDENCIES) $(EXTRA_sorting_test_DEPENDENCIES) + @rm -f sorting-test$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(sorting_test_OBJECTS) $(sorting_test_LDADD) $(LIBS) +wxg/$(am__dirstamp): + @$(MKDIR_P) wxg + @: > wxg/$(am__dirstamp) +wxg/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) wxg/$(DEPDIR) + @: > wxg/$(DEPDIR)/$(am__dirstamp) +wxg/WMain_wxg.$(OBJEXT): wxg/$(am__dirstamp) \ + wxg/$(DEPDIR)/$(am__dirstamp) +wxg/WAbout_wxg.$(OBJEXT): wxg/$(am__dirstamp) \ + wxg/$(DEPDIR)/$(am__dirstamp) + +sound-of-sorting$(EXEEXT): $(sound_of_sorting_OBJECTS) $(sound_of_sorting_DEPENDENCIES) $(EXTRA_sound_of_sorting_DEPENDENCIES) + @rm -f sound-of-sorting$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(sound_of_sorting_OBJECTS) $(sound_of_sorting_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f algorithms/*.$(OBJEXT) + -rm -f wxg/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +include ./$(DEPDIR)/SortAlgo.Po # am--include-marker +include ./$(DEPDIR)/SortArray.Po # am--include-marker +include ./$(DEPDIR)/SortSound.Po # am--include-marker +include ./$(DEPDIR)/SortTest.Po # am--include-marker +include ./$(DEPDIR)/WMain.Po # am--include-marker +include ./$(DEPDIR)/WSortView.Po # am--include-marker +include ./$(DEPDIR)/wxClickText.Po # am--include-marker +include algorithms/$(DEPDIR)/grailsort.Po # am--include-marker +include algorithms/$(DEPDIR)/pdqsort.Po # am--include-marker +include algorithms/$(DEPDIR)/timsort.Po # am--include-marker +include algorithms/$(DEPDIR)/wikisort.Po # am--include-marker +include wxg/$(DEPDIR)/WAbout_wxg.Po # am--include-marker +include wxg/$(DEPDIR)/WMain_wxg.Po # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cpp.o: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CXX)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: + $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CXX)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ +# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +sorting-test.log: sorting-test$(EXEEXT) + @p='sorting-test$(EXEEXT)'; \ + b='sorting-test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test$(EXEEXT).log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f algorithms/$(DEPDIR)/$(am__dirstamp) + -rm -f algorithms/$(am__dirstamp) + -rm -f wxg/$(DEPDIR)/$(am__dirstamp) + -rm -f wxg/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/SortAlgo.Po + -rm -f ./$(DEPDIR)/SortArray.Po + -rm -f ./$(DEPDIR)/SortSound.Po + -rm -f ./$(DEPDIR)/SortTest.Po + -rm -f ./$(DEPDIR)/WMain.Po + -rm -f ./$(DEPDIR)/WSortView.Po + -rm -f ./$(DEPDIR)/wxClickText.Po + -rm -f algorithms/$(DEPDIR)/grailsort.Po + -rm -f algorithms/$(DEPDIR)/pdqsort.Po + -rm -f algorithms/$(DEPDIR)/timsort.Po + -rm -f algorithms/$(DEPDIR)/wikisort.Po + -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po + -rm -f wxg/$(DEPDIR)/WMain_wxg.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/SortAlgo.Po + -rm -f ./$(DEPDIR)/SortArray.Po + -rm -f ./$(DEPDIR)/SortSound.Po + -rm -f ./$(DEPDIR)/SortTest.Po + -rm -f ./$(DEPDIR)/WMain.Po + -rm -f ./$(DEPDIR)/WSortView.Po + -rm -f ./$(DEPDIR)/wxClickText.Po + -rm -f algorithms/$(DEPDIR)/grailsort.Po + -rm -f algorithms/$(DEPDIR)/pdqsort.Po + -rm -f algorithms/$(DEPDIR)/timsort.Po + -rm -f algorithms/$(DEPDIR)/wikisort.Po + -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po + -rm -f wxg/$(DEPDIR)/WMain_wxg.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \ + check-am clean clean-binPROGRAMS clean-generic \ + clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + recheck tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS + +.PRECIOUS: Makefile + + +resources.o: resources.rc + $(WX_RESCOMP) $(srcdir)/resources.rc resources.o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/Makefile.am b/src/Makefile.am index 873bfcf3b..61fd09749 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,7 +27,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) +AM_CXXFLAGS = -W -Wall -O2 $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = if GOT_RESCOMP diff --git a/src/Makefile.in b/src/Makefile.in index 8d81830e6..26a74a894 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -548,7 +548,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) +AM_CXXFLAGS = -W -Wall -O2 $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = $(am__append_1) @WX_LIBS@ @SDL_LIBS@ EXTRA_DIST = \ resources.rc sos.ico sos.xpm \ From 1ba5cd09277097bd43c2580df3a30ce67ecd446b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 23:06:04 +0800 Subject: [PATCH 155/289] Delete src/Makefile Not needed --- src/Makefile | 1123 -------------------------------------------------- 1 file changed, 1123 deletions(-) delete mode 100644 src/Makefile diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 4f9342605..000000000 --- a/src/Makefile +++ /dev/null @@ -1,1123 +0,0 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. -# src/Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994-2021 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - -# $Id: Makefile.am 2 2007-01-05 14:04:27Z tb $ - - -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/sound-of-sorting -pkgincludedir = $(includedir)/sound-of-sorting -pkglibdir = $(libdir)/sound-of-sorting -pkglibexecdir = $(libexecdir)/sound-of-sorting -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = x86_64-w64-mingw32 -host_triplet = x86_64-w64-mingw32 -target_triplet = x86_64-w64-mingw32 -bin_PROGRAMS = sound-of-sorting$(EXEEXT) -noinst_PROGRAMS = sorting-test$(EXEEXT) -TESTS = sorting-test$(EXEEXT) -am__append_1 = resources.o -subdir = src -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__installdirs = "$(DESTDIR)$(bindir)" -PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) -am__dirstamp = $(am__leading_dot)dirstamp -am__objects_1 = SortArray.$(OBJEXT) SortSound.$(OBJEXT) \ - SortAlgo.$(OBJEXT) algorithms/grailsort.$(OBJEXT) \ - algorithms/pdqsort.$(OBJEXT) algorithms/timsort.$(OBJEXT) \ - algorithms/wikisort.$(OBJEXT) -am_sorting_test_OBJECTS = SortTest.$(OBJEXT) $(am__objects_1) -sorting_test_OBJECTS = $(am_sorting_test_OBJECTS) -sorting_test_LDADD = $(LDADD) -sorting_test_DEPENDENCIES = $(am__append_1) -am_sound_of_sorting_OBJECTS = WMain.$(OBJEXT) wxg/WMain_wxg.$(OBJEXT) \ - wxg/WAbout_wxg.$(OBJEXT) WSortView.$(OBJEXT) \ - wxClickText.$(OBJEXT) $(am__objects_1) -sound_of_sorting_OBJECTS = $(am_sound_of_sorting_OBJECTS) -sound_of_sorting_LDADD = $(LDADD) -sound_of_sorting_DEPENDENCIES = $(am__append_1) -AM_V_P = $(am__v_P_$(V)) -am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_$(V)) -am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_$(V)) -am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I. -depcomp = $(SHELL) $(top_srcdir)/acscripts/depcomp -am__maybe_remake_depfiles = depfiles -am__depfiles_remade = ./$(DEPDIR)/SortAlgo.Po ./$(DEPDIR)/SortArray.Po \ - ./$(DEPDIR)/SortSound.Po ./$(DEPDIR)/SortTest.Po \ - ./$(DEPDIR)/WMain.Po ./$(DEPDIR)/WSortView.Po \ - ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/grailsort.Po \ - algorithms/$(DEPDIR)/pdqsort.Po \ - algorithms/$(DEPDIR)/timsort.Po \ - algorithms/$(DEPDIR)/wikisort.Po wxg/$(DEPDIR)/WAbout_wxg.Po \ - wxg/$(DEPDIR)/WMain_wxg.Po -am__mv = mv -f -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -AM_V_CXX = $(am__v_CXX_$(V)) -am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY)) -am__v_CXX_0 = @echo " CXX " $@; -am__v_CXX_1 = -CXXLD = $(CXX) -CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ - -o $@ -AM_V_CXXLD = $(am__v_CXXLD_$(V)) -am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY)) -am__v_CXXLD_0 = @echo " CXXLD " $@; -am__v_CXXLD_1 = -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_$(V)) -am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_$(V)) -am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(sorting_test_SOURCES) $(sound_of_sorting_SOURCES) -DIST_SOURCES = $(sorting_test_SOURCES) $(sound_of_sorting_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -am__tty_colors_dummy = \ - mgn= red= grn= lgn= blu= brg= std=; \ - am__color_tests=no -am__tty_colors = { \ - $(am__tty_colors_dummy); \ - if test "X$(AM_COLOR_TESTS)" = Xno; then \ - am__color_tests=no; \ - elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ - am__color_tests=yes; \ - elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ - am__color_tests=yes; \ - fi; \ - if test $$am__color_tests = yes; then \ - red=''; \ - grn=''; \ - lgn=''; \ - blu=''; \ - mgn=''; \ - brg=''; \ - std=''; \ - fi; \ -} -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__recheck_rx = ^[ ]*:recheck:[ ]* -am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* -am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* -# A command that, given a newline-separated list of test names on the -# standard input, print the name of the tests that are to be re-run -# upon "make recheck". -am__list_recheck_tests = $(AWK) '{ \ - recheck = 1; \ - while ((rc = (getline line < ($$0 ".trs"))) != 0) \ - { \ - if (rc < 0) \ - { \ - if ((getline line2 < ($$0 ".log")) < 0) \ - recheck = 0; \ - break; \ - } \ - else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ - { \ - recheck = 0; \ - break; \ - } \ - else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ - { \ - break; \ - } \ - }; \ - if (recheck) \ - print $$0; \ - close ($$0 ".trs"); \ - close ($$0 ".log"); \ -}' -# A command that, given a newline-separated list of test names on the -# standard input, create the global log from their .trs and .log files. -am__create_global_log = $(AWK) ' \ -function fatal(msg) \ -{ \ - print "fatal: making $@: " msg | "cat >&2"; \ - exit 1; \ -} \ -function rst_section(header) \ -{ \ - print header; \ - len = length(header); \ - for (i = 1; i <= len; i = i + 1) \ - printf "="; \ - printf "\n\n"; \ -} \ -{ \ - copy_in_global_log = 1; \ - global_test_result = "RUN"; \ - while ((rc = (getline line < ($$0 ".trs"))) != 0) \ - { \ - if (rc < 0) \ - fatal("failed to read from " $$0 ".trs"); \ - if (line ~ /$(am__global_test_result_rx)/) \ - { \ - sub("$(am__global_test_result_rx)", "", line); \ - sub("[ ]*$$", "", line); \ - global_test_result = line; \ - } \ - else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ - copy_in_global_log = 0; \ - }; \ - if (copy_in_global_log) \ - { \ - rst_section(global_test_result ": " $$0); \ - while ((rc = (getline line < ($$0 ".log"))) != 0) \ - { \ - if (rc < 0) \ - fatal("failed to read from " $$0 ".log"); \ - print line; \ - }; \ - printf "\n"; \ - }; \ - close ($$0 ".trs"); \ - close ($$0 ".log"); \ -}' -# Restructured Text title. -am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } -# Solaris 10 'make', and several other traditional 'make' implementations, -# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it -# by disabling -e (using the XSI extension "set +e") if it's set. -am__sh_e_setup = case $$- in *e*) set +e;; esac -# Default flags passed to test drivers. -am__common_driver_flags = \ - --color-tests "$$am__color_tests" \ - --enable-hard-errors "$$am__enable_hard_errors" \ - --expect-failure "$$am__expect_failure" -# To be inserted before the command running the test. Creates the -# directory for the log if needed. Stores in $dir the directory -# containing $f, in $tst the test, in $log the log. Executes the -# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and -# passes TESTS_ENVIRONMENT. Set up options for the wrapper that -# will run the test scripts (or their associated LOG_COMPILER, if -# thy have one). -am__check_pre = \ -$(am__sh_e_setup); \ -$(am__vpath_adj_setup) $(am__vpath_adj) \ -$(am__tty_colors); \ -srcdir=$(srcdir); export srcdir; \ -case "$@" in \ - */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ - *) am__odir=.;; \ -esac; \ -test "x$$am__odir" = x"." || test -d "$$am__odir" \ - || $(MKDIR_P) "$$am__odir" || exit $$?; \ -if test -f "./$$f"; then dir=./; \ -elif test -f "$$f"; then dir=; \ -else dir="$(srcdir)/"; fi; \ -tst=$$dir$$f; log='$@'; \ -if test -n '$(DISABLE_HARD_ERRORS)'; then \ - am__enable_hard_errors=no; \ -else \ - am__enable_hard_errors=yes; \ -fi; \ -case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ - am__expect_failure=yes;; \ - *) \ - am__expect_failure=no;; \ -esac; \ -$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) -# A shell command to get the names of the tests scripts with any registered -# extension removed (i.e., equivalently, the names of the test logs, with -# the '.log' extension removed). The result is saved in the shell variable -# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, -# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", -# since that might cause problem with VPATH rewrites for suffix-less tests. -# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. -am__set_TESTS_bases = \ - bases='$(TEST_LOGS)'; \ - bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ - bases=`echo $$bases` -AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' -RECHECK_LOGS = $(TEST_LOGS) -AM_RECURSIVE_TARGETS = check recheck -TEST_SUITE_LOG = test-suite.log -TEST_EXTENSIONS = .exe .test -LOG_DRIVER = $(SHELL) $(top_srcdir)/acscripts/test-driver -LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) -am__set_b = \ - case '$@' in \ - */*) \ - case '$*' in \ - */*) b='$*';; \ - *) b=`echo '$@' | sed 's/\.log$$//'`; \ - esac;; \ - *) \ - b='$*';; \ - esac -am__test_logs1 = $(TESTS:=.log) -am__test_logs2 = $(am__test_logs1:.exe.log=.log) -TEST_LOGS = $(am__test_logs2:.test.log=.log) -TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/acscripts/test-driver -TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ - $(TEST_LOG_FLAGS) -am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/acscripts/depcomp \ - $(top_srcdir)/acscripts/test-driver -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' aclocal-1.16 -AMTAR = $${TAR-tar} -AM_DEFAULT_VERBOSITY = 1 -AUTOCONF = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoconf -AUTOHEADER = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' autoheader -AUTOMAKE = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' automake-1.16 -AWK = gawk -CC = gcc -CCDEPMODE = depmode=gcc3 -CFLAGS = -g -Wno-unused-local-typedefs -CPPFLAGS = -CSCOPE = cscope -CTAGS = ctags -CXX = g++ -CXXDEPMODE = depmode=gcc3 -CXXFLAGS = -O2 -Wno-unused-local-typedefs -CYGPATH_W = cygpath -w -DEFS = -DPACKAGE_NAME=\"sound-of-sorting\" -DPACKAGE_TARNAME=\"sound-of-sorting\" -DPACKAGE_VERSION=\"0.6.5\" -DPACKAGE_STRING=\"sound-of-sorting\ 0.6.5\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"sound-of-sorting\" -DVERSION=\"0.6.5\" -DMSW_PERFORMANCECOUNTER=1 -DEPDIR = .deps -ECHO_C = -ECHO_N = -n -ECHO_T = -ETAGS = etags -EXEEXT = .exe -INSTALL = /usr/bin/install -c -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = $(install_sh) -c -s -LDFLAGS = -LIBOBJS = -LIBS = -LTLIBOBJS = -MAINT = # -MAKEINFO = ${SHELL} '/c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/missing' makeinfo -MKDIR_P = /usr/bin/mkdir -p -OBJEXT = o -PACKAGE = sound-of-sorting -PACKAGE_BUGREPORT = -PACKAGE_NAME = sound-of-sorting -PACKAGE_STRING = sound-of-sorting 0.6.5 -PACKAGE_TARNAME = sound-of-sorting -PACKAGE_URL = -PACKAGE_VERSION = 0.6.5 -PATH_SEPARATOR = : -PKG_CONFIG = /mingw64/bin/pkg-config -PKG_CONFIG_LIBDIR = -PKG_CONFIG_PATH = /mingw64/lib/pkgconfig:/mingw64/share/pkgconfig -RANLIB = ranlib -SDL2_CONFIG = /mingw64/bin/pkg-config sdl2 -SDL2_FRAMEWORK = -SDL_CFLAGS = -IC:/msys64/mingw64/include/SDL2 -Dmain=SDL_main -SDL_LIBS = -lmingw32 -lSDL2main -lSDL2 -mwindows -SET_MAKE = -SHELL = /bin/sh -STRIP = -VERSION = 0.6.5 -WX_CFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_CFLAGS_ONLY = -WX_CONFIG_PATH = /mingw64/bin/wx-config -WX_CPPFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_CXXFLAGS = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_CXXFLAGS_ONLY = -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ -WX_LIBS = -L/mingw64/lib -Wl,--subsystem,windows -mwindows -lwx_mswu_core-3.2 -lwx_baseu-3.2 -WX_LIBS_STATIC = -LC:/msys64/mingw64/lib -pipe -Wl,--subsystem,windows -mwindows C:/msys64/mingw64/lib/libwx_mswu_adv-3.0.a C:/msys64/mingw64/lib/libwx_mswu_core-3.0.a C:/msys64/mingw64/lib/libwx_baseu-3.0.a -lwxregexu-3.0 -lwxexpat-3.0 -lwxtiff-3.0 -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 -lrpcrt4 -loleaut32 -lole32 -luuid -llzma -ljbig -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 -loleacc -WX_RESCOMP = windres --include-dir /mingw64/include/wx-3.2 --define __WIN32__ --define __GNUWIN32__ --define WX_CPU_AMD64 -WX_VERSION = 3.2.6 -WX_VERSION_MAJOR = 3 -WX_VERSION_MICRO = 6 -WX_VERSION_MINOR = 2 -abs_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master/src -abs_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master/src -abs_top_builddir = /c/Users/louwe/Desktop/sound-of-sorting-master -abs_top_srcdir = /c/Users/louwe/Desktop/sound-of-sorting-master -ac_ct_CC = gcc -ac_ct_CXX = g++ -am__include = include -am__leading_dot = . -am__quote = -am__tar = $${TAR-tar} chof - "$$tardir" -am__untar = $${TAR-tar} xf - -bindir = ${exec_prefix}/bin -build = x86_64-w64-mingw32 -build_alias = x86_64-w64-mingw32 -build_cpu = x86_64 -build_os = mingw32 -build_vendor = w64 -builddir = . -datadir = ${datarootdir} -datarootdir = ${prefix}/share -docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} -dvidir = ${docdir} -exec_prefix = ${prefix} -host = x86_64-w64-mingw32 -host_alias = -host_cpu = x86_64 -host_os = mingw32 -host_vendor = w64 -htmldir = ${docdir} -includedir = ${prefix}/include -infodir = ${datarootdir}/info -install_sh = ${SHELL} /c/Users/louwe/Desktop/sound-of-sorting-master/acscripts/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -localedir = ${datarootdir}/locale -localstatedir = ${prefix}/var -mandir = ${datarootdir}/man -mkdir_p = $(MKDIR_P) -oldincludedir = /usr/include -pdfdir = ${docdir} -prefix = /mingw64 -program_transform_name = s,x,x, -psdir = ${docdir} -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -srcdir = . -sysconfdir = ${prefix}/etc -target = x86_64-w64-mingw32 -target_alias = -target_cpu = x86_64 -target_os = mingw32 -target_vendor = w64 -top_build_prefix = ../ -top_builddir = .. -top_srcdir = .. -COMMON = SortArray.cpp SortArray.h \ - SortSound.cpp \ - SortAlgo.cpp SortAlgo.h \ - algorithms/grailsort.cpp \ - algorithms/pdqsort.cpp \ - algorithms/timsort.cpp \ - algorithms/wikisort.cpp - -sound_of_sorting_SOURCES = \ - WMain.cpp WMain.h \ - wxg/WMain_wxg.cpp wxg/WMain_wxg.h \ - wxg/WAbout_wxg.cpp wxg/WAbout_wxg.h \ - WSortView.cpp WSortView.h \ - wxClickText.cpp wxClickText.h \ - $(COMMON) - -sorting_test_SOURCES = \ - SortTest.cpp \ - $(COMMON) - -AM_CXXFLAGS = -W -Wall -O2 $(filter-out -g, -I/mingw64/lib/wx/include/msw-unicode-3.2 -I/mingw64/include/wx-3.2 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXMSW__ ) $(filter-out -Dmain=SDL_main, -IC:/msys64/mingw64/include/SDL2 -Dmain=SDL_main) -LDADD = $(am__append_1) -L/mingw64/lib -Wl,--subsystem,windows -mwindows -lwx_mswu_core-3.2 -lwx_baseu-3.2 -lmingw32 -lSDL2main -lSDL2 -mwindows -EXTRA_DIST = \ - resources.rc sos.ico sos.xpm \ - wxg/sos.wxg - -all: all-am - -.SUFFIXES: -.SUFFIXES: .cpp .log .o .obj .test .test$(EXEEXT) .trs -$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: # $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): # $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ - fi; \ - for p in $$list; do echo "$$p $$p"; done | \ - sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p \ - ; then echo "$$p"; echo "$$p"; else :; fi; \ - done | \ - sed -e 'p;s,.*/,,;n;h' \ - -e 's|.*|.|' \ - -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ - sed 'N;N;N;s,\n, ,g' | \ - $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ - files=`for p in $$list; do echo "$$p"; done | \ - sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' \ - `; \ - test -n "$$list" || exit 0; \ - echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(bindir)" && rm -f $$files - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -clean-noinstPROGRAMS: - -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) -algorithms/$(am__dirstamp): - @$(MKDIR_P) algorithms - @: > algorithms/$(am__dirstamp) -algorithms/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) algorithms/$(DEPDIR) - @: > algorithms/$(DEPDIR)/$(am__dirstamp) -algorithms/grailsort.$(OBJEXT): algorithms/$(am__dirstamp) \ - algorithms/$(DEPDIR)/$(am__dirstamp) -algorithms/pdqsort.$(OBJEXT): algorithms/$(am__dirstamp) \ - algorithms/$(DEPDIR)/$(am__dirstamp) -algorithms/timsort.$(OBJEXT): algorithms/$(am__dirstamp) \ - algorithms/$(DEPDIR)/$(am__dirstamp) -algorithms/wikisort.$(OBJEXT): algorithms/$(am__dirstamp) \ - algorithms/$(DEPDIR)/$(am__dirstamp) - -sorting-test$(EXEEXT): $(sorting_test_OBJECTS) $(sorting_test_DEPENDENCIES) $(EXTRA_sorting_test_DEPENDENCIES) - @rm -f sorting-test$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(sorting_test_OBJECTS) $(sorting_test_LDADD) $(LIBS) -wxg/$(am__dirstamp): - @$(MKDIR_P) wxg - @: > wxg/$(am__dirstamp) -wxg/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) wxg/$(DEPDIR) - @: > wxg/$(DEPDIR)/$(am__dirstamp) -wxg/WMain_wxg.$(OBJEXT): wxg/$(am__dirstamp) \ - wxg/$(DEPDIR)/$(am__dirstamp) -wxg/WAbout_wxg.$(OBJEXT): wxg/$(am__dirstamp) \ - wxg/$(DEPDIR)/$(am__dirstamp) - -sound-of-sorting$(EXEEXT): $(sound_of_sorting_OBJECTS) $(sound_of_sorting_DEPENDENCIES) $(EXTRA_sound_of_sorting_DEPENDENCIES) - @rm -f sound-of-sorting$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(sound_of_sorting_OBJECTS) $(sound_of_sorting_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -rm -f algorithms/*.$(OBJEXT) - -rm -f wxg/*.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -include ./$(DEPDIR)/SortAlgo.Po # am--include-marker -include ./$(DEPDIR)/SortArray.Po # am--include-marker -include ./$(DEPDIR)/SortSound.Po # am--include-marker -include ./$(DEPDIR)/SortTest.Po # am--include-marker -include ./$(DEPDIR)/WMain.Po # am--include-marker -include ./$(DEPDIR)/WSortView.Po # am--include-marker -include ./$(DEPDIR)/wxClickText.Po # am--include-marker -include algorithms/$(DEPDIR)/grailsort.Po # am--include-marker -include algorithms/$(DEPDIR)/pdqsort.Po # am--include-marker -include algorithms/$(DEPDIR)/timsort.Po # am--include-marker -include algorithms/$(DEPDIR)/wikisort.Po # am--include-marker -include wxg/$(DEPDIR)/WAbout_wxg.Po # am--include-marker -include wxg/$(DEPDIR)/WMain_wxg.Po # am--include-marker - -$(am__depfiles_remade): - @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ - -am--depfiles: $(am__depfiles_remade) - -.cpp.o: - $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ - $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ - $(am__mv) $$depbase.Tpo $$depbase.Po -# $(AM_V_CXX)source='$<' object='$@' libtool=no \ -# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ -# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ $< - -.cpp.obj: - $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ - $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ - $(am__mv) $$depbase.Tpo $$depbase.Po -# $(AM_V_CXX)source='$<' object='$@' libtool=no \ -# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \ -# $(AM_V_CXX_no)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -# Recover from deleted '.trs' file; this should ensure that -# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create -# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells -# to avoid problems with "make -n". -.log.trs: - rm -f $< $@ - $(MAKE) $(AM_MAKEFLAGS) $< - -# Leading 'am--fnord' is there to ensure the list of targets does not -# expand to empty, as could happen e.g. with make check TESTS=''. -am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) -am--force-recheck: - @: - -$(TEST_SUITE_LOG): $(TEST_LOGS) - @$(am__set_TESTS_bases); \ - am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ - redo_bases=`for i in $$bases; do \ - am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ - done`; \ - if test -n "$$redo_bases"; then \ - redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ - redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ - if $(am__make_dryrun); then :; else \ - rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ - fi; \ - fi; \ - if test -n "$$am__remaking_logs"; then \ - echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ - "recursion detected" >&2; \ - elif test -n "$$redo_logs"; then \ - am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ - fi; \ - if $(am__make_dryrun); then :; else \ - st=0; \ - errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ - for i in $$redo_bases; do \ - test -f $$i.trs && test -r $$i.trs \ - || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ - test -f $$i.log && test -r $$i.log \ - || { echo "$$errmsg $$i.log" >&2; st=1; }; \ - done; \ - test $$st -eq 0 || exit 1; \ - fi - @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ - ws='[ ]'; \ - results=`for b in $$bases; do echo $$b.trs; done`; \ - test -n "$$results" || results=/dev/null; \ - all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ - pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ - fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ - skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ - xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ - xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ - error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ - if test `expr $$fail + $$xpass + $$error` -eq 0; then \ - success=true; \ - else \ - success=false; \ - fi; \ - br='==================='; br=$$br$$br$$br$$br; \ - result_count () \ - { \ - if test x"$$1" = x"--maybe-color"; then \ - maybe_colorize=yes; \ - elif test x"$$1" = x"--no-color"; then \ - maybe_colorize=no; \ - else \ - echo "$@: invalid 'result_count' usage" >&2; exit 4; \ - fi; \ - shift; \ - desc=$$1 count=$$2; \ - if test $$maybe_colorize = yes && test $$count -gt 0; then \ - color_start=$$3 color_end=$$std; \ - else \ - color_start= color_end=; \ - fi; \ - echo "$${color_start}# $$desc $$count$${color_end}"; \ - }; \ - create_testsuite_report () \ - { \ - result_count $$1 "TOTAL:" $$all "$$brg"; \ - result_count $$1 "PASS: " $$pass "$$grn"; \ - result_count $$1 "SKIP: " $$skip "$$blu"; \ - result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ - result_count $$1 "FAIL: " $$fail "$$red"; \ - result_count $$1 "XPASS:" $$xpass "$$red"; \ - result_count $$1 "ERROR:" $$error "$$mgn"; \ - }; \ - { \ - echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ - $(am__rst_title); \ - create_testsuite_report --no-color; \ - echo; \ - echo ".. contents:: :depth: 2"; \ - echo; \ - for b in $$bases; do echo $$b; done \ - | $(am__create_global_log); \ - } >$(TEST_SUITE_LOG).tmp || exit 1; \ - mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ - if $$success; then \ - col="$$grn"; \ - else \ - col="$$red"; \ - test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ - fi; \ - echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ - echo "$${col}$$br$${std}"; \ - create_testsuite_report --maybe-color; \ - echo "$$col$$br$$std"; \ - if $$success; then :; else \ - echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ - if test -n "$(PACKAGE_BUGREPORT)"; then \ - echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ - fi; \ - echo "$$col$$br$$std"; \ - fi; \ - $$success || exit 1 - -check-TESTS: - @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list - @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - @set +e; $(am__set_TESTS_bases); \ - log_list=`for i in $$bases; do echo $$i.log; done`; \ - trs_list=`for i in $$bases; do echo $$i.trs; done`; \ - log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ - $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ - exit $$?; -recheck: all - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - @set +e; $(am__set_TESTS_bases); \ - bases=`for i in $$bases; do echo $$i; done \ - | $(am__list_recheck_tests)` || exit 1; \ - log_list=`for i in $$bases; do echo $$i.log; done`; \ - log_list=`echo $$log_list`; \ - $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ - am__force_recheck=am--force-recheck \ - TEST_LOGS="$$log_list"; \ - exit $$? -sorting-test.log: sorting-test$(EXEEXT) - @p='sorting-test$(EXEEXT)'; \ - b='sorting-test'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -.test.log: - @p='$<'; \ - $(am__set_b); \ - $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -.test$(EXEEXT).log: - @p='$<'; \ - $(am__set_b); \ - $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-TESTS -check: check-am -all-am: Makefile $(PROGRAMS) -installdirs: - for dir in "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) - -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) - -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -rm -f algorithms/$(DEPDIR)/$(am__dirstamp) - -rm -f algorithms/$(am__dirstamp) - -rm -f wxg/$(DEPDIR)/$(am__dirstamp) - -rm -f wxg/$(am__dirstamp) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \ - mostlyclean-am - -distclean: distclean-am - -rm -f ./$(DEPDIR)/SortAlgo.Po - -rm -f ./$(DEPDIR)/SortArray.Po - -rm -f ./$(DEPDIR)/SortSound.Po - -rm -f ./$(DEPDIR)/SortTest.Po - -rm -f ./$(DEPDIR)/WMain.Po - -rm -f ./$(DEPDIR)/WSortView.Po - -rm -f ./$(DEPDIR)/wxClickText.Po - -rm -f algorithms/$(DEPDIR)/grailsort.Po - -rm -f algorithms/$(DEPDIR)/pdqsort.Po - -rm -f algorithms/$(DEPDIR)/timsort.Po - -rm -f algorithms/$(DEPDIR)/wikisort.Po - -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po - -rm -f wxg/$(DEPDIR)/WMain_wxg.Po - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-binPROGRAMS - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/SortAlgo.Po - -rm -f ./$(DEPDIR)/SortArray.Po - -rm -f ./$(DEPDIR)/SortSound.Po - -rm -f ./$(DEPDIR)/SortTest.Po - -rm -f ./$(DEPDIR)/WMain.Po - -rm -f ./$(DEPDIR)/WSortView.Po - -rm -f ./$(DEPDIR)/wxClickText.Po - -rm -f algorithms/$(DEPDIR)/grailsort.Po - -rm -f algorithms/$(DEPDIR)/pdqsort.Po - -rm -f algorithms/$(DEPDIR)/timsort.Po - -rm -f algorithms/$(DEPDIR)/wikisort.Po - -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po - -rm -f wxg/$(DEPDIR)/WMain_wxg.Po - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS - -.MAKE: check-am install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \ - check-am clean clean-binPROGRAMS clean-generic \ - clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ - distclean-compile distclean-generic distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-binPROGRAMS install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ - recheck tags tags-am uninstall uninstall-am \ - uninstall-binPROGRAMS - -.PRECIOUS: Makefile - - -resources.o: resources.rc - $(WX_RESCOMP) $(srcdir)/resources.rc resources.o - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: From 3aab3b58cf9f5b87214eb213e7dd3c2c9d0d13fe Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 23:08:34 +0800 Subject: [PATCH 156/289] Update several files --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index abce69dd7..e235dfb04 100755 --- a/configure +++ b/configure @@ -2840,7 +2840,7 @@ if test "$CFLAGS" == ""; then CFLAGS="-g -Wno-unused-local-typedefs" fi if test "$CXXFLAGS" == ""; then - CXXFLAGS="-g -Wno-unused-local-typedefs" + CXXFLAGS="-O2 -Wno-unused-local-typedefs" fi # enable full optimization by configure switch diff --git a/configure.ac b/configure.ac index 360d8f243..f31ca354d 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ if test "$CFLAGS" == ""; then CFLAGS="-g -Wno-unused-local-typedefs" fi if test "$CXXFLAGS" == ""; then - CXXFLAGS="-g -Wno-unused-local-typedefs" + CXXFLAGS="-O2 -Wno-unused-local-typedefs" fi # enable full optimization by configure switch From 32a2ea4a09eb4e79997f63346f6b31815f40e56c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 23 Oct 2024 23:32:16 +0800 Subject: [PATCH 157/289] Simplified optimization flag Since configure.ac already has the -O2 flag, there is no need to add it to these files --- src/Makefile.am | 2 +- src/Makefile.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 61fd09749..730c4c727 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,7 +27,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall -O2 $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) +AM_CXXFLAGS = -W -Wall $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = if GOT_RESCOMP diff --git a/src/Makefile.in b/src/Makefile.in index 26a74a894..f75d918b7 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -548,7 +548,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall -O2 $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) +AM_CXXFLAGS = -W -Wall $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = $(am__append_1) @WX_LIBS@ @SDL_LIBS@ EXTRA_DIST = \ resources.rc sos.ico sos.xpm \ From d27236ca811e6ee979269b2d071bb9677289c08d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 03:31:05 +0800 Subject: [PATCH 158/289] Provided counted_rotate() method This is for sorting algorithms that use std::reverse(), such as Tim Sort --- src/SortArray.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/SortArray.h b/src/SortArray.h index d39e7f456..da0050f90 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -54,6 +54,7 @@ extern size_t m_swaps; // Custom counted swap function template +constexpr void counted_swap(T & a, T & b) { std::swap(a, b); ++m_swaps; @@ -61,6 +62,7 @@ void counted_swap(T & a, T & b) { // Custom counted iter_swap function template +constexpr void counted_iter_swap(Iterator a, Iterator b) { std::iter_swap(a, b); ++m_swaps; @@ -68,6 +70,7 @@ void counted_iter_swap(Iterator a, Iterator b) { // Custom counted swap_ranges function template +constexpr ForwardIt2 counted_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) { while (first1 != last1) { counted_iter_swap(first1, first2); @@ -78,6 +81,7 @@ ForwardIt2 counted_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 f } template +constexpr ForwardIt counted_rotate(ForwardIt first, ForwardIt middle, ForwardIt last) { if (first == middle) @@ -100,6 +104,25 @@ ForwardIt counted_rotate(ForwardIt first, ForwardIt middle, ForwardIt last) return write; } +template +constexpr +void counted_reverse(BidirIt first, BidirIt last) +{ + using iter_cat = typename std::iterator_traits::iterator_category; + if constexpr (std::is_base_of_v) + { + if (first == last) { return; } + for (--last; first < last; (void)++first, --last) + { counted_iter_swap(first, last); } + } + else + { + while (first != last && first != --last) + { counted_iter_swap(first++, last); } + } + +} + // custom struct for array items, which allows detailed counting of comparisons. class ArrayItem { From 8ec86315a4dca2f5da912da45c9445542471d0a9 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 03:31:42 +0800 Subject: [PATCH 159/289] Tim Sort will now use counted_rotate() --- src/algorithms/timsort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/timsort.cpp b/src/algorithms/timsort.cpp index 215a05cbb..eb7de6561 100644 --- a/src/algorithms/timsort.cpp +++ b/src/algorithms/timsort.cpp @@ -200,7 +200,7 @@ class TimSort while(runHi < hi && compare.lt(*runHi, *(runHi - 1))) { ++runHi; } - std::reverse(lo, runHi); + counted_reverse(lo, runHi); } else { // ascending while(runHi < hi && compare.ge(*runHi, *(runHi - 1))) { From f02d86754732379526a2921a129b0d2f6d10e4cf Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 04:22:48 +0800 Subject: [PATCH 160/289] Provided high-level implementation of sort_heap and make_heap --- src/SortArray.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/SortArray.h b/src/SortArray.h index da0050f90..9cc5c8ef5 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -120,7 +120,55 @@ void counted_reverse(BidirIt first, BidirIt last) while (first != last && first != --last) { counted_iter_swap(first++, last); } } - +} + +template > +void counted_make_heap(RandomIt first, RandomIt last, Compare comp = Compare()) +{ + if (last - first < 2) return; // Nothing to do for 0 or 1 element + + // The index of the last non-leaf node is (n / 2) - 1, where n = distance(first, last) + auto n = std::distance(first, last); + for (auto i = (n / 2) - 1; i >= 0; --i) + { + // Sift down the element at index i to restore heap property + sift_down(first, last, i, comp); + } +} + +template +void sift_down(RandomIt first, RandomIt last, std::size_t index, Compare comp) +{ + size_t n = std::distance(first, last); + size_t current = index; + + while (true) + { + size_t left_child = 2 * current + 1; + size_t right_child = 2 * current + 2; + size_t largest = current; + + if (left_child < n && comp(first[largest], first[left_child])) + { largest = left_child; } + + if (right_child < n && comp(first[largest], first[right_child])) + { largest = right_child; } + + if (largest == current) { break; } + counted_swap(first[current], first[largest]); + current = largest; + } +} + +template > +void counted_sort_heap(RandomIt first, RandomIt last, Compare comp = Compare()) +{ + while (last - first > 1) + { + counted_swap(*first, *(last - 1)); + sift_down(first, last - 1, 0, comp); + --last; + } } // custom struct for array items, which allows detailed counting of comparisons. From e7103d9903e79ef477926a05136eaaa3cd7da658 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 04:23:49 +0800 Subject: [PATCH 161/289] PDQ Sort will now use counted_make_heap and counted_sort_heap --- src/algorithms/pdqsort.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/pdqsort.cpp b/src/algorithms/pdqsort.cpp index f12eb368a..fe2a8825f 100644 --- a/src/algorithms/pdqsort.cpp +++ b/src/algorithms/pdqsort.cpp @@ -448,8 +448,8 @@ namespace pdqsort_detail { if (highly_unbalanced) { // If we had too many bad partitions, switch to heapsort to guarantee O(n log n). if (--bad_allowed == 0) { - std::make_heap(begin, end, comp); - std::sort_heap(begin, end, comp); + counted_make_heap(begin, end); + counted_sort_heap(begin, end); return; } From 0a09556c73558d49ce315abf49b807af5c3dc94b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 12:24:51 +0800 Subject: [PATCH 162/289] Changed counted_swap to counted_iter_swap --- src/SortArray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortArray.h b/src/SortArray.h index 9cc5c8ef5..d1064d0aa 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -165,7 +165,7 @@ void counted_sort_heap(RandomIt first, RandomIt last, Compare comp = Compare()) { while (last - first > 1) { - counted_swap(*first, *(last - 1)); + counted_iter_swap(first, last - 1); sift_down(first, last - 1, 0, comp); --last; } From 91164dd06ccf1bd0e632b5d11b7043b6e19be955 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 12:26:30 +0800 Subject: [PATCH 163/289] Add files via upload --- src/SortArray.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SortArray.h b/src/SortArray.h index d1064d0aa..7034d693d 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -125,13 +125,11 @@ void counted_reverse(BidirIt first, BidirIt last) template > void counted_make_heap(RandomIt first, RandomIt last, Compare comp = Compare()) { - if (last - first < 2) return; // Nothing to do for 0 or 1 element + if (last - first < 2) return; - // The index of the last non-leaf node is (n / 2) - 1, where n = distance(first, last) auto n = std::distance(first, last); for (auto i = (n / 2) - 1; i >= 0; --i) { - // Sift down the element at index i to restore heap property sift_down(first, last, i, comp); } } From 610b07aeacfb67e10022ed1c39fcbcca2780e2fa Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 13:46:19 +0800 Subject: [PATCH 164/289] Added Proportion Extend Merge Sort I also modified Binary Insertion Sort to take low and high bounds --- src/SortAlgo.cpp | 184 +++++++++++++++++++++++++++++++++++++++++++++-- src/SortAlgo.h | 1 + 2 files changed, 178 insertions(+), 7 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index ceaa78feb..d19158247 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -73,10 +73,12 @@ const struct AlgoEntry g_algolist[] = _("An in-place merge sort variant that interleaves 2 halves of the input array, and then uses Insertion Sort to sort the array.")}, { _("New Shuffle Merge Sort"), &NewShuffleMergeSort, UINT_MAX, 512, _("An improvement upon Weave Merge Sort, with faster weave time, and inserting now makes comparisons with a worst-case similar to Merge Sort.") }, - { _("Strand Sort"), &StrandSort, UINT_MAX, 512, - wxEmptyString }, { _("Andrey's In-Place Merge Sort"), &AndreyMergeSort, UINT_MAX, 512, wxEmptyString }, + { _("Proportion Extend Merge Sort"), &ProportionMergeSort, UINT_MAX, 512, + wxEmptyString }, + { _("Strand Sort"), &StrandSort, UINT_MAX, 512, + wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, _("Quick sort variant with left and right pointers.") }, { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, @@ -341,14 +343,14 @@ void BinaryInsertionSort2(SortArray& A) } } -void BinaryInsertionSort(SortArray& A) +void BinaryInsertSort(SortArray& A, size_t start, size_t end) { - for (size_t i = 1; i < A.size(); ++i) + for (size_t i = start; i < end; ++i) { value_type key = A[i]; A.mark(i); - size_t lo = 0, hi = i; + size_t lo = start, hi = i; while (lo < hi) { size_t mid = (lo + hi) / 2; if (key < A[mid]) @@ -357,8 +359,6 @@ void BinaryInsertionSort(SortArray& A) lo = mid + 1; } - // item has to go into position lo - size_t j = i; while (j > lo) { @@ -370,6 +370,11 @@ void BinaryInsertionSort(SortArray& A) } } +void BinaryInsertionSort(SortArray& A) +{ + BinaryInsertSort(A, 0, A.size()); +} + // **************************************************************************** // *** Merge Sort (out-of-place with sentinels) @@ -3120,6 +3125,7 @@ void NewShuffleMergeSort(SortArray& A) // **************************************************************************** // *** Andrey Astrelin's In-Place Merge Sort + void sortVector(SortArray& A, size_t a, size_t b) { while (b > 1) @@ -3251,3 +3257,167 @@ void AndreyMergeSort(SortArray& A) { msort(A, 0, A.size()); } + + +// **************************************************************************** +// *** Proportion Extend Merge Sort + +/* + MIT License + + Copyright (c) 2023 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void blockSwap(SortArray& A, size_t a, size_t b, size_t s) +{ + while (s-- > 0) + { + A.swap(a, b); + ++a; ++b; + } +} + +size_t partition(SortArray& A, size_t a, size_t b, size_t p) +{ + size_t i = a - 1, j = b; + while (true) + { + do { ++i; } while (i < j && A[i] < A[p]); + do { --j; } while (j >= i && A[j] > A[p]); + if (i < j) { A.swap(i, j); } + else { return i; } + } +} + +void mergeFW(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + size_t pLen = m - a, i = 0, j = m, k = a; + blockSwap(A, a, p, pLen); + while (i < pLen && j < b) + { + if (A[p + i] <= A[j]) { A.swap(k, p + i); ++k; ++i; } + else { A.swap(k, j); ++k; ++j; } + } + while (i < pLen) { A.swap(k, p + i); ++k; ++i; } +} + +void mergeBW(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + size_t pLen = b - m, j = m - 1, k = b - 1; + int i = pLen - 1; + blockSwap(A, m, p, pLen); + while (i >= 0 && j >= a) + { + if (A[p + i] >= A[j]) { A.swap(k, p + i); --k; --i; } + else { A.swap(k, j); --k; --j; } + } + while (i >= 0) { A.swap(k, p + i); --k; --i; } +} + +void smartMerge(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + if (m - a < b - m) { mergeFW(A, a, m, b, p); } + else { mergeBW(A, a, m, b, p); } +} + +void mergeTo(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + size_t i = a, j = m; + while (i < m && j < b) + { + if (A[i] <= A[j]) { A.swap(p, i); ++p; ++i; } + else { A.swap(p, j); ++p; ++j; } + } + while (i < m) { A.swap(p, i); ++p; ++i; } + while (j < b) { A.swap(p, j); ++p; ++j; } +} + +void pingPongMerge(SortArray& A, size_t a, size_t m1, size_t m, size_t m2, size_t b, size_t p) +{ + size_t p1 = p + m - a, pEnd = p + b - a; + mergeTo(A, a, m1, m, p); + mergeTo(A, m, m2, b, p1); + mergeTo(A, p, p1, pEnd, a); +} + +void mergeSort(SortArray& A, size_t a, size_t b, size_t p) +{ + const size_t min_insert = 8; + size_t n = b - a, j = n; + for (; (j + 3) / 4 >= min_insert; j = (j + 3) / 4) {} + for (size_t i = a; i < b; i += j) + { + BinaryInsertSort(A, i, std::min(b, i + j)); + } + for (size_t i; j < n; j *= 4) + { + for (i = a; i + 2 * j < b; i += 4 * j) + { + pingPongMerge(A, i, i + j, i + 2 * j, std::min(i + 3 * j, b), std::min(i + 4 * j, b), p); + + } + if (i + j < b) { mergeBW(A, i, i + j, b, p); } + } +} + +void smartMergeSort(SortArray& A, size_t a, size_t b, size_t p, size_t pb) +{ + if (b - a <= pb - p) { mergeSort(A, a, b, p); return; } + size_t m = (a + b) >> 1; + mergeSort(A, a, m, p); + mergeSort(A, m, b, p); + mergeFW(A, a, m, b, p); +} + +void peSort(SortArray& A, size_t a, size_t m, size_t b) +{ + size_t n = b - a; + const size_t min_insert = 8; + if (n < 4 * min_insert) { BinaryInsertSort(A, a, b); return; } + if (m - a <= n / 3) + { + size_t t = (n + 2) / 3; + smartMergeSort(A, m, b - t, b - t, b); + smartMerge(A, a, m, b - t, b - t); + m = b - t; + } + size_t m1 = (a + m) >> 1, m2 = partition(A, m, b, m1); + size_t i = m, j = m2; + while (i > m1) { --i; --j; A.swap(i, j); } + m = m2 - (m - m1); + if (m - m1 < b - m2) + { + mergeSort(A, m1, m, m2); + smartMerge(A, a, m1, m, m2); + peSort(A, m + 1, m2, b); + } + else + { + mergeSort(A, m2, b, m1); + smartMerge(A, m + 1, m2, b, m1); + peSort(A, a, m1, m); + } +} + +void ProportionMergeSort(SortArray& A) +{ + peSort(A, 0, 0, A.size()); +} diff --git a/src/SortAlgo.h b/src/SortAlgo.h index c0fc4095d..0dab66e44 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -67,6 +67,7 @@ void WeaveMergeSort(class SortArray& a); void StrandSort(class SortArray& a); void NewShuffleMergeSort(class SortArray& a); void AndreyMergeSort(class SortArray& a); +void ProportionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); From 012141fd55db653b632b9a411d60473111d764fb Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 20:06:28 +0800 Subject: [PATCH 165/289] Fixed Proportion Merge Sort going out of bounds --- src/SortAlgo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d19158247..6b91e545b 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -352,7 +352,7 @@ void BinaryInsertSort(SortArray& A, size_t start, size_t end) size_t lo = start, hi = i; while (lo < hi) { - size_t mid = (lo + hi) / 2; + size_t mid = lo + ((hi - lo) / 2); if (key < A[mid]) hi = mid; else @@ -3321,10 +3321,10 @@ void mergeFW(SortArray& A, size_t a, size_t m, size_t b, size_t p) void mergeBW(SortArray& A, size_t a, size_t m, size_t b, size_t p) { - size_t pLen = b - m, j = m - 1, k = b - 1; - int i = pLen - 1; + size_t pLen = b - m; + int i = static_cast(pLen - 1), j = m - 1, k = b - 1, z = a; blockSwap(A, m, p, pLen); - while (i >= 0 && j >= a) + while (i >= 0 && j >= z) { if (A[p + i] >= A[j]) { A.swap(k, p + i); --k; --i; } else { A.swap(k, j); --k; --j; } From 182307439b41aac5cbc703c92dbb1a1fc4045d5c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 20:09:49 +0800 Subject: [PATCH 166/289] Reverted Binary Insertion Sort formula --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 6b91e545b..ea4fe4868 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -352,7 +352,7 @@ void BinaryInsertSort(SortArray& A, size_t start, size_t end) size_t lo = start, hi = i; while (lo < hi) { - size_t mid = lo + ((hi - lo) / 2); + size_t mid = (lo + hi) / 2; if (key < A[mid]) hi = mid; else From 1272d40682759a10aac13951312471963748a68b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 20:56:24 +0800 Subject: [PATCH 167/289] Added Combined Odd-Even Sort This looks very, very similar to Bubble Sort, but of course the code still looks different. --- src/SortAlgo.cpp | 24 +++++++++++++++++++++++- src/SortAlgo.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index ea4fe4868..9606c4e16 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -101,7 +101,7 @@ const struct AlgoEntry g_algolist[] = { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, - _("This variant can detect if an array is sorted, if the array is sorted, the sorting process will stop.") }, + _("This variant terminates early if the array is already sorted.") }, { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, @@ -122,6 +122,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Odd-Even Sort"), &OddEvenSort, UINT_MAX, 1024, wxEmptyString }, + { _("Combined Odd-Even Sort"), &CombinedOddEvenSort, UINT_MAX, 1024, + _("This variant of Odd-Even Sort combines the odd and even phases into a single loop.") }, // older sequential implementation, which really makes little sense to do //{ _("Bitonic Sort"), &BitonicSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Batcher's Bitonic Sort"), &BitonicSortNetwork, UINT_MAX, UINT_MAX, @@ -1259,6 +1261,26 @@ void OddEvenSort(SortArray& A) } } +void CombinedOddEvenSort(SortArray& A) +{ + bool sorted = false; + size_t n = A.size(); + while (!sorted) + { + sorted = true; + for (size_t i = 0; i < n - 1; ++i) + { + if ((i % 2 == 0 && A[i] > A[i + 1]) || + (i % 2 == 1 && A[i] > A[i + 1])) + { + A.swap(i, i + 1); + sorted = false; + } + } + --n; + } +} + // **************************************************************************** // *** Shell Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 0dab66e44..5eb20016c 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -88,6 +88,7 @@ void CombSort(class SortArray& a); void GnomeSort(class SortArray& a); void OptimizedGnomeSort(class SortArray& a); void OddEvenSort(class SortArray& a); +void CombinedOddEvenSort(class SortArray& a); void CircleSort(class SortArray& a); void ShellSort(SortArray& a); From 39ab11386b6572b5b265efa66c08bdc0d3c3ae2d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 21:12:27 +0800 Subject: [PATCH 168/289] Optimized Combined Odd-Even Sort Oh please, don't point your fingers at me for this, it is not my fault that this looks like Bubble Sort now! LOL --- src/SortAlgo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 9606c4e16..c6936b074 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1270,8 +1270,7 @@ void CombinedOddEvenSort(SortArray& A) sorted = true; for (size_t i = 0; i < n - 1; ++i) { - if ((i % 2 == 0 && A[i] > A[i + 1]) || - (i % 2 == 1 && A[i] > A[i + 1])) + if (A[i] > A[i + 1]) { A.swap(i, i + 1); sorted = false; From 547d5f4772d9220b197c7f350dc62a4f55721325 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 24 Oct 2024 21:40:16 +0800 Subject: [PATCH 169/289] Added Targeted Bubble Sort Now this is a worthy addition! Instead of that weird addition, this variant of Bubble Sort is capable of dynamically adjusting its sorting boundaries depending on the input array. This can be particularly observed on Scrambled Head inputs! I can't believe I made this work! --- src/SortAlgo.cpp | 43 ++++++++++++++++++++++--------------------- src/SortAlgo.h | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index c6936b074..f0a3215a7 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -102,6 +102,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, _("This variant terminates early if the array is already sorted.") }, + { _("Targeted Bubble Sort"), &TargetedBubbleSort, UINT_MAX, 1024, + _("This variant of Bubble Sort is capable of adjusting the sorting boundaries based on the input array.") }, { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, @@ -122,8 +124,6 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Odd-Even Sort"), &OddEvenSort, UINT_MAX, 1024, wxEmptyString }, - { _("Combined Odd-Even Sort"), &CombinedOddEvenSort, UINT_MAX, 1024, - _("This variant of Odd-Even Sort combines the odd and even phases into a single loop.") }, // older sequential implementation, which really makes little sense to do //{ _("Bitonic Sort"), &BitonicSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Batcher's Bitonic Sort"), &BitonicSortNetwork, UINT_MAX, UINT_MAX, @@ -1062,6 +1062,26 @@ void OptimizedBubbleSort(SortArray& A) } } +void TargetedBubbleSort(SortArray& A) +{ + bool sorted = false; + size_t target = A.size(), lastSwapped = 0; + while (!sorted) + { + sorted = true; + for (size_t i = 0; i < target - 1; ++i) + { + if (A[i] > A[i + 1]) + { + A.swap(i, i + 1); + lastSwapped = i; + sorted = false; + } + } + target = lastSwapped + 1; + } +} + // **************************************************************************** // *** Cocktail Shaker Sort @@ -1261,25 +1281,6 @@ void OddEvenSort(SortArray& A) } } -void CombinedOddEvenSort(SortArray& A) -{ - bool sorted = false; - size_t n = A.size(); - while (!sorted) - { - sorted = true; - for (size_t i = 0; i < n - 1; ++i) - { - if (A[i] > A[i + 1]) - { - A.swap(i, i + 1); - sorted = false; - } - } - --n; - } -} - // **************************************************************************** // *** Shell Sort diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 5eb20016c..21e4d585c 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -88,7 +88,7 @@ void CombSort(class SortArray& a); void GnomeSort(class SortArray& a); void OptimizedGnomeSort(class SortArray& a); void OddEvenSort(class SortArray& a); -void CombinedOddEvenSort(class SortArray& a); +void TargetedBubbleSort(class SortArray& a); void CircleSort(class SortArray& a); void ShellSort(SortArray& a); From c714c444331b47bac9b3c8f2551c825bf5597b0d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 25 Oct 2024 00:51:45 +0800 Subject: [PATCH 170/289] Simplified Targeted Bubble Sort code --- src/SortAlgo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f0a3215a7..d826dd017 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1065,11 +1065,11 @@ void OptimizedBubbleSort(SortArray& A) void TargetedBubbleSort(SortArray& A) { bool sorted = false; - size_t target = A.size(), lastSwapped = 0; + size_t target = A.size() - 1, lastSwapped = 0; while (!sorted) { sorted = true; - for (size_t i = 0; i < target - 1; ++i) + for (size_t i = 0; i < target; ++i) { if (A[i] > A[i + 1]) { @@ -1078,7 +1078,7 @@ void TargetedBubbleSort(SortArray& A) sorted = false; } } - target = lastSwapped + 1; + target = lastSwapped; } } From ae1604677ada48627c16d973b2ca083274466f33 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 25 Oct 2024 03:58:58 +0800 Subject: [PATCH 171/289] Provided counted_partition() method This method is applicable for Quick Sort algorithms that may use std::partition --- src/SortArray.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/SortArray.h b/src/SortArray.h index 7034d693d..eb01edd4e 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -84,19 +84,15 @@ template constexpr ForwardIt counted_rotate(ForwardIt first, ForwardIt middle, ForwardIt last) { - if (first == middle) - return last; - - if (middle == last) - return first; + if (first == middle) { return last; } + if (middle == last) { return first; } ForwardIt write = first; ForwardIt next_read = first; for (ForwardIt read = middle; read != last; ++write, ++read) { - if (write == next_read) - next_read = read; + if (write == next_read) { next_read = read; } counted_iter_swap(write, read); } @@ -169,6 +165,24 @@ void counted_sort_heap(RandomIt first, RandomIt last, Compare comp = Compare()) } } +template +ForwardIt counted_partition(ForwardIt first, ForwardIt last, UnaryPred p) +{ + first = std::find_if_not(first, last, p); + if (first == last) { return first; } + + for (auto i = std::next(first); i != last; ++i) + { + if (p(*i)) + { + counted_iter_swap(i, first); + ++first; + } + } + + return first; +} + // custom struct for array items, which allows detailed counting of comparisons. class ArrayItem { From 2e5d1975d147a7fbc719ab884e7ca369b58fb114 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 25 Oct 2024 13:53:18 +0800 Subject: [PATCH 172/289] Added Adjacency Pancake Sort and second Gravity Sort For some clarification, I renamed the previous Gravity Sort to Bead Sort, and this is now named Gravity Sort. Yes they both have the same "idea", but the sorting logic, and therefore the visualization is very different. --- src/SortAlgo.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++++++- src/SortAlgo.h | 2 + 2 files changed, 227 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d826dd017..d322c0392 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -155,10 +155,14 @@ const struct AlgoEntry g_algolist[] = _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, { _("Grail Sort (external buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, _("A variant of Grail Sort that uses an external buffer for a potential speedup.") }, - { _("Bead Sort"), &GravitySort, UINT_MAX, UINT_MAX, - _("Also known as Gravity Sort. This is a non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, + { _("Bead Sort"), &BeadSort, UINT_MAX, UINT_MAX, + _("This is a non-comparison based sorting algorithm that uses the concept of stacked beads to sort the elements.") }, + { _("Gravity Sort"), &GravitySort, UINT_MAX, UINT_MAX, + _("A non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, + { _("Adjacency Pancake Sort"), &AdjacencyPancakeSort, UINT_MAX, UINT_MAX, + _("An improvement upon Pancake Sort, which performs only 5/3 N + O(1) flips.") }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, wxEmptyString }, { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, @@ -1963,7 +1967,7 @@ void PancakeSort(SortArray& A) } } -void GravitySort(SortArray& A) +void BeadSort(SortArray& A) { int max = A[0]; int len = A.size(); @@ -2000,6 +2004,220 @@ void GravitySort(SortArray& A) } } +/* + MIT License + + Copyright (c) 2020 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void GravitySort(SortArray& A) +{ + int n = A.size(); + int min = A[0], max = A[0]; + for (int i = 1; i < n; ++i) + { + int ele = A[i].get(); + if (ele < min) { min = ele; } + if (ele > max) { max = ele; } + } + std::vector x(n, 0); + std::vector y(max - min + 1, 0); + for (int i = 0; i < n; ++i) + { + int ele = A[i].get(); + x[i] = ele - min; + y[ele - min] = y[ele - min] + 1; + } + + int y_size = static_cast(y.size() - 1); + for (int i = y_size; i > 0; --i) + { + y[i - 1] = y[i - 1] += y[i]; + } + + for (int j = y_size; j >= 0; --j) + { + for (int i = 0; i < n; ++i) + { + int val = 0, val2 = 0; + if (i >= n - y[j]) { val = 1; } + if (x[i] >= j) { val2 = 1; } + int inc = val - val2, ele = A[i].get(); + A.set(i, ArrayItem(ele + inc)); + } + } +} + +/* + MIT License + + Copyright (c) 2024 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +void dualSwap(SortArray& A, std::vector& keys, int a, int b) +{ + size_t z = static_cast(a); + A[z].get(); + A.swap(z, static_cast(b)); + value_type temp = keys[a]; + keys[a] = keys[b]; + keys[b] = temp; +} + +void reversal(SortArray& A, std::vector& keys, int a, int b) +{ + while (b - a > 1) { --b; dualSwap(A, keys, a, b); ++a; } +} + +bool isAdjacent(std::vector& keys, int a, int b, int N) +{ + return (keys[a] + 1) % N == keys[b] || (keys[b] + 1) % N == keys[a]; +} + +int findAdjacent(std::vector& keys, int e, int a, int N) +{ + while (!isAdjacent(keys, a, e, N)) { ++a; } + return a; +} + +void AdjacencyPancakeSort(SortArray& A) +{ + int a = 0, N = static_cast(A.size()), b = N; + if (N == 2) + { + reverseArr(A, a, a + 1); + return; + } + std::vector keys(N); + + for (int j = a; j < b; ++j) + { + int c = 0; + for (int i = a; i < b; ++i) + { + if (i == j) { continue; } + if (A[i] < A[j] || (A[i] == A[j] && i < j)) { ++c; } + } + keys[j - a] = ArrayItem(c); + } + + while (true) + { + int i = a; + while (i < b - 1 && isAdjacent(keys, i, i + 1, N)) { ++i; } + if (i == b - 1) { break; } + if (i == a) + { + int j = findAdjacent(keys, a, a + 2, N); + if (!isAdjacent(keys, j - 1, j, N)) + { reversal(A, keys, a, j); } + else + { + int k = findAdjacent(keys, a, j + 1, N); + if (!isAdjacent(keys, k - 1, k, N)) + { reversal(A, keys, a, k); } + else + { + reversal(A, keys, a, j + 1); + reversal(A, keys, a, j); + reversal(A, keys, a, k + 1); + reversal(A, keys, a, a + k - j); + } + } + } + else + { + int j = findAdjacent(keys, a, i + 1, N); + if (!isAdjacent(keys, j - 1, j, N)) + { reversal(A, keys, a, j); } + else + { + int k = findAdjacent(keys, i, i + 2, N); + if (k + 1 < b && isAdjacent(keys, k + 1, k, N)) + { + reversal(A, keys, a, i + 1); + reversal(A, keys, a, k + 1); + } + else if (k + 1 < b && isAdjacent(keys, k - 1, k, N)) + { + reversal(A, keys, a, k + 1); + reversal(A, keys, a, a + k - i); + } + else + { + reversal(A, keys, a, k + 1); + reversal(A, keys, a, a + k - i); + if (j < k) + { + reversal(A, keys, a, k + 1); + reversal(A, keys, a, i + k - j + 1); + } + else + { + reversal(A, keys, a, j + 1); + reversal(A, keys, a, a + j - k); + } + } + } + } + } + + int i = a; + while (keys[i] != 0 && keys[i] != N - 1) { ++i; } + if (keys[i] == 0) + { + if (i == a) { return; } + reversal(A, keys, a, b); + i = b - 2 - (i - a); + } + else if (i == a) + { + reversal(A, keys, a, b); + return; + } + ++i; + reversal(A, keys, a, i); + reversal(A, keys, a, b); + reversal(A, keys, a, b - i); +} + // **************************************************************************** // *** Bitonic Sort @@ -3344,7 +3562,10 @@ void mergeFW(SortArray& A, size_t a, size_t m, size_t b, size_t p) void mergeBW(SortArray& A, size_t a, size_t m, size_t b, size_t p) { size_t pLen = b - m; - int i = static_cast(pLen - 1), j = m - 1, k = b - 1, z = a; + int i = static_cast(pLen - 1), + j = static_cast(m - 1), + k = static_cast(b - 1), + z = static_cast(a); blockSwap(A, m, p, pLen); while (i >= 0 && j >= z) { diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 21e4d585c..e429410fa 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -121,6 +121,8 @@ void BozoSort(class SortArray& a); void StoogeSort(class SortArray& a); void SlowSort(class SortArray& a); void PancakeSort(class SortArray& a); +void AdjacencyPancakeSort(class SortArray& a); +void BeadSort(class SortArray& a); void GravitySort(class SortArray& a); void CycleSort(class SortArray& a); From 7dd5ca9e29e4b8702aadb797d7a82f6da0ad490d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 25 Oct 2024 18:24:53 +0800 Subject: [PATCH 173/289] Fixed options panel collapsing bug This change fixes 2 issues with the options panel. 1. Fixed the options panel completely disappearing if the edge of it is double-clicked (where it can be resized) 2. The options panel now has a minimum size, meaning, it cannot be resized any lower than this minimum size, preventing it from disappearing completely if resized all the way to the right side of the screen. The options panel can now be "hidden" and resized to appear again! --- src/WMain.cpp | 8 ++++++++ src/WMain.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/WMain.cpp b/src/WMain.cpp index c87e1d50f..f846df5f5 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -47,6 +47,7 @@ WMain::WMain(wxWindow* parent) // resize right split window splitter_0->SetSashPosition(GetSize().x - 280); + splitter_0->SetMinimumPaneSize(1); // insert list of algorithms into wxListBox for (const AlgoEntry* ae = g_algolist; ae != g_algolist_end; ++ae) @@ -116,6 +117,7 @@ BEGIN_EVENT_TABLE(WMain, WMain_wxg) EVT_TOGGLEBUTTON(ID_SOUND_BUTTON, WMain::OnSoundButton) EVT_BUTTON(ID_RANDOM_BUTTON, WMain::OnRandomButton) EVT_BUTTON(wxID_ABOUT, WMain::OnAboutButton) + EVT_SPLITTER_DCLICK(wxID_ANY, WMain::OnDClick) EVT_COMMAND_SCROLL(ID_SPEED_SLIDER, WMain::OnSpeedSliderChange) EVT_COMMAND_SCROLL(ID_SOUND_SUSTAIN_SLIDER, WMain::OnSoundSustainSliderChange) @@ -163,6 +165,12 @@ bool WMain::RunAlgorithm() } } +void WMain::OnDClick(wxSplitterEvent& event) +{ + // Veto the event to prevent the default behavior + event.Veto(); +} + void WMain::AbortAlgorithm() { if (!m_thread) return; diff --git a/src/WMain.h b/src/WMain.h index f04e5e32e..fbf52f770 100644 --- a/src/WMain.h +++ b/src/WMain.h @@ -85,6 +85,7 @@ class WMain : public WMain_wxg virtual void OnArraySizeSliderChange(wxScrollEvent &event); virtual void OnAlgoList(wxCommandEvent &event); virtual void OnAlgoListDClick(wxCommandEvent &event); + virtual void OnDClick(wxSplitterEvent& event); virtual void OnRunFinished(wxCommandEvent&); DECLARE_EVENT_TABLE() From b8ba78dc75047eb2096b9b74328b1f84f6f2d88d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 25 Oct 2024 18:37:23 +0800 Subject: [PATCH 174/289] Simplified options panel double click event method --- src/WMain.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index f846df5f5..140e691a4 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -165,11 +165,7 @@ bool WMain::RunAlgorithm() } } -void WMain::OnDClick(wxSplitterEvent& event) -{ - // Veto the event to prevent the default behavior - event.Veto(); -} +void WMain::OnDClick(wxSplitterEvent& event) { event.Veto(); } void WMain::AbortAlgorithm() { From e8dadd34400c2d860b20e1374161c5c881bdb655 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 26 Oct 2024 10:13:49 +0800 Subject: [PATCH 175/289] Prepare files for Quick Library Sort --- src/Makefile.am | 1 + src/Makefile.in | 12 ++++++++++-- src/SortAlgo.cpp | 4 +++- src/SortAlgo.h | 2 ++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 730c4c727..96e5c59c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ COMMON = SortArray.cpp SortArray.h \ SortAlgo.cpp SortAlgo.h \ algorithms/grailsort.cpp \ algorithms/pdqsort.cpp \ + algorithms/quicklibrarysort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp diff --git a/src/Makefile.in b/src/Makefile.in index f75d918b7..0ca17943b 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -109,8 +109,9 @@ PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = SortArray.$(OBJEXT) SortSound.$(OBJEXT) \ SortAlgo.$(OBJEXT) algorithms/grailsort.$(OBJEXT) \ - algorithms/pdqsort.$(OBJEXT) algorithms/timsort.$(OBJEXT) \ - algorithms/wikisort.$(OBJEXT) + algorithms/pdqsort.$(OBJEXT) \ + algorithms/quicklibrarysort.$(OBJEXT) \ + algorithms/timsort.$(OBJEXT) algorithms/wikisort.$(OBJEXT) am_sorting_test_OBJECTS = SortTest.$(OBJEXT) $(am__objects_1) sorting_test_OBJECTS = $(am_sorting_test_OBJECTS) sorting_test_LDADD = $(LDADD) @@ -141,6 +142,7 @@ am__depfiles_remade = ./$(DEPDIR)/SortAlgo.Po ./$(DEPDIR)/SortArray.Po \ ./$(DEPDIR)/WMain.Po ./$(DEPDIR)/WSortView.Po \ ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/grailsort.Po \ algorithms/$(DEPDIR)/pdqsort.Po \ + algorithms/$(DEPDIR)/quicklibrarysort.Po \ algorithms/$(DEPDIR)/timsort.Po \ algorithms/$(DEPDIR)/wikisort.Po wxg/$(DEPDIR)/WAbout_wxg.Po \ wxg/$(DEPDIR)/WMain_wxg.Po @@ -533,6 +535,7 @@ COMMON = SortArray.cpp SortArray.h \ SortAlgo.cpp SortAlgo.h \ algorithms/grailsort.cpp \ algorithms/pdqsort.cpp \ + algorithms/quicklibrarysort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp @@ -642,6 +645,8 @@ algorithms/grailsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/pdqsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/quicklibrarysort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/timsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/wikisort.$(OBJEXT): algorithms/$(am__dirstamp) \ @@ -682,6 +687,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wxClickText.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/grailsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/pdqsort.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/quicklibrarysort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/timsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/wikisort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@wxg/$(DEPDIR)/WAbout_wxg.Po@am__quote@ # am--include-marker @@ -1016,6 +1022,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/wxClickText.Po -rm -f algorithms/$(DEPDIR)/grailsort.Po -rm -f algorithms/$(DEPDIR)/pdqsort.Po + -rm -f algorithms/$(DEPDIR)/quicklibrarysort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po @@ -1074,6 +1081,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/wxClickText.Po -rm -f algorithms/$(DEPDIR)/grailsort.Po -rm -f algorithms/$(DEPDIR)/pdqsort.Po + -rm -f algorithms/$(DEPDIR)/quicklibrarysort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d322c0392..d945ea5b9 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -98,6 +98,8 @@ const struct AlgoEntry g_algolist[] = "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, + { _("Quick Library Sort"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, + _("A Library Sort variant that uses Quick Sort partitioning.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, @@ -3663,4 +3665,4 @@ void peSort(SortArray& A, size_t a, size_t m, size_t b) void ProportionMergeSort(SortArray& A) { peSort(A, 0, 0, A.size()); -} +} \ No newline at end of file diff --git a/src/SortAlgo.h b/src/SortAlgo.h index e429410fa..5b8ea392b 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -58,6 +58,7 @@ void SandpaperSort(class SortArray& a); void DoubleSandpaperSort(class SortArray& a); void InsertionSort2(class SortArray& a); void BinaryInsertionSort(class SortArray& a); +void BinaryInsertSort(class SortArray& a, size_t start, size_t end); void MergeSort(class SortArray& a); void MergeSortIterative(class SortArray& a); @@ -79,6 +80,7 @@ void QuickSortLL(class SortArray& a); void QuickSortTernaryLR(class SortArray& a); void QuickSortTernaryLL(class SortArray& a); void QuickSortDualPivot(class SortArray& a); +void QuickLibrarySort(SortArray& a); void BubbleSort(class SortArray& a); void OptimizedBubbleSort(class SortArray& a); From 211c1f27dd35d090d537d111a88eadc65da9c971 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 26 Oct 2024 10:14:56 +0800 Subject: [PATCH 176/289] Added Quick Library Sort (Flan Sort) --- src/algorithms/quicklibrarysort.cpp | 414 ++++++++++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 src/algorithms/quicklibrarysort.cpp diff --git a/src/algorithms/quicklibrarysort.cpp b/src/algorithms/quicklibrarysort.cpp new file mode 100644 index 000000000..dcfd16c2b --- /dev/null +++ b/src/algorithms/quicklibrarysort.cpp @@ -0,0 +1,414 @@ +/* + * + MIT License + + Copyright (c) 2021-2024 aphitorite, edited by Flanlaina (a.k.a. Ayako-chan) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + * +*/ + +/** + ultimate sorting algorithm: + + unstable and probabilistic sorting algorithm performing an average of + n log n + ~4.4 n comparisons and O(n) moves (~12.1 n) in O(1) space + + makes the fewest comparisons among the sorts of its kind + achieves the ultimate goal of a n log n + O(n) comps in place O(n) moves sort + + implements a modified library sort where the original algorithm is proven to be O(n log n) + from http://www.cs.sunysb.edu/~bender/newpub/BenderFaMo06-librarysort.pdf + + @author aphitorite +*/ + +#include "../SortAlgo.h" +#include + +const int MIN_INSERT = 32; +const int G = 7; +const int R = 3; + +std::random_device rd; +std::mt19937 eng(rd()); + +void shiftBW(SortArray& A, int a, int m, int b) +{ + while (m > a) { --b; --m; A.swap(b, m); } +} + +int randGapSearch(SortArray& A, int a, int b, int val) +{ + int s = G + 1, randCnt = 0; + while (a < b) + { + int m = a + (((b - a) / s) / 2) * s; + int ele = A[m]; + if (val < ele) { b = m; } + else if (val > ele) { a = m + s; } + else if (randCnt++ < 1) + { + std::uniform_int_distribution<> distr(0, ((b - a) / s) - 1); + m = a + distr(eng) * s; + ele = A[m]; + if (val < ele) { b = m; } + else if (val > ele) { a = m + s; } + else { a = m; break; } + } + else { a = m; break; } + } + return a; +} + +int rightBinSearch(SortArray& A, int a, int b, int val, bool bw) +{ + int cmp = -1; + if (bw == true) { cmp = 1; } + while (a < b) + { + int m = a + (b - a) / 2; + int ele = A[m], result = 0; + if (val < ele) { result = -1; } + else if (val > ele) { result = 1; } + + if (result == cmp) { b = m; } + else { a = m + 1; } + } + return a; +} + +void insertTo(SortArray& A, int tmp, int a, int b) +{ + while (a > b) + { + size_t z = static_cast(a); + A.set(z, A[z - 1]); + --a; + } + size_t z = static_cast(b); + A.set(z, ArrayItem(tmp)); +} + +void binaryInsert(SortArray& A, int a, int b) +{ + for (int i = a + 1; i < b; ++i) + { + int ele = A[i]; + insertTo(A, ele, i, rightBinSearch(A, a, i, ele, false)); + } +} + +void retrieve(SortArray& A, int b, int p, int pEnd, int bsv, bool bw) +{ + int j = b - 1, m; + for (int k = pEnd - (G + 1); k > p + G; ) + { + m = rightBinSearch(A, k - G, k, bsv, bw) - 1; + k -= G + 1; + while (m >= k) + { + size_t x = static_cast(j), y = static_cast(m); + A.swap(x, y); + --j; --m; + } + } + m = rightBinSearch(A, p, p + G, bsv, bw) - 1; + while (m >= p) + { + size_t x = static_cast(j), y = static_cast(m); + A.swap(x, y); + --j; --m; + } +} + +void rescatter(SortArray & A, int i, int p, int pEnd, int bsv, bool bw) +{ + int j = i - 2 * (G + 1), m; + for (int k = pEnd - (G + 1); k > p + G; ) + { + m = rightBinSearch(A, k - G, k, bsv, bw) - 1; + k -= G + 1; + while (m >= k) + { + size_t x = static_cast(j), y = static_cast(m); + A.swap(x, y); + j -= G + 1; --m; + } + } + m = rightBinSearch(A, p, p + G, bsv, bw) - 1; + while (m >= p) + { + size_t x = static_cast(j), y = static_cast(m); + A.swap(x, y); + j -= G + 1; --m; + } +} + +void rebalance(SortArray& A, int a, int b, int p, int pEnd, int pb, int bsv, bool bw) +{ + retrieve(A, b, p, pEnd, bsv, bw); + int gCnt = (pb - p) / (G + 1); + int gapElems = (b - a) - gCnt + 1; + int baseCnt = gapElems / gCnt; + int extra = gapElems - gCnt * baseCnt; + for (int k = p + G;; k += G + 1) + { + int val = 0; + if (extra > 0) { val = 1; } + int iter = baseCnt + val; + --extra; + for (int j = 0; j < iter; ++j) + { + size_t x = static_cast(a), y = static_cast(k - G + j); + A.swap(x, y); + ++a; + } + if (k < pb - (G + 1)) + { + size_t x = static_cast(a), y = static_cast(k); + A.swap(x, y); + ++a; + } + else { break; } + } +} + +void librarySort(SortArray& A, int a, int b, int p, int pb, int bsv, bool bw) +{ + int len = b - a; + if (len <= MIN_INSERT) + { + size_t x = static_cast(a), y = static_cast(b); + binaryInsert(A, x, y); + return; + } + int s = len; + while (s > MIN_INSERT) { s = (s - 1) / R + 1; } + int i = a + s, j = a + R * s, pEnd = p + (s + 1) * (G + 1) + G; + binaryInsert(A, a, i); + for (int k = 0; k < s; ++k) + { + size_t x = static_cast(a + k); + size_t y = static_cast(p + k * (G + 1) + G); + A.swap(x, y); + } + + while (i < b) + { + if (i == j) + { + s = i - a; + int pEndNew = p + (s + 1) * (G + 1) + G; + if (pEndNew > pb) + { + rebalance(A, a, i, p, pEnd, pb, bsv, bw); + pEnd = pb; + j = a; + } + else + { + rescatter(A, pEndNew, p, pEnd, bsv, bw); + pEnd = pEndNew; + j = a + (j - a) * R; + } + } + int ele = A[i]; + int bLoc = randGapSearch(A, p + G, pEnd - (G + 1), ele); + int loc = rightBinSearch(A, bLoc - G, bLoc, bsv, bw); + if (loc == bLoc) + { + int rotP = -1; + do { bLoc += G + 1; } + while (bLoc < pEnd && (rotP = rightBinSearch(A, bLoc - G, bLoc, bsv, bw)) == bLoc); + if (bLoc == pb) { rebalance(A, a, i, p, pEnd, pb, bsv, bw); } + else if (bLoc == pEnd) + { + int rotS = G / 2 + 1; + shiftBW(A, loc - rotS, bLoc - (G + 1), bLoc - (G + 1) + rotS); + pEnd += G + 1; + } + else + { + int rotS = bLoc - std::max(rotP, bLoc - (G + 1) / 2); + shiftBW(A, loc - rotS, bLoc - rotS, bLoc); + } + } + else + { + size_t k = static_cast(i), l = static_cast(loc); + int ele = A[k]; + A.set(k, A[l]); + ++i; + insertTo(A, ele, loc, rightBinSearch(A, bLoc - G, loc, ele, false)); + } + } + retrieve(A, b, p, pEnd, bsv, bw); +} + +int medianOfThree(SortArray& A, int a, int m, int b) +{ + size_t d = static_cast(a); + size_t n = static_cast(m); + size_t c = static_cast(b); + if (A[n] > A[d]) + { + if (A[n] < A[c]) { return m; } + if (A[d] > A[c]) { return a; } + else { return b; } + } + else + { + if (A[n] > A[c]) { return m; } + if (A[d] < A[c]) { return a; } + else { return b; } + } +} + +int ninther(SortArray& A, int a, int b) +{ + int s = (b - a) / 9; + int a1 = medianOfThree(A, a, a + s, a + 2 * s); + int m1 = medianOfThree(A, a + 3 * s, a + 4 * s, a + 5 * s); + int b1 = medianOfThree(A, a + 6 * s, a + 7 * s, a + 8 * s); + return medianOfThree(A, a1, m1, b1); +} + +int medianOfThreeNinthers(SortArray& A, int a, int b) +{ + int s = (b - a) / 3; + int a1 = ninther(A, a, a + s); + int m1 = ninther(A, a + s, a + 2 * s); + int b1 = ninther(A, a + 2 * s, b); + return medianOfThree(A, a1, m1, b1); +} + +void quickLibrary(SortArray& A, int a, int b, int p, int pb, int minSize, int bsv, bool bw) +{ + if (b - a <= minSize) + { + librarySort(A, a, b, p, pb, bsv, bw); + return; + } + int piv = A[medianOfThreeNinthers(A, a, b)]; + int i = a - 1, j = b; + do + { + int val = A[0]; + do + { + ++i; + val = A[i]; + } + while (i < j && val < piv); + val = A[0]; + do + { + --j; + val = A[j]; + } + while (j >= i && val > piv); + if (i < j) + { + size_t x = static_cast(i), y = static_cast(j); + A.swap(x, y); + } + else { break; } + } + while (true); + quickLibrary(A, a, i, p, pb, minSize, bsv, bw); + quickLibrary(A, i, b, p, pb, minSize, bsv, bw); +} + +void QuickLibrarySort(SortArray& A) +{ + int length = static_cast(A.size()), a = 0, b = length; + while (b - a > MIN_INSERT) + { + int piv = A[medianOfThreeNinthers(A, a, b)]; + int i1 = a, i = a - 1, j = b, j1 = b; + for (;;) + { + ++i; + while (i < j) + { + int ele = A[i]; + if (ele == piv) + { + size_t x = static_cast(i1), y = static_cast(i); + A.swap(x, y); ++i1; + } + else if (ele > piv) { break; } + ++i; + } + --j; + while (j > i) + { + int ele = A[j]; + if (ele == piv) + { + --j1; + size_t x = static_cast(j1), y = static_cast(j); + A.swap(x, y); + } + else if (ele < piv) { break; } + --j; + } + if (i < j) + { + size_t x = static_cast(i), y = static_cast(j); + A.swap(x, y); + } + else + { + if (i1 == b) { return; } + else if (j < i) { ++j; } + while (i1 > a) + { + --i; --i1; + size_t x = static_cast(i), y = static_cast(i1); + A.swap(x, y); + } + while (j1 < b) + { + size_t x = static_cast(j), y = static_cast(j1); + A.swap(x, y); + ++j; ++j1; + } + break; + } + } + int left = i - a, right = b - j; + if (left <= right) + { + right -= (right + 1) % (G + 1) + (G + 1); + left = std::max(right / (G + 1) * R, MIN_INSERT); + quickLibrary(A, a, i, j, j + right, left, piv, false); + a = j; + } + else + { + left -= (left + 1) % (G + 1) + (G + 1); + right = std::max(left / (G + 1) * R, MIN_INSERT); + quickLibrary(A, j, b, a, a + left, right, piv, true); + b = i; + } + } + binaryInsert(A, a, b); +} \ No newline at end of file From 3e559b3c31c47dd2502335f332f0b67b91ebab28 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 26 Oct 2024 10:16:51 +0800 Subject: [PATCH 177/289] Update files From 35558d4c361b5ac2c477d57ad4805db1984103b5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 26 Oct 2024 10:28:46 +0800 Subject: [PATCH 178/289] Update quicklibrarysort.cpp --- src/algorithms/quicklibrarysort.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/quicklibrarysort.cpp b/src/algorithms/quicklibrarysort.cpp index dcfd16c2b..4bd9dc302 100644 --- a/src/algorithms/quicklibrarysort.cpp +++ b/src/algorithms/quicklibrarysort.cpp @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * +* */ /** @@ -411,4 +411,4 @@ void QuickLibrarySort(SortArray& A) } } binaryInsert(A, a, b); -} \ No newline at end of file +} From aa8f4eb701ff36e1c7b658f66e7ff7d3996fdcfc Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 26 Oct 2024 13:10:55 +0800 Subject: [PATCH 179/289] Added sounds during the sorting process I first prioritized and made sure that the sorting algorithm is fully working before adding sounds. Now it has sounds! --- src/algorithms/quicklibrarysort.cpp | 35 +++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/algorithms/quicklibrarysort.cpp b/src/algorithms/quicklibrarysort.cpp index 4bd9dc302..27e79af09 100644 --- a/src/algorithms/quicklibrarysort.cpp +++ b/src/algorithms/quicklibrarysort.cpp @@ -51,7 +51,7 @@ std::mt19937 eng(rd()); void shiftBW(SortArray& A, int a, int m, int b) { - while (m > a) { --b; --m; A.swap(b, m); } + while (m > a) { --b; --m; A[b].get(); A.swap(b, m); } } int randGapSearch(SortArray& A, int a, int b, int val) @@ -60,14 +60,14 @@ int randGapSearch(SortArray& A, int a, int b, int val) while (a < b) { int m = a + (((b - a) / s) / 2) * s; - int ele = A[m]; + int ele = A[m].get(); if (val < ele) { b = m; } else if (val > ele) { a = m + s; } else if (randCnt++ < 1) { std::uniform_int_distribution<> distr(0, ((b - a) / s) - 1); m = a + distr(eng) * s; - ele = A[m]; + ele = A[m].get(); if (val < ele) { b = m; } else if (val > ele) { a = m + s; } else { a = m; break; } @@ -84,7 +84,7 @@ int rightBinSearch(SortArray& A, int a, int b, int val, bool bw) while (a < b) { int m = a + (b - a) / 2; - int ele = A[m], result = 0; + int ele = A[m].get(), result = 0; if (val < ele) { result = -1; } else if (val > ele) { result = 1; } @@ -99,18 +99,20 @@ void insertTo(SortArray& A, int tmp, int a, int b) while (a > b) { size_t z = static_cast(a); + A[z].get(); A.set(z, A[z - 1]); --a; } size_t z = static_cast(b); A.set(z, ArrayItem(tmp)); + A[z].get(); } void binaryInsert(SortArray& A, int a, int b) { for (int i = a + 1; i < b; ++i) { - int ele = A[i]; + int ele = A[i].get(); insertTo(A, ele, i, rightBinSearch(A, a, i, ele, false)); } } @@ -125,6 +127,7 @@ void retrieve(SortArray& A, int b, int p, int pEnd, int bsv, bool bw) while (m >= k) { size_t x = static_cast(j), y = static_cast(m); + A[x].get(); A.swap(x, y); --j; --m; } @@ -133,6 +136,7 @@ void retrieve(SortArray& A, int b, int p, int pEnd, int bsv, bool bw) while (m >= p) { size_t x = static_cast(j), y = static_cast(m); + A[x].get(); A.swap(x, y); --j; --m; } @@ -148,6 +152,7 @@ void rescatter(SortArray & A, int i, int p, int pEnd, int bsv, bool bw) while (m >= k) { size_t x = static_cast(j), y = static_cast(m); + A[x].get(); A.swap(x, y); j -= G + 1; --m; } @@ -156,6 +161,7 @@ void rescatter(SortArray & A, int i, int p, int pEnd, int bsv, bool bw) while (m >= p) { size_t x = static_cast(j), y = static_cast(m); + A[x].get(); A.swap(x, y); j -= G + 1; --m; } @@ -177,12 +183,14 @@ void rebalance(SortArray& A, int a, int b, int p, int pEnd, int pb, int bsv, boo for (int j = 0; j < iter; ++j) { size_t x = static_cast(a), y = static_cast(k - G + j); + A[x].get(); A.swap(x, y); ++a; } if (k < pb - (G + 1)) { size_t x = static_cast(a), y = static_cast(k); + A[x].get(); A.swap(x, y); ++a; } @@ -207,6 +215,7 @@ void librarySort(SortArray& A, int a, int b, int p, int pb, int bsv, bool bw) { size_t x = static_cast(a + k); size_t y = static_cast(p + k * (G + 1) + G); + A[x].get(); A.swap(x, y); } @@ -229,7 +238,7 @@ void librarySort(SortArray& A, int a, int b, int p, int pb, int bsv, bool bw) j = a + (j - a) * R; } } - int ele = A[i]; + int ele = A[i].get(); int bLoc = randGapSearch(A, p + G, pEnd - (G + 1), ele); int loc = rightBinSearch(A, bLoc - G, bLoc, bsv, bw); if (loc == bLoc) @@ -253,7 +262,7 @@ void librarySort(SortArray& A, int a, int b, int p, int pb, int bsv, bool bw) else { size_t k = static_cast(i), l = static_cast(loc); - int ele = A[k]; + int ele = A[k].get(); A.set(k, A[l]); ++i; insertTo(A, ele, loc, rightBinSearch(A, bLoc - G, loc, ele, false)); @@ -314,14 +323,14 @@ void quickLibrary(SortArray& A, int a, int b, int p, int pb, int minSize, int bs do { ++i; - val = A[i]; + val = A[i].get(); } while (i < j && val < piv); val = A[0]; do { --j; - val = A[j]; + val = A[j].get(); } while (j >= i && val > piv); if (i < j) @@ -348,7 +357,7 @@ void QuickLibrarySort(SortArray& A) ++i; while (i < j) { - int ele = A[i]; + int ele = A[i].get(); if (ele == piv) { size_t x = static_cast(i1), y = static_cast(i); @@ -360,7 +369,7 @@ void QuickLibrarySort(SortArray& A) --j; while (j > i) { - int ele = A[j]; + int ele = A[j].get(); if (ele == piv) { --j1; @@ -383,11 +392,13 @@ void QuickLibrarySort(SortArray& A) { --i; --i1; size_t x = static_cast(i), y = static_cast(i1); + A[x].get(); A.swap(x, y); } while (j1 < b) { size_t x = static_cast(j), y = static_cast(j1); + A[x].get(); A.swap(x, y); ++j; ++j1; } @@ -411,4 +422,4 @@ void QuickLibrarySort(SortArray& A) } } binaryInsert(A, a, b); -} +} \ No newline at end of file From 7b95bd7878a18bf42a4ea772798ac11db067d124 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 26 Oct 2024 23:36:39 +0800 Subject: [PATCH 180/289] Minor code corrections on Quick Library Sort --- src/algorithms/quicklibrarysort.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/algorithms/quicklibrarysort.cpp b/src/algorithms/quicklibrarysort.cpp index 27e79af09..496ef865e 100644 --- a/src/algorithms/quicklibrarysort.cpp +++ b/src/algorithms/quicklibrarysort.cpp @@ -203,8 +203,7 @@ void librarySort(SortArray& A, int a, int b, int p, int pb, int bsv, bool bw) int len = b - a; if (len <= MIN_INSERT) { - size_t x = static_cast(a), y = static_cast(b); - binaryInsert(A, x, y); + binaryInsert(A, a, b); return; } int s = len; @@ -273,19 +272,16 @@ void librarySort(SortArray& A, int a, int b, int p, int pb, int bsv, bool bw) int medianOfThree(SortArray& A, int a, int m, int b) { - size_t d = static_cast(a); - size_t n = static_cast(m); - size_t c = static_cast(b); - if (A[n] > A[d]) + if (A[m] > A[a]) { - if (A[n] < A[c]) { return m; } - if (A[d] > A[c]) { return a; } + if (A[m] < A[b]) { return m; } + if (A[a] > A[b]) { return a; } else { return b; } } else { - if (A[n] > A[c]) { return m; } - if (A[d] < A[c]) { return a; } + if (A[m] > A[b]) { return m; } + if (A[a] < A[b]) { return a; } else { return b; } } } From 099aa20d341f42e816a945d97724446ce641024c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 01:42:01 +0800 Subject: [PATCH 181/289] Renamed Quick Library Sort to Flan Sort As per the request of the author, the second name is left inside the parenthesis --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index d945ea5b9..57017575d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -98,7 +98,7 @@ const struct AlgoEntry g_algolist[] = "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, - { _("Quick Library Sort"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, + { _("Flan Sort (Quick Library Sort)"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, _("A Library Sort variant that uses Quick Sort partitioning.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, From 3156b069cf9019c8ad93db0171e0583ffe5f2f29 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 01:46:48 +0800 Subject: [PATCH 182/289] Changed description of Flan Sort --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 57017575d..b631606ed 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -99,7 +99,7 @@ const struct AlgoEntry g_algolist[] = { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, { _("Flan Sort (Quick Library Sort)"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, - _("A Library Sort variant that uses Quick Sort partitioning.") }, + _("An in-place Library Sort variant that uses Quick Sort partitioning to make space.") }, { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, From 4bc064598250329a4b74deb7cd7a6f8e2f27ed30 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 02:14:04 +0800 Subject: [PATCH 183/289] Made some file renaming --- src/Makefile.am | 2 +- src/Makefile.in | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 96e5c59c3..ff88b4425 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,9 +5,9 @@ bin_PROGRAMS = sound-of-sorting COMMON = SortArray.cpp SortArray.h \ SortSound.cpp \ SortAlgo.cpp SortAlgo.h \ + algorithms/flansort.cpp \ algorithms/grailsort.cpp \ algorithms/pdqsort.cpp \ - algorithms/quicklibrarysort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp diff --git a/src/Makefile.in b/src/Makefile.in index 0ca17943b..7d665f5e3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -108,9 +108,8 @@ am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = SortArray.$(OBJEXT) SortSound.$(OBJEXT) \ - SortAlgo.$(OBJEXT) algorithms/grailsort.$(OBJEXT) \ - algorithms/pdqsort.$(OBJEXT) \ - algorithms/quicklibrarysort.$(OBJEXT) \ + SortAlgo.$(OBJEXT) algorithms/flansort.$(OBJEXT) \ + algorithms/grailsort.$(OBJEXT) algorithms/pdqsort.$(OBJEXT) \ algorithms/timsort.$(OBJEXT) algorithms/wikisort.$(OBJEXT) am_sorting_test_OBJECTS = SortTest.$(OBJEXT) $(am__objects_1) sorting_test_OBJECTS = $(am_sorting_test_OBJECTS) @@ -140,9 +139,9 @@ am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/SortAlgo.Po ./$(DEPDIR)/SortArray.Po \ ./$(DEPDIR)/SortSound.Po ./$(DEPDIR)/SortTest.Po \ ./$(DEPDIR)/WMain.Po ./$(DEPDIR)/WSortView.Po \ - ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/grailsort.Po \ + ./$(DEPDIR)/wxClickText.Po algorithms/$(DEPDIR)/flansort.Po \ + algorithms/$(DEPDIR)/grailsort.Po \ algorithms/$(DEPDIR)/pdqsort.Po \ - algorithms/$(DEPDIR)/quicklibrarysort.Po \ algorithms/$(DEPDIR)/timsort.Po \ algorithms/$(DEPDIR)/wikisort.Po wxg/$(DEPDIR)/WAbout_wxg.Po \ wxg/$(DEPDIR)/WMain_wxg.Po @@ -533,9 +532,9 @@ top_srcdir = @top_srcdir@ COMMON = SortArray.cpp SortArray.h \ SortSound.cpp \ SortAlgo.cpp SortAlgo.h \ + algorithms/flansort.cpp \ algorithms/grailsort.cpp \ algorithms/pdqsort.cpp \ - algorithms/quicklibrarysort.cpp \ algorithms/timsort.cpp \ algorithms/wikisort.cpp @@ -641,12 +640,12 @@ algorithms/$(am__dirstamp): algorithms/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) algorithms/$(DEPDIR) @: > algorithms/$(DEPDIR)/$(am__dirstamp) +algorithms/flansort.$(OBJEXT): algorithms/$(am__dirstamp) \ + algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/grailsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/pdqsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) -algorithms/quicklibrarysort.$(OBJEXT): algorithms/$(am__dirstamp) \ - algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/timsort.$(OBJEXT): algorithms/$(am__dirstamp) \ algorithms/$(DEPDIR)/$(am__dirstamp) algorithms/wikisort.$(OBJEXT): algorithms/$(am__dirstamp) \ @@ -685,9 +684,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WMain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WSortView.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wxClickText.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/flansort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/grailsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/pdqsort.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/quicklibrarysort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/timsort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@algorithms/$(DEPDIR)/wikisort.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@wxg/$(DEPDIR)/WAbout_wxg.Po@am__quote@ # am--include-marker @@ -1020,9 +1019,9 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/WMain.Po -rm -f ./$(DEPDIR)/WSortView.Po -rm -f ./$(DEPDIR)/wxClickText.Po + -rm -f algorithms/$(DEPDIR)/flansort.Po -rm -f algorithms/$(DEPDIR)/grailsort.Po -rm -f algorithms/$(DEPDIR)/pdqsort.Po - -rm -f algorithms/$(DEPDIR)/quicklibrarysort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po @@ -1079,9 +1078,9 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/WMain.Po -rm -f ./$(DEPDIR)/WSortView.Po -rm -f ./$(DEPDIR)/wxClickText.Po + -rm -f algorithms/$(DEPDIR)/flansort.Po -rm -f algorithms/$(DEPDIR)/grailsort.Po -rm -f algorithms/$(DEPDIR)/pdqsort.Po - -rm -f algorithms/$(DEPDIR)/quicklibrarysort.Po -rm -f algorithms/$(DEPDIR)/timsort.Po -rm -f algorithms/$(DEPDIR)/wikisort.Po -rm -f wxg/$(DEPDIR)/WAbout_wxg.Po From 966ea23358e07c72b956ec5caf83e04b11eb1dde Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 02:14:58 +0800 Subject: [PATCH 184/289] Rename quicklibrarysort.cpp to flansort.cpp To make it consistent with the Makefile --- src/algorithms/{quicklibrarysort.cpp => flansort.cpp} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/algorithms/{quicklibrarysort.cpp => flansort.cpp} (99%) diff --git a/src/algorithms/quicklibrarysort.cpp b/src/algorithms/flansort.cpp similarity index 99% rename from src/algorithms/quicklibrarysort.cpp rename to src/algorithms/flansort.cpp index 496ef865e..c863b3287 100644 --- a/src/algorithms/quicklibrarysort.cpp +++ b/src/algorithms/flansort.cpp @@ -418,4 +418,4 @@ void QuickLibrarySort(SortArray& A) } } binaryInsert(A, a, b); -} \ No newline at end of file +} From c387d2f82b5795b01cfc62c619529e2a15a58069 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 03:55:03 +0800 Subject: [PATCH 185/289] Added Optimized Pancake Sort --- src/SortAlgo.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++++++ src/SortAlgo.h | 1 + 2 files changed, 102 insertions(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index b631606ed..ca373bc4e 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -163,6 +163,8 @@ const struct AlgoEntry g_algolist[] = _("A non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, + { _("Optimized Pancake Sort"), &OptimizedPancakeSort, UINT_MAX, UINT_MAX, + _("An optimized variant of Pancake Sort that performs 1/2 as many flips.") }, { _("Adjacency Pancake Sort"), &AdjacencyPancakeSort, UINT_MAX, UINT_MAX, _("An improvement upon Pancake Sort, which performs only 5/3 N + O(1) flips.") }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, @@ -1969,6 +1971,105 @@ void PancakeSort(SortArray& A) } } + +// **************************************************************************** +// *** Optimized Pancake Sort +/* + The MIT License (MIT) + + Copyright (c) 2021-2023 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +void flip2(SortArray& A, size_t high) +{ + if (high > 0) { --high; } + size_t low = 0; + while (low < high) + { + A[low].get(); + A.swap(low, high); + ++low; --high; + } +} + + +bool mergeFlip(SortArray& A, size_t h1, size_t h2) +{ + if (h1 == 1 && h2 == 1) + { + if (A[0] > A[1]) { flip2(A, 2); } + return true; + } + size_t n = h1 + h2, m = n / 2; + if (h2 < h1) + { + if (h2 < 1) { return true; } + size_t i = 0, j = h2; + while (i < j) + { + size_t k = (i + j) / 2, loc = n - 1 - k; + A[loc].get(); + if (A[n - 1 - k - m] > A[loc]) { i = k + 1; } + else { j = k; } + } + flip2(A, n - m - i); + flip2(A, n - i); + if (mergeFlip(A, h2 - i, i + m - h2)) { flip2(A, m); } + flip2(A, n); + if (!mergeFlip(A, i, n - m - i)) { flip2(A, n - m); } + } + else + { + if (h1 < 1) { return false; } + size_t i = 0, j = h1; + while (i < j) + { + size_t k = (i + j) / 2; + A[k].get(); + if (A[k] < A[k + m]) { i = k + 1; } + else { j = k; } + } + flip2(A, i); + flip2(A, i + m); + if (mergeFlip(A, i + m - h1, h1 - i)) { flip2(A, m); } + flip2(A, n); + if (!mergeFlip(A, n - m - i, i)) { flip2(A, n - m); } + } + return true; +} + +void sortFlip(SortArray& A, size_t n) +{ + if (n < 2) { return; } + size_t h = n / 2; + sortFlip(A, h); + flip2(A, n); + sortFlip(A, n - h); + mergeFlip(A, n - h, h); +} + +void OptimizedPancakeSort(SortArray& A) +{ + sortFlip(A, A.size()); +} + void BeadSort(SortArray& A) { int max = A[0]; diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 5b8ea392b..73ec6a886 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -123,6 +123,7 @@ void BozoSort(class SortArray& a); void StoogeSort(class SortArray& a); void SlowSort(class SortArray& a); void PancakeSort(class SortArray& a); +void OptimizedPancakeSort(class SortArray& a); void AdjacencyPancakeSort(class SortArray& a); void BeadSort(class SortArray& a); void GravitySort(class SortArray& a); From ba58a557c184b1566ee4f4d303ada9f2443d0f61 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 10:09:19 +0800 Subject: [PATCH 186/289] Introduced live index watching and marking on Double Selection Sort This should allow Double Selection Sort to now have the same visuals as Selection Sort. --- src/SortAlgo.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index ca373bc4e..531279e2e 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -189,9 +189,11 @@ const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; void DoubleSelectionSort(SortArray& A) { size_t left = 0; - size_t right = A.size() - 1; - volatile size_t max_idx = 0; - volatile size_t low_idx = 0; + size_t right = A.size() - 1, n = right; + volatile ssize_t max_idx = 0; + volatile ssize_t low_idx = 0; + A.watch(&max_idx, 4); + A.watch(&low_idx, 5); while (left < right) { max_idx = right; @@ -210,10 +212,16 @@ void DoubleSelectionSort(SortArray& A) } } A.swap(left, low_idx); - if (max_idx == left) { max_idx = low_idx; } + ssize_t l = left; // This removes comparison warning + if (max_idx == l) { max_idx = low_idx; } A.swap(right, max_idx); + if (left > 0) { A.unmark(left - 1); } + if (right < n) { A.unmark(right + 1); } + A.mark(left); + A.mark(right); ++left; --right; } + A.unwatch_all(); } void SelectionSort(SortArray& A) @@ -1204,6 +1212,7 @@ void GnomeSort(SortArray& A) A.swap(i, i-1); if (i > 1) --i; } + } } From a221061bbfa741fa2eea3789b91cae547635f397 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 13:34:05 +0800 Subject: [PATCH 187/289] Updated Adjacency Pancake Sort due to new changes by the author --- src/SortAlgo.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 531279e2e..f9aa50b13 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -283,7 +283,8 @@ void SandpaperSort(SortArray& A) { for (size_t j = i + 1; j < n; ++j) { - if (A[i] > A[j]) { + if (A[i] > A[j]) + { A.swap(i, j); } } @@ -1212,7 +1213,6 @@ void GnomeSort(SortArray& A) A.swap(i, i-1); if (i > 1) --i; } - } } @@ -1949,7 +1949,7 @@ void flip(SortArray& A, size_t high) } } -size_t find_max(SortArray& A, size_t n) // Optimized find_max method, the original method performs the search in linear time +size_t find_max(SortArray& A, size_t n) // Optimized find_max method, searching the max element in n/2 time { size_t max = 0; for (size_t low = 1, hi = n; low <= hi; ++low, --hi) @@ -2287,24 +2287,22 @@ void AdjacencyPancakeSort(SortArray& A) reversal(A, keys, a, i + 1); reversal(A, keys, a, k + 1); } - else if (k + 1 < b && isAdjacent(keys, k - 1, k, N)) - { - reversal(A, keys, a, k + 1); - reversal(A, keys, a, a + k - i); - } else { reversal(A, keys, a, k + 1); reversal(A, keys, a, a + k - i); - if (j < k) - { - reversal(A, keys, a, k + 1); - reversal(A, keys, a, i + k - j + 1); - } - else + if (!isAdjacent(keys, k - 1, k, N)) { - reversal(A, keys, a, j + 1); - reversal(A, keys, a, a + j - k); + if (j < k) + { + reversal(A, keys, a, k + 1); + reversal(A, keys, a, i + k - j + 1); + } + else + { + reversal(A, keys, a, j + 1); + reversal(A, keys, a, a + j - k); + } } } } @@ -2327,7 +2325,7 @@ void AdjacencyPancakeSort(SortArray& A) ++i; reversal(A, keys, a, i); reversal(A, keys, a, b); - reversal(A, keys, a, b - i); + reversal(A, keys, a, b - (i - a)); } // **************************************************************************** From 478a1b42ecd433ef6471398193c38d75aee7c0cd Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 27 Oct 2024 19:09:30 +0800 Subject: [PATCH 188/289] Added Bell Curve array input type --- src/SortArray.cpp | 52 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 8844797f0..d2b8c9b02 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -133,6 +133,7 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Ribbon")); list.Add(_("Max Heapified")); list.Add(_("Flipped Min Heapified")); + list.Add(_("Bell Curve")); } void flippedminheapify(std::vector& m_array, int len, int root, int dist) @@ -166,6 +167,12 @@ void heapify(std::vector& m_array, int n, int i) } } +float gaussian(float x, float mean, float std_dev) +{ + float exponent = -((x - mean) * (x - mean)) / (2 * std_dev * std_dev); + return std::exp(exponent); +} + void SortArray::FillData(unsigned int schema, size_t arraysize) { if (arraysize == 0) arraysize = 1; @@ -206,7 +213,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= half + (half / 2)) - { ++it1; } + { + ++it1; + } } std::shuffle(it1, m_array.end(), g); break; @@ -218,7 +227,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= (m_array.size() / 4)) - { ++it; } + { + ++it; + } } std::shuffle(m_array.begin(), it, g); break; @@ -230,7 +241,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= (m_array.size() / 2) - 1) - { ++it2; } + { + ++it2; + } } std::shuffle(it2, m_array.end(), g); break; @@ -242,7 +255,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= (m_array.size() / 2) - 1) - { ++it3; } + { + ++it3; + } } std::shuffle(m_array.begin(), it3, g); break; @@ -254,7 +269,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= (m_array.size() / 4)) - { ++it4; } + { + ++it4; + } } std::shuffle(it4, m_array.end(), g); break; @@ -267,7 +284,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(i + 1); if (i <= half + (half / 2)) - { ++it5; } + { + ++it5; + } } std::shuffle(m_array.begin(), it5, g); break; @@ -562,8 +581,25 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) int n = m_array.size(); for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } std::shuffle(m_array.begin(), m_array.end(), g); - for (int i = n / 2; i >= 1; --i) - { flippedminheapify(m_array, n, i, n); } + for (int i = n / 2; i >= 1; --i) + { + flippedminheapify(m_array, n, i, n); + } + break; + } + case 24: // Bell Curve + { + int length = m_array.size(); + float mean = length / 2.0f; + float std_dev = length / 6.4f; + for (int i = 0; i < length; ++i) + { + float x = static_cast(i); + float gaussianValue = gaussian(x, mean, std_dev); + int item = static_cast(gaussianValue * 255.0f); + item = std::max(0, std::min(item, 255)); + m_array[i] = ArrayItem(item); + } break; } default: From 4ad479cdab65feae4346862622c5c7c642275d04 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 05:42:49 +0800 Subject: [PATCH 189/289] Added Buffer Partition Merge Sort Also added InsertSort(), an Insertion Sort method that takes low and high bounds so that it can be used on subarrays. Buffer Partition Merge Sort requires the variant of Insertion Sort where the second index variable (j) must be an int so that it is allowed to go below 0, therefore, InsertSort is now implemented this way. InsertionSort() will now call upon InsertSort(). --- src/SortAlgo.cpp | 300 ++++++++++++++++++++++++++++++++++++++++++++--- src/SortAlgo.h | 3 +- 2 files changed, 286 insertions(+), 17 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f9aa50b13..2a70b0566 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -56,7 +56,7 @@ const struct AlgoEntry g_algolist[] = _("Also known as Exchange Sort.") }, { _("Double Sandpaper Sort"), &DoubleSandpaperSort, UINT_MAX, UINT_MAX, _("A variant of Exchange Sort that sorts the array bidirectionally.") }, - { _("Insertion Sort"), &InsertionSort2, UINT_MAX, UINT_MAX, + { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, wxEmptyString }, @@ -77,6 +77,8 @@ const struct AlgoEntry g_algolist[] = wxEmptyString }, { _("Proportion Extend Merge Sort"), &ProportionMergeSort, UINT_MAX, 512, wxEmptyString }, + { _("Buffer Partition Merge Sort"), &BufferPartitionMergeSort, UINT_MAX, 512, + wxEmptyString }, { _("Strand Sort"), &StrandSort, UINT_MAX, 512, wxEmptyString }, { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, @@ -294,39 +296,46 @@ void SandpaperSort(SortArray& A) // **************************************************************************** // *** Insertion Sort -// swaps every time (keeps all values visible) -void InsertionSort(SortArray& A) +void InsertSort(SortArray& A, size_t start, size_t end) { - for (size_t i = 1; i < A.size(); ++i) + int begin = static_cast(start); + for (size_t i = start; i < end; ++i) { - value_type key = A[i]; A.mark(i); - - ssize_t j = i - 1; - while (j >= 0 && A[j] > key) + int j = i - 1; + value_type key = A[i]; + while (j >= begin && A[j] > key) { - A.swap(j, j+1); - j--; + A.set(j + 1, A[j]); + --j; } + int index = j + 1; + A.set(index, key); A.unmark(i); } } // with extra item on stack +void InsertionSort(SortArray& A) +{ + InsertSort(A, 0, A.size()); +} + +// swaps every time (keeps all values visible) void InsertionSort2(SortArray& A) { for (size_t i = 1; i < A.size(); ++i) { - A.mark(i); - size_t j = i; value_type key = A[i]; - while (j >= 1 && A[j - 1] > key) + A.mark(i); + + ssize_t j = i - 1; + while (j >= 0 && A[j] > key) { - A.set(j, A[j - 1]); - --j; + A.swap(j, j + 1); + j--; } - A.set(j, key); A.unmark(i); } @@ -3773,4 +3782,263 @@ void peSort(SortArray& A, size_t a, size_t m, size_t b) void ProportionMergeSort(SortArray& A) { peSort(A, 0, 0, A.size()); +} + +// **************************************************************************** +// *** Buffer Partition Merge Sort + +/* + * + MIT License + + Copyright (c) 2021 yuji, implemented by aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +* +*/ + +void shiftBW2(SortArray& A, int a, int m, int b) +{ + while (m > a) + { + --b; --m; + A.swap(static_cast(b), static_cast(m)); + } +} + +void inPlaceMerge(SortArray& A, int a, int m, int b) +{ + int i = a, j = m, k = 0; + while (i < j && j < b) + { + if (A[i] > A[j]) + { + k = j; ++k; + while (k < b && A[i] > A[k]) { ++k; } + rotate(A, static_cast(i), static_cast(j), static_cast(k)); + i += k - j; + j = k; + } + else { ++i; } + } +} + +void medianOfThree(SortArray& A, int a, int b) +{ + int m = a + (b - 1 - a) / 2; + if (A[a] > A[m]) { A.swap(static_cast(a), static_cast(m)); } + if (A[m] > A[b - 1]) + { + A.swap(static_cast(m), static_cast(b - 1)); + if (A[a] > A[m]) { return; } + } + A.swap(static_cast(a), static_cast(m)); +} + +void medianofMedians(SortArray& A, int a, int b, int s) +{ + int end = b, start = a, i, j; + bool ad = true; + while (end - start > 1) + { + j = start; + for (i = start; i + 2 * s <= end; i += s) + { + InsertSort(A, static_cast(i), static_cast(i + s)); + A.swap(static_cast(j), static_cast(i + s / 2)); + ++j; + } + if (i < end) + { + InsertSort(A, static_cast(i), static_cast(end)); + int val = 0; + if (ad) { val = 1; } + A.swap(static_cast(j), static_cast(i + (end - val - i) / 2)); + if ((end - i) % 2 == 0) { ad = !ad; } + ++j; + } + end = j; + } +} + +int partition(SortArray& A, int a, int b) +{ + int i = a, j = b; + while (true) + { + do { ++i; } + while (i < j && A[i] > A[a]); + do { --j; } + while (j >= i && A[j] < A[a]); + if (i < j) { A.swap(static_cast(i), static_cast(j)); } + else { return j; } + } +} + +int quickSelect(SortArray& A, int a, int b, int m) +{ + bool badPartition = false, mom = false; + int m1 = (m + b + 1) / 2; + while (true) + { + if (badPartition) + { + medianofMedians(A, a, b, 5); + mom = true; + } + else { medianOfThree(A, a, b); } + int p = partition(A, a, b); + A.swap(static_cast(a), static_cast(p)); + int l = std::max(1, p - a), r = std::max(1, b - (p + 1)); + badPartition = !mom && (l / r >= 16 || r / l >= 16); + if (p >= m && p < m1) { return p; } + else if (p < m) { a = p + 1; } + else { b = p; } + } +} + +void mergeVector(SortArray& A, int a, int m, int b, int p) +{ + int i = a, j = m; + while (i < m && j < b) + { + if (A[i] <= A[j]) + { + A.swap(static_cast(p), static_cast(i)); + ++p; ++i; + } + else + { + A.swap(static_cast(p), static_cast(j)); + ++p; ++j; + } + } + while (i < m) + { + A.swap(static_cast(p), static_cast(i)); + ++p; ++i; + } + while (j < b) + { + A.swap(static_cast(p), static_cast(j)); + ++p; ++j; + } +} + +int mergeFW2(SortArray& A, int p, int a, int m, int b) +{ + int i = a, j = m; + while (i < m && j < b) + { + if (A[i] <= A[j]) + { + A.swap(static_cast(p), static_cast(i)); + ++p; ++i; + } + else + { + A.swap(static_cast(p), static_cast(j)); + ++p; ++j; + } + } + if (i < m) { return i; } + else { return j; } +} + +int getMinLevel(int n) +{ + while (n >= 32) { n = (n + 3) / 4; } + return n; +} + +void mergeSort2(SortArray& A, int a, int b, int p) +{ + int len = b - a; + if (len < 2) { return; } + int i, pos, j = getMinLevel(len); + for (i = a; i + j <= b; i += j) + { + BinaryInsertSort(A, static_cast(i), static_cast(i + j)); + } + BinaryInsertSort(A, static_cast(i), static_cast(b)); + while (j < len) + { + pos = p; + for (i = a; i + 2 * j <= b; i += 2 * j, pos += 2 * j) + { mergeVector(A, i, i + j, i + 2 * j, pos); } + if (i + j < b) { mergeVector(A, i, i + j, b, pos); } + else + { + while (i < b) + { + A.swap(static_cast(i), static_cast(pos)); + ++i; ++pos; + } + } + j *= 2; + pos = a; + for (i = p; i + 2 * j <= p + len; i += 2 * j, pos += 2 * j) + { mergeVector(A, i, i + j, i + 2 * j, pos); } + if (i + j < p + len) { mergeVector(A, i, i + j, p + len, pos); } + else + { + while (i < p + len) + { + A.swap(static_cast(i), static_cast(pos)); + ++i; ++pos; + } + } + j *= 2; + } +} + +void sortArray(SortArray& A, int a, int b) +{ + int minLvl = static_cast(sqrt(b - a)); + int m = (a + b + 1) / 2; + mergeSort2(A, m, b, a); + while (m - a > minLvl) + { + int m1 = (a + m + 1) / 2; + m1 = quickSelect(A, a, m, m1); + mergeSort2(A, m1, m, a); + int bSize = m1 - a; + int m2 = std::min(m1 + bSize, b); + m1 = mergeFW2(A, a, m1, m, m2); + while (m1 < m) + { + shiftBW2(A, m1, m, m2); + m1 = m2 - (m - m1); + a = m1 - bSize; + m = m2; + if (m == b) { break; } + m2 = std::min(m2 + bSize, b); + m1 = mergeFW2(A, a, m1, m, m2); + } + m = m1; + a = m1 - bSize; + } + BinaryInsertSort(A, static_cast(a), static_cast(m)); + inPlaceMerge(A, a, m, b); +} + +void BufferPartitionMergeSort(SortArray& A) +{ + sortArray(A, 0, A.size()); } \ No newline at end of file diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 73ec6a886..ceb7e067e 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -56,7 +56,7 @@ void SelectionSort(class SortArray& a); void DoubleSelectionSort(class SortArray& a); void SandpaperSort(class SortArray& a); void DoubleSandpaperSort(class SortArray& a); -void InsertionSort2(class SortArray& a); +void InsertionSort(class SortArray& a); void BinaryInsertionSort(class SortArray& a); void BinaryInsertSort(class SortArray& a, size_t start, size_t end); @@ -69,6 +69,7 @@ void StrandSort(class SortArray& a); void NewShuffleMergeSort(class SortArray& a); void AndreyMergeSort(class SortArray& a); void ProportionMergeSort(class SortArray& a); +void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); From 20dffd3584ff423b129511a95d28a425651cac6b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 11:15:58 +0800 Subject: [PATCH 190/289] Compressed Scrambled Tail and Head array inputs The 6 input types (25, 50, 75, Head and Tail) has now been compressed into just 2 array input types named Scrambled Tail and Head, but with a twist! Each reset on Scrambled Tail and Head cycles through 25%, 50%, and 75% Shuffled, so the user still has the "choice" to choose the percentage of shuffled data that they want. --- src/SortArray.cpp | 176 ++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 84 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index d2b8c9b02..648babd33 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -39,6 +39,9 @@ size_t g_access_count = 0; size_t m_swaps = 0; +static int scrambled_tail_intensity = 1; +static int scrambled_head_intensity = 1; + void ArrayItem::OnAccess(const ArrayItem& a) { SoundAccess(a.get_direct()); @@ -113,12 +116,8 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Ascending")); list.Add(_("Descending")); list.Add(_("Near Sorted")); - list.Add(_("25% Shuffled (Tail)")); - list.Add(_("25% Shuffled (Head)")); - list.Add(_("50% Shuffled (Tail)")); - list.Add(_("50% Shuffled (Head)")); - list.Add(_("75% Shuffled (Tail)")); - list.Add(_("75% Shuffled (Head)")); + list.Add(_("Scrambled Tail")); + list.Add(_("Scrambled Head")); list.Add(_("Shuffled Cubic")); list.Add(_("Shuffled Quintic")); list.Add(_("Shuffled n-2 Equal")); @@ -205,93 +204,102 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) m_array[m_array.size() - 1] = temp1; break; } - case 4: // 25% Shuffled + case 4: // Scrambled Tail { std::vector::iterator it1 = m_array.begin(); - size_t half = m_array.size() / 2; - for (size_t i = 0; i < m_array.size(); ++i) + if (scrambled_tail_intensity > 3) { scrambled_tail_intensity = 1; } + switch (scrambled_tail_intensity) { - m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) + case 1: { - ++it1; + size_t half = m_array.size() / 2; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= half + (half / 2)) + { + ++it1; + } + } + break; } - } - std::shuffle(it1, m_array.end(), g); - break; - } - case 5: // 25% Sorted, Head - { - std::vector::iterator it = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) + case 2: { - ++it; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { + ++it1; + } + } + break; } - } - std::shuffle(m_array.begin(), it, g); - break; - } - case 6: // 50% Sorted - { - std::vector::iterator it2 = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) + case 3: { - ++it2; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4)) + { + ++it1; + } + } } } - std::shuffle(it2, m_array.end(), g); + ++scrambled_tail_intensity; + std::shuffle(it1, m_array.end(), g); break; } - case 7: // 50% Sorted, Head + case 5: // Scrambled Head { - std::vector::iterator it3 = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) + std::vector::iterator it = m_array.begin(); + if (scrambled_head_intensity > 3) { scrambled_head_intensity = 1; } + switch (scrambled_head_intensity) { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) + case 1: { - ++it3; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 4)) + { + ++it; + } + } + break; } - } - std::shuffle(m_array.begin(), it3, g); - break; - } - case 8: // 75% Shuffled - { - std::vector::iterator it4 = m_array.begin(); - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) + case 2: { - ++it4; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= (m_array.size() / 2) - 1) + { + ++it; + } + } + break; } - } - std::shuffle(it4, m_array.end(), g); - break; - } - case 9: // 75% Shuffled, Head - { - std::vector::iterator it5 = m_array.begin(); - size_t half = m_array.size() / 2; - for (size_t i = 0; i < m_array.size(); ++i) - { - m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) + case 3: { - ++it5; + size_t half = m_array.size() / 2; + for (size_t i = 0; i < m_array.size(); ++i) + { + m_array[i] = ArrayItem(i + 1); + if (i <= half + (half / 2)) + { + ++it; + } + } + break; } } - std::shuffle(m_array.begin(), it5, g); + ++scrambled_head_intensity; + std::shuffle(m_array.begin(), it, g); break; } - case 10: // Cubic skew of [1,n] + case 6: // Cubic skew of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { @@ -308,7 +316,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); break; } - case 11: // Quintic skew of [1,n] + case 7: // Quintic skew of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { @@ -325,7 +333,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); break; } - case 12: // shuffled n-2 equal values in [1,n] + case 8: // shuffled n-2 equal values in [1,n] { m_array[0] = ArrayItem(1); for (size_t i = 1; i < m_array.size() - 1; ++i) { m_array[i] = ArrayItem(arraysize / 2 + 1); } @@ -333,7 +341,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); break; } - case 13: // Pipe organ (1, 1, 2, 2, 1, 1) + case 9: // Pipe organ (1, 1, 2, 2, 1, 1) { size_t n = m_array.size(); if (n % 2 == 0) @@ -364,7 +372,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 14: // Mirrored organ (3, 2, 1, 1, 2, 3) + case 10: // Mirrored organ (3, 2, 1, 1, 2, 3) { size_t n = m_array.size(); if (n % 2 == 0) @@ -396,7 +404,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 15: // Wave + case 11: // Wave { double n = double(m_array.size()); double pi = 3.14159265358979323846; @@ -409,7 +417,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 16: // Sawtooth + case 12: // Sawtooth { size_t n = m_array.size(), teeth; if (n % 5 == 0) { teeth = 5; } @@ -437,7 +445,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 17: // Reverse Sawtooth + case 13: // Reverse Sawtooth { size_t n = m_array.size(), teeth; if (n % 5 == 0) { teeth = 5; } @@ -465,7 +473,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 18: // Many Similar + case 14: // Many Similar { size_t group_count = 0, size = m_array.size(); if (size % 10 == 0) { group_count = 10; } @@ -497,7 +505,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) std::shuffle(m_array.begin(), m_array.end(), g); break; } - case 19: // Quicksort Killer + case 15: // Quicksort Killer { int currentLen = m_array.size(); for (int i = 0; i < currentLen; ++i) @@ -512,7 +520,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 20: // Spike + case 16: // Spike { size_t n = m_array.size(); int spike, val = 1; @@ -556,7 +564,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 21: // Ribbon + case 17: // Ribbon { int min = 1; int max = m_array.size(); @@ -568,7 +576,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 22: // Max Heapified + case 18: // Max Heapified { int n = m_array.size(); for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } @@ -576,7 +584,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (int i = n / 2 - 1; i >= 0; --i) { heapify(m_array, n, i); } break; } - case 23: // Flipped Min Heapified + case 19: // Flipped Min Heapified { int n = m_array.size(); for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } @@ -587,7 +595,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 24: // Bell Curve + case 20: // Bell Curve { int length = m_array.size(); float mean = length / 2.0f; From 2d7dc8d1eb09fb6d069e90721d95e1d3838b1ad5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 11:29:40 +0800 Subject: [PATCH 191/289] Minor correction on Scrambled Tail --- src/SortArray.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 648babd33..2198ef3c1 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -245,6 +245,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) ++it1; } } + break; } } ++scrambled_tail_intensity; From a5690ecc8de17ee11a0dbf3b4618736f628a1b0b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 11:46:53 +0800 Subject: [PATCH 192/289] Introduced a safeguard case for Scrambled Tail and Head This is incase the value responsible for cycling between shuffled data percentages has been somehow modified outside of the program. --- src/SortArray.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 2198ef3c1..5bf257e64 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -207,7 +207,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 4: // Scrambled Tail { std::vector::iterator it1 = m_array.begin(); - if (scrambled_tail_intensity > 3) { scrambled_tail_intensity = 1; } + if (scrambled_tail_intensity > 3 || scrambled_tail_intensity <= 0) { scrambled_tail_intensity = 1; } switch (scrambled_tail_intensity) { case 1: @@ -255,7 +255,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 5: // Scrambled Head { std::vector::iterator it = m_array.begin(); - if (scrambled_head_intensity > 3) { scrambled_head_intensity = 1; } + if (scrambled_head_intensity > 3 || scrambled_head_intensity <= 0) { scrambled_head_intensity = 1; } switch (scrambled_head_intensity) { case 1: From b42fe5bb8bcd863f22e77a9e93af217ebbf7804a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 11:53:14 +0800 Subject: [PATCH 193/289] Shortened Scrambled Tail and Head code From 64c482cb5f7b375884c8cc7ef14e28d0d30b0c53 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 11:54:03 +0800 Subject: [PATCH 194/289] Shortened Scrambled Tail and Head LOC I hate it when VS keeps on adding newlines --- src/SortArray.cpp | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 5bf257e64..b6a2ec2b2 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -216,10 +216,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) - { - ++it1; - } + if (i <= half + (half / 2)) { ++it1; } } break; } @@ -228,10 +225,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) - { - ++it1; - } + if (i <= (m_array.size() / 2) - 1) { ++it1; } } break; } @@ -240,10 +234,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) - { - ++it1; - } + if (i <= (m_array.size() / 4)) { ++it1; } } break; } @@ -263,10 +254,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 4)) - { - ++it; - } + if (i <= (m_array.size() / 4)) { ++it; } } break; } @@ -275,10 +263,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= (m_array.size() / 2) - 1) - { - ++it; - } + if (i <= (m_array.size() / 2) - 1) { ++it; } } break; } @@ -288,10 +273,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); - if (i <= half + (half / 2)) - { - ++it; - } + if (i <= half + (half / 2)) { ++it; } } break; } From be92a19eaee0627a96557c2fcecd254960ae502f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 13:18:39 +0800 Subject: [PATCH 195/289] Slightly altered element step rendering This change ensures that the last element of the array is always drawn, this is incase if the i_step variable never lands on the last index of the array. This change could help ensure that Near Sorted is always rendered correctly. --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 7849174a8..4fb311528 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -252,7 +252,7 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); - if (i == i_step || i == 0) + if (i == i_step || i == 0 || i == (size - 1)) { clr = clr % numBrushes; dc.SetPen(pens[clr]); From 7b4a7a92d45fa1dffed968e8fdf8ef0bbdd8eccd Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 13:25:13 +0800 Subject: [PATCH 196/289] Avoided needing to recalculate size every iteration --- src/WSortView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 4fb311528..d0bba6e0f 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -248,11 +248,11 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) int numBrushes = sizeof(brushes) / sizeof(brushes[0]); if (step > 1) { - size_t i_step = step; + size_t i_step = step, last = size - 1; for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); - if (i == i_step || i == 0 || i == (size - 1)) + if (i == i_step || i == 0 || i == last) { clr = clr % numBrushes; dc.SetPen(pens[clr]); From aa9d63fdaa262a6386def70b77ec171bed362c84 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 13:50:56 +0800 Subject: [PATCH 197/289] Limited visibility scope of array input generation helpers --- src/SortArray.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index b6a2ec2b2..3b502fc67 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -135,7 +135,7 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Bell Curve")); } -void flippedminheapify(std::vector& m_array, int len, int root, int dist) +static void flippedminheapify(std::vector& m_array, int len, int root, int dist) { while (root <= dist / 2) { @@ -152,7 +152,7 @@ void flippedminheapify(std::vector& m_array, int len, int root, int d } } -void heapify(std::vector& m_array, int n, int i) +static void heapify(std::vector& m_array, int n, int i) { int largest = i, left = 2 * i + 1, right = 2 * i + 2; if (left < n && m_array[left] > m_array[largest]) { largest = left; } @@ -166,7 +166,7 @@ void heapify(std::vector& m_array, int n, int i) } } -float gaussian(float x, float mean, float std_dev) +static float gaussian(float x, float mean, float std_dev) { float exponent = -((x - mean) * (x - mean)) / (2 * std_dev * std_dev); return std::exp(exponent); From c81fd765202bccfcc42b72828e2481c0e521d94e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 14:35:33 +0800 Subject: [PATCH 198/289] Update WMain.cpp Since the project is already using -O2, I believe setting the thread to max priority is redundant now. --- src/WMain.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 140e691a4..e81adc93b 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -155,7 +155,6 @@ bool WMain::RunAlgorithm() m_thread_terminate = false; m_thread->Create(); - m_thread->SetPriority(WXTHREAD_MAX_PRIORITY); g_algo_running = true; m_thread->Run(); From d824bb3da06fcdb9fa3268c20794061d56a33bc7 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 15:09:30 +0800 Subject: [PATCH 199/289] Simplified loop condition on step visualization By initializing i_step to 0, i == 0 is not needed anymore. But i == last is still needed in order to make sure that the last element is always included in the drawing process. The last variable is now a const, numBrushes is now also a const, as these variables are not meant to change. --- src/WSortView.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index d0bba6e0f..2dcda4513 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -245,14 +245,15 @@ void WSortView::paint(wxDC& dc, const wxSize& dcsize) wxMutexLocker lock(m_array.m_mutex); ASSERT(lock.IsOk()); - int numBrushes = sizeof(brushes) / sizeof(brushes[0]); + const int numBrushes = sizeof(brushes) / sizeof(brushes[0]); if (step > 1) { - size_t i_step = step, last = size - 1; + size_t i_step = 0; + const size_t last = size - 1; for (size_t i = 0; i < size; ++i) { int clr = m_array.GetIndexColor(i); - if (i == i_step || i == 0 || i == last) + if (i == i_step || i == last) { clr = clr % numBrushes; dc.SetPen(pens[clr]); From 9a87aeb9f8e983b878120fb090445a25245f12c4 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 28 Oct 2024 15:40:37 +0800 Subject: [PATCH 200/289] High-level StlSort will now use the shifting InsertionSort --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 2a70b0566..c0fe8cae2 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1830,7 +1830,7 @@ void StlSort(SortArray& A) { size_t n = A.size(); introsortLoop(A, 0, n, 2 * floorLogBaseTwo(n)); - InsertionSort2(A); + InsertionSort(A); } void StlSort2(SortArray& A) From 9367add5861b9e1480dcd60db8990bae380bef31 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 03:40:20 +0800 Subject: [PATCH 201/289] Added Perlin Noise Curve array input type This also fixes the leftmost portion of the array being 0, by using Insertion Sort like logic to fix the curved array --- src/SortArray.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 3b502fc67..2454d0a8e 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -42,6 +42,41 @@ size_t m_swaps = 0; static int scrambled_tail_intensity = 1; static int scrambled_head_intensity = 1; +static const int perm[512] = { + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, + 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, + 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, + 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, + 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, + 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, + 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, + 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, + 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, + 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, + 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, + 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, + 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, + 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, + 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, + 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, + 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, + 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, + 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, + 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, + 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, + 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, + 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, + 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, + 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 +}; + void ArrayItem::OnAccess(const ArrayItem& a) { SoundAccess(a.get_direct()); @@ -133,6 +168,7 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Max Heapified")); list.Add(_("Flipped Min Heapified")); list.Add(_("Bell Curve")); + list.Add(_("Perlin Noise Curve")); } static void flippedminheapify(std::vector& m_array, int len, int root, int dist) @@ -172,6 +208,25 @@ static float gaussian(float x, float mean, float std_dev) return std::exp(exponent); } +static float fade(float t) { + return t * t * t * (t * (t * 6 - 15) + 10); +} + +static float lerp(float t, float a, float b) { + return a + t * (b - a); +} + +static float gradient(int hash, float x) { + return (hash & 1) == 0 ? x : -x; +} + +static float returnPerlinNoise(float x) { + int X = static_cast(floor(x)) & 255; + x -= floor(x); + float u = fade(x); + return lerp(u, gradient(perm[X], x), gradient(perm[X + 1], x - 1)) * 2; +} + void SortArray::FillData(unsigned int schema, size_t arraysize) { if (arraysize == 0) arraysize = 1; @@ -593,6 +648,23 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } + case 21: + { + int n = m_array.size(); + for (int i = 0; i < n; ++i) { + int value = -(static_cast(returnPerlinNoise(static_cast(i) / n) * n)); + m_array[i] = ArrayItem(std::min(value, n - 1)); + } + ArrayItem middle = m_array[n / 2]; // Fix 0-value leftmost portion + int index; + for (index = 0; index < n - 1; ++index) + { + if (m_array[index] > m_array[index + 1]) { break; } + else { m_array[index] = m_array[index + 1]; } + } + m_array[index] = middle; + break; + } default: return FillData(0, arraysize); } From 49e6a68448281f410c9c5dd04788685ac1779f0c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 04:19:55 +0800 Subject: [PATCH 202/289] Simplified Perlin Noise Curve correction code --- src/SortArray.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 2454d0a8e..216d37681 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -655,14 +655,11 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) int value = -(static_cast(returnPerlinNoise(static_cast(i) / n) * n)); m_array[i] = ArrayItem(std::min(value, n - 1)); } - ArrayItem middle = m_array[n / 2]; // Fix 0-value leftmost portion - int index; - for (index = 0; index < n - 1; ++index) + for (int index = 0; index < n - 1; ++index) // Fix 0-value leftmost portion { if (m_array[index] > m_array[index + 1]) { break; } else { m_array[index] = m_array[index + 1]; } } - m_array[index] = middle; break; } default: From c00d6534fe1daacf85fb2c7a3108a8075344d52d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 20:46:46 +0800 Subject: [PATCH 203/289] Added Blancmange Curve array input type --- src/SortArray.cpp | 52 +++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 216d37681..f5f6eead9 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -169,6 +169,7 @@ void SortArray::FillInputlist(wxArrayString& list) list.Add(_("Flipped Min Heapified")); list.Add(_("Bell Curve")); list.Add(_("Perlin Noise Curve")); + list.Add(_("Blancmange Curve")); } static void flippedminheapify(std::vector& m_array, int len, int root, int dist) @@ -212,12 +213,18 @@ static float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } -static float lerp(float t, float a, float b) { - return a + t * (b - a); -} +static float lerp(float t, float a, float b) { return a + t * (b - a); } + +static float gradient(int hash, float x) { return (hash & 1) == 0 ? x : -x; } + +static double triangleWave(double x) { return abs(x - (int)(x + 0.5)); } -static float gradient(int hash, float x) { - return (hash & 1) == 0 ? x : -x; +static double curve(int n, double x) { return triangleWave((1 << n) * x) / (1 << n); } + +static double curveSum(int n, double x) { + double sum = 0; + while (n >= 0) { sum += curve(n, x); --n; } + return sum; } static float returnPerlinNoise(float x) { @@ -389,7 +396,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(val); ++val; } - val = n / 2; + val = static_cast(n) / 2; for (size_t i = n / 2; i <= n - 1; ++i) { m_array[i] = ArrayItem(val); --val; @@ -402,7 +409,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) { m_array[i] = ArrayItem(val); ++val; } - val = n / 2; + val = static_cast(n) / 2; for (size_t i = (n / 2) + 1; i <= n - 1; ++i) { m_array[i] = ArrayItem(val); --val; @@ -415,7 +422,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) size_t n = m_array.size(); if (n % 2 == 0) { - int val = n / 2; + int val = static_cast(n) / 2; for (size_t i = 0; i < n / 2; ++i) { m_array[i] = ArrayItem(val); --val; @@ -428,7 +435,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } else { - int val = n / 2; + int val = static_cast(n) / 2; for (size_t i = 0; i <= n / 2; ++i) { m_array[i] = ArrayItem(val); @@ -444,7 +451,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } case 11: // Wave { - double n = double(m_array.size()); + double n = static_cast(m_array.size()); double pi = 3.14159265358979323846; for (size_t i = 0; i < m_array.size(); ++i) { @@ -545,7 +552,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } case 15: // Quicksort Killer { - int currentLen = m_array.size(); + int currentLen = static_cast(m_array.size()); for (int i = 0; i < currentLen; ++i) { m_array[i] = ArrayItem(i + 1); @@ -605,7 +612,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 17: // Ribbon { int min = 1; - int max = m_array.size(); + int max = static_cast(m_array.size()); for (size_t i = 0; i < m_array.size(); ++i) { if (i % 2 == 0) { m_array[i] = ArrayItem(min); } @@ -624,7 +631,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } case 19: // Flipped Min Heapified { - int n = m_array.size(); + int n = static_cast(m_array.size()); for (int i = 0; i < n; ++i) { m_array[i] = ArrayItem(i + 1); } std::shuffle(m_array.begin(), m_array.end(), g); for (int i = n / 2; i >= 1; --i) @@ -635,7 +642,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } case 20: // Bell Curve { - int length = m_array.size(); + int length = static_cast(m_array.size()); float mean = length / 2.0f; float std_dev = length / 6.4f; for (int i = 0; i < length; ++i) @@ -648,20 +655,31 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 21: + case 21: // Perlin Npise Curve { - int n = m_array.size(); + int n = static_cast(m_array.size()); for (int i = 0; i < n; ++i) { int value = -(static_cast(returnPerlinNoise(static_cast(i) / n) * n)); m_array[i] = ArrayItem(std::min(value, n - 1)); } - for (int index = 0; index < n - 1; ++index) // Fix 0-value leftmost portion + for (int index = 0; index < n - 1; ++index) // Fix zero first element by expanding the left curve { if (m_array[index] > m_array[index + 1]) { break; } else { m_array[index] = m_array[index + 1]; } } break; } + case 22: // Blancmange Curve + { + int len = static_cast(m_array.size()); + int floorLog = static_cast(log(len) / log(2)); + for (int i = 0; i < len; ++i) + { + int val = static_cast(len * curveSum(floorLog, static_cast(i) / len)); + m_array[i] = ArrayItem(val); + } + break; + } default: return FillData(0, arraysize); } From ae353e3d32316565f4f21f138c26f156cbb51f83 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 20:50:56 +0800 Subject: [PATCH 204/289] Added zero first element fix on Blancmange Curve --- src/SortArray.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index f5f6eead9..2a0c590b2 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -678,6 +678,9 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) int val = static_cast(len * curveSum(floorLog, static_cast(i) / len)); m_array[i] = ArrayItem(val); } + int half = len / 2; + // Fix zero first element by expanding the left portion + for (int i = 0; i < half; ++i) { m_array[i] = m_array[i + 1]; } break; } default: From 4f082d4d8e38be2961d02716552bd8964a477aee Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 20:58:41 +0800 Subject: [PATCH 205/289] Slightly optimized Perlin Noise Curve array correction --- src/SortArray.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 2a0c590b2..536683000 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -655,7 +655,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } break; } - case 21: // Perlin Npise Curve + case 21: // Perlin Noise Curve { int n = static_cast(m_array.size()); for (int i = 0; i < n; ++i) { @@ -664,7 +664,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } for (int index = 0; index < n - 1; ++index) // Fix zero first element by expanding the left curve { - if (m_array[index] > m_array[index + 1]) { break; } + if (m_array[index] >= m_array[index + 1]) { break; } else { m_array[index] = m_array[index + 1]; } } break; From fbc2517aa2d8c499b58b0f828bcd754e9f279a91 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 22:23:24 +0800 Subject: [PATCH 206/289] Remade Many Similar array generation This should be even more accurate than the previous implementation. --- src/SortArray.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 536683000..984bbe773 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -520,30 +520,22 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } case 14: // Many Similar { - size_t group_count = 0, size = m_array.size(); - if (size % 10 == 0) { group_count = 10; } - else if (size % 9 == 0) { group_count = 9; } - else if (size % 8 == 0) { group_count = 8; } - else if (size % 7 == 0) { group_count = 7; } - else if (size % 6 == 0) { group_count = 6; } - else if (size % 5 == 0) { group_count = 5; } - else if (size % 4 == 0) { group_count = 4; } - else if (size % 2 != 0) { group_count = 3; } - else { group_count = 2; } - size_t n = m_array.size(); - if (n <= 10) + size_t size = m_array.size(), group_count = 0, divisor = 2; + if (size % 5 == 0) { divisor = 5; } + else if (size % 4 == 0) { divisor = 4; } + else if (size % 3 == 0) { divisor = 3; } + else // Array size is a prime number, decrement and reevaluate! { - if (n % 2 != 0) { group_count = 3; } - else { group_count = 2; } + --size; + if (size % 5 == 0) { divisor = 5; } + else if (size % 4 == 0) { divisor = 4; } } + group_count = size / divisor; size_t repeat = 1; int val = 1; for (size_t i = 0; i < size; ++i) { - if (repeat > group_count) - { - ++val; repeat = 1; - } + if (repeat > group_count) { ++val; repeat = 1; } m_array[i] = ArrayItem(val); ++repeat; } From 9a5959f2052386d42e033f423094dcebc3736358 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 29 Oct 2024 22:48:56 +0800 Subject: [PATCH 207/289] Allowed bigger groupings in Many Similar array Also provided a one-off fix if the size of the array is perfectly divisible by 2 only --- src/SortArray.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 984bbe773..66c8a7963 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -521,16 +521,35 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 14: // Many Similar { size_t size = m_array.size(), group_count = 0, divisor = 2; - if (size % 5 == 0) { divisor = 5; } + if (size % 16 == 0) { divisor = 16; } + else if (size % 15 == 0) { divisor = 15; } + else if (size % 14 == 0) { divisor = 14; } + else if (size % 13 == 0) { divisor = 13; } + else if (size % 12 == 0) { divisor = 12; } + else if (size % 11 == 0) { divisor = 11; } + else if (size % 10 == 0) { divisor = 10; } + else if (size % 9 == 0) { divisor = 9; } + else if (size % 8 == 0) { divisor = 8; } + else if (size % 7 == 0) { divisor = 7; } + else if (size % 6 == 0) { divisor = 6; } + else if (size % 5 == 0) { divisor = 5; } else if (size % 4 == 0) { divisor = 4; } else if (size % 3 == 0) { divisor = 3; } else // Array size is a prime number, decrement and reevaluate! { --size; - if (size % 5 == 0) { divisor = 5; } + if (size % 16 == 0) { divisor = 16; } + else if (size % 15 == 0) { divisor = 15; } + else if (size % 14 == 0) { divisor = 14; } + else if (size % 12 == 0) { divisor = 12; } + else if (size % 10 == 0) { divisor = 10; } + else if (size % 6 == 0) { divisor = 6; } + else if (size % 8 == 0) { divisor = 8; } + else if (size % 5 == 0) { divisor = 5; } else if (size % 4 == 0) { divisor = 4; } } group_count = size / divisor; + if (divisor == 2) { ++group_count; } size_t repeat = 1; int val = 1; for (size_t i = 0; i < size; ++i) From 3a45fabd533913111bad2dab5badc21275d28285 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 01:32:12 +0800 Subject: [PATCH 208/289] Further refined Many Similar array input implementation This introduces some changes to how Many Similar works: 1. The possible number of unique elements are now made to be more modular by being inside a constant array, which means that if the user wants to manually add or remove a potential number number of unique elements, then simply modifying the groupSizes array will suffice, and the code for Many Similar generation will immediately notice this change (as long as the file has been saved of course). 2. The case for prime array size is more robust now. The previous implementation decrements the array size by 1 and then rechecks the best number of unique elements for this size, which is correct, but the size is never reset back to its original value afterwards leading to a slight inconsistency, meaning there is a "one-off" index that is not considered. This change fixes it by first checking if the size is a prime number or not, if the array size is a prime number, the size variable will be reset (because it is decremented), the first value of the array will be set to 1, and the starting index for the value insertion will be incremented by one to skip the first index (0). --- src/SortArray.cpp | 55 ++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 66c8a7963..3dfca60e3 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -77,6 +77,8 @@ static const int perm[512] = { 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; +static const size_t groupSizes[] = { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; + void ArrayItem::OnAccess(const ArrayItem& a) { SoundAccess(a.get_direct()); @@ -221,6 +223,18 @@ static double triangleWave(double x) { return abs(x - (int)(x + 0.5)); } static double curve(int n, double x) { return triangleWave((1 << n) * x) / (1 << n); } +static size_t groupCount(size_t size) +{ + size_t divisor = 2, len = sizeof(groupSizes) / sizeof(groupSizes[0]); + for (size_t i = 0; i < len; ++i) + { + size_t cur = groupSizes[i]; + if (cur == size) { continue; } + if (size % cur == 0) { divisor = cur; break; } + } + return divisor; +} + static double curveSum(int n, double x) { double sum = 0; while (n >= 0) { sum += curve(n, x); --n; } @@ -520,39 +534,26 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) } case 14: // Many Similar { - size_t size = m_array.size(), group_count = 0, divisor = 2; - if (size % 16 == 0) { divisor = 16; } - else if (size % 15 == 0) { divisor = 15; } - else if (size % 14 == 0) { divisor = 14; } - else if (size % 13 == 0) { divisor = 13; } - else if (size % 12 == 0) { divisor = 12; } - else if (size % 11 == 0) { divisor = 11; } - else if (size % 10 == 0) { divisor = 10; } - else if (size % 9 == 0) { divisor = 9; } - else if (size % 8 == 0) { divisor = 8; } - else if (size % 7 == 0) { divisor = 7; } - else if (size % 6 == 0) { divisor = 6; } - else if (size % 5 == 0) { divisor = 5; } - else if (size % 4 == 0) { divisor = 4; } - else if (size % 3 == 0) { divisor = 3; } - else // Array size is a prime number, decrement and reevaluate! + size_t size = m_array.size(), group_count = 0, divisor = groupCount(size); + bool isPrime = false; + // If the size is an odd number, and groupCount returns 2, then the array size is a prime number + if (divisor == 2 && size % 2 != 0) { --size; - if (size % 16 == 0) { divisor = 16; } - else if (size % 15 == 0) { divisor = 15; } - else if (size % 14 == 0) { divisor = 14; } - else if (size % 12 == 0) { divisor = 12; } - else if (size % 10 == 0) { divisor = 10; } - else if (size % 6 == 0) { divisor = 6; } - else if (size % 8 == 0) { divisor = 8; } - else if (size % 5 == 0) { divisor = 5; } - else if (size % 4 == 0) { divisor = 4; } + isPrime = true; + divisor = groupCount(size); } group_count = size / divisor; if (divisor == 2) { ++group_count; } - size_t repeat = 1; + size_t repeat = 1, i = 0; + if (isPrime == true) + { + m_array[0] = ArrayItem(1); + size = m_array.size(); + ++i; + } int val = 1; - for (size_t i = 0; i < size; ++i) + for (; i < size; ++i) { if (repeat > group_count) { ++val; repeat = 1; } m_array[i] = ArrayItem(val); From 394169633064b699fca599554399ea2090bfa365 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 01:50:31 +0800 Subject: [PATCH 209/289] Slight correction on groupCount() method Although I checked that even without this condition, the program doesn't complain if the array is set to 1 and then Many Similar is selected. But this condition is here for consistency. --- src/SortArray.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 3dfca60e3..661043546 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -225,6 +225,7 @@ static double curve(int n, double x) { return triangleWave((1 << n) * x) / (1 << static size_t groupCount(size_t size) { + if (size <= 1) { return 2; } size_t divisor = 2, len = sizeof(groupSizes) / sizeof(groupSizes[0]); for (size_t i = 0; i < len; ++i) { From e54656f5401be6eb6b594db46f515938e0d951c1 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 02:06:55 +0800 Subject: [PATCH 210/289] Fixed 2 unique elements on very large array sizes for Many Similar This change probably feels more like a personal preference, but I think it is not really good if a large array size generates only 2 unique elements, especially since Many Similar is generated dynamically here, therefore, this change avoids this 2 unique element configuration on an even array size from happening by performing some adjustments. --- src/SortArray.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 661043546..777796035 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -536,7 +536,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 14: // Many Similar { size_t size = m_array.size(), group_count = 0, divisor = groupCount(size); - bool isPrime = false; + bool isPrime = false, isDiv2Even = false; // If the size is an odd number, and groupCount returns 2, then the array size is a prime number if (divisor == 2 && size % 2 != 0) { @@ -544,8 +544,14 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) isPrime = true; divisor = groupCount(size); } + // If the size is an even number, and the divisor returns 2, then decrement the size by 2 to pick a good group count + else if (divisor == 2 && size % 2 == 0) + { + size -= 2; + isDiv2Even = true; + divisor = groupCount(size); + } group_count = size / divisor; - if (divisor == 2) { ++group_count; } size_t repeat = 1, i = 0; if (isPrime == true) { @@ -553,6 +559,13 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) size = m_array.size(); ++i; } + if (isDiv2Even == true) + { + m_array[0] = ArrayItem(1); + m_array[1] = ArrayItem(1); + i += 2; + size = m_array.size(); + } int val = 1; for (; i < size; ++i) { From d9d8235fd1d68c2a612248bccc52c49715a367d7 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 06:13:52 +0800 Subject: [PATCH 211/289] Add files via upload --- src/SortArray.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 777796035..3cb5cc6ef 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -42,7 +42,7 @@ size_t m_swaps = 0; static int scrambled_tail_intensity = 1; static int scrambled_head_intensity = 1; -static const int perm[512] = { +static const std::array perm = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, @@ -77,7 +77,8 @@ static const int perm[512] = { 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; -static const size_t groupSizes[] = { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; + +static const std::array groupSizes = { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; void ArrayItem::OnAccess(const ArrayItem& a) { @@ -226,7 +227,7 @@ static double curve(int n, double x) { return triangleWave((1 << n) * x) / (1 << static size_t groupCount(size_t size) { if (size <= 1) { return 2; } - size_t divisor = 2, len = sizeof(groupSizes) / sizeof(groupSizes[0]); + size_t divisor = 2, len = groupSizes.size(); for (size_t i = 0; i < len; ++i) { size_t cur = groupSizes[i]; From 156bbba3a7e73c8c238a9679188551190749b175 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 11:37:36 +0800 Subject: [PATCH 212/289] Add files via upload --- src/SortArray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 3cb5cc6ef..267ec223c 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -261,7 +261,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 0: // Shuffle of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); } - std::shuffle(m_array.begin(), m_array.end(), g); + std::shuffle(MyIterator(m_array, 0), MyIterator(m_array, m_array.size()), g); break; } case 1: // Ascending [1,n] From fa968e02950b842bfe79f47fcb84e238cd3378ea Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 11:38:51 +0800 Subject: [PATCH 213/289] Reverted unnecessary change --- src/SortArray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 267ec223c..3cb5cc6ef 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -261,7 +261,7 @@ void SortArray::FillData(unsigned int schema, size_t arraysize) case 0: // Shuffle of [1,n] { for (size_t i = 0; i < m_array.size(); ++i) { m_array[i] = ArrayItem(i + 1); } - std::shuffle(MyIterator(m_array, 0), MyIterator(m_array, m_array.size()), g); + std::shuffle(m_array.begin(), m_array.end(), g); break; } case 1: // Ascending [1,n] From 315ef7c2284f6c84f8656bdf56c290cb0085ddba Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 14:09:18 +0800 Subject: [PATCH 214/289] Added Rotate Radix MSD and LSD Sort This also modifies rotate() to be more "safe" as it uses int now, rotate has "small" chance of having an overflow due to the condition (if (n > 0)),, so this fixes that too. --- src/SortAlgo.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++---- src/SortAlgo.h | 2 + 2 files changed, 139 insertions(+), 13 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index c0fe8cae2..3831af7c4 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -143,6 +143,10 @@ const struct AlgoEntry g_algolist[] = _("Least significant digit radix sort, performed in O(1) space.") }, { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, 512, _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, + { _("Rotate Radix Sort (MSD)"), &RotateRadixSortMSD, UINT_MAX, 512, + wxEmptyString }, + { _("Rotate Radix Sort (LSD)"), &RotateRadixSortLSD, UINT_MAX, 512, + wxEmptyString }, { _("American Flag Sort"), &AmericanFlagSort, UINT_MAX, inversion_count_instrumented, _("American Flag Sort is an efficient, in-place variant of radix sort that distributes items into hundreds of buckets.") }, { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, @@ -575,14 +579,14 @@ void shiftValue(SortArray& A, size_t a, size_t b, size_t len) } } -void rotate(SortArray& A, size_t a, size_t m, size_t b) +void rotate(SortArray& A, int a, int m, int b) { - size_t l = m - a, r = b - m; + int l = m - a, r = b - m; while (l > 0 && r > 0) { if (r < l) { - shiftValue(A, m - r, m, r); + shiftValue(A, static_cast(m - r), static_cast(m), static_cast(r)); b -= r; m -= r; l -= r; @@ -590,7 +594,7 @@ void rotate(SortArray& A, size_t a, size_t m, size_t b) else { - shiftValue(A, a, m, l); + shiftValue(A, static_cast(a), static_cast(m), static_cast(l)); a += l; m += l; r -= l; @@ -652,7 +656,7 @@ void weaveMerge(SortArray& A, size_t a, size_t m, size_t b) { m = (a1 + e) / 2; size_t p = 1 << static_cast(log(m - a1) / log(2)); - rotate(A, m - p, m, e - p); + rotate(A, static_cast(m - p), static_cast(m), static_cast(e - p)); m = e - p; f = m - p; @@ -1514,7 +1518,7 @@ size_t maxLog(SortArray& A, size_t n, size_t base) return digit; } -int getDigit(int a, double power, int radix) +int getDigit2(int a, double power, int radix) { double digit = (a / static_cast(pow(radix, power)) % radix); return static_cast(digit); @@ -1550,7 +1554,7 @@ void radixMSD(SortArray& A, size_t len, size_t min, size_t max, size_t radix, do for (size_t i = min; i < max; ++i) { int ele = A[i].get(); - int digit = getDigit(ele, pow, radix); + int digit = getDigit2(ele, pow, radix); registers[digit].push_back(A[i]); } @@ -1676,7 +1680,7 @@ void InPlaceRadixSortLSD(SortArray& A) for (size_t i = 0; i < n; ++i) { int ele = A[pos].get(); - int digit = getDigit(ele, (double)p, bucket); + int digit = getDigit2(ele, (double)p, bucket); if (digit == 0) { ++pos; } else { @@ -1690,6 +1694,128 @@ void InPlaceRadixSortLSD(SortArray& A) } } +// **************************************************************************** +// *** Rotate Radix MSD/LSD Sort + +/* + Copyright (c) 2020-2021 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +static const int base = 4; + +int shift(int n, int q) +{ + while (q > 0) + { + n /= base; + --q; + } + return n; +} + +int binSearch(SortArray& A, int a, int b, int d, int p) +{ + while (a < b) + { + int m = (a + b) / 2; + int ele = A[m]; + int result = static_cast(getDigit2(static_cast(ele), static_cast(p), static_cast(base))); + if (result >= d) { b = m; } + else { a = m + 1; } + } + return a; +} + +void rotateMerge(SortArray& A, int a, int m, int b, int da, int db, int p) +{ + if (b - a < 2 || db - da < 2) { return; } + int dm = (da + db) / 2; + int m1 = binSearch(A, a, m, dm, p); + int m2 = binSearch(A, m, b, dm, p); + rotate(A, m1, m, m2); + m = m1 + (m2 - m); + rotateMerge(A, m, m2, b, dm, db, p); + rotateMerge(A, a, m1, m, da, dm, p); +} + +void rotateMergeSort(SortArray& A, int a, int b, int p) +{ + if (b - a < 2) { return; } + int m = (a + b) / 2; + rotateMergeSort(A, a, m, p); + rotateMergeSort(A, m, b, p); + rotateMerge(A, a, m, b, 0, base, p); +} + +int dist(SortArray& A, int a, int b, int p) +{ + rotateMergeSort(A, a, b, p); + return binSearch(A, a, b, 1, p); +} + +void RotateRadixSortMSD(SortArray& A) +{ + int len = static_cast(A.size()); + int q = static_cast(maxLog(A, static_cast(len), static_cast(base))); + int m = 0, i = 0, b = len; + while (i < len) + { + int p = 0; + if (b - i < 1) { p = i; } + else { p = dist(A, i, b, q); } + if (q == 0) + { + m += base; + int t = m / base; + while (t % base == 0) + { + t /= base; + ++q; + } + i = b; + while (b < len) + { + int ele = A[b]; + if (shift(ele, q + 1) == shift(m, q + 1)) { ++b; } + else { break; } + } + } + else + { + b = p; + --q; + } + } +} + +void RotateRadixSortLSD(SortArray& A) +{ + int len = static_cast(A.size()); + int max = static_cast(maxLog(A, static_cast(len), static_cast(base))); + for (int i = 0; i <= max; ++i) + { + rotateMergeSort(A, 0, len, i); + } +} + // **************************************************************************** // *** Use STL Sorts via Iterator Adapters @@ -3032,6 +3158,9 @@ void PairwiseIterativeSort(SortArray& A) See the License for the specific language governing permissions and limitations under the License. */ + +size_t getDigit(size_t num, size_t divisor, size_t buckets) { return (num / divisor) % buckets; } + int getMaxNumberOfDigits(SortArray& A, size_t len, int buckets) { int max = std::numeric_limits::min(); @@ -3045,11 +3174,6 @@ int getMaxNumberOfDigits(SortArray& A, size_t len, int buckets) return max; } -size_t getDigit(size_t num, size_t divisor, size_t buckets) -{ - return (num / divisor) % buckets; -} - void sort(SortArray& A, size_t start, size_t len, size_t divisor) { size_t buckets = 128; diff --git a/src/SortAlgo.h b/src/SortAlgo.h index ceb7e067e..36e0ade15 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -105,6 +105,8 @@ void BatcherSortNetwork(SortArray& a); void InPlaceRadixSortLSD(class SortArray& a); void RadixSortLSD(class SortArray& a); void RadixSortMSD(class SortArray& a); +void RotateRadixSortLSD(class SortArray& a); +void RotateRadixSortMSD(class SortArray& a); void AmericanFlagSort(class SortArray& a); void StlSort(class SortArray& a); From 1530813dcda0446e0042c4109b08b3a76e8354d9 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 17:53:07 +0800 Subject: [PATCH 215/289] Added sounds on Rotate Radix LSD/MSD Sort --- src/SortAlgo.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 3831af7c4..46c4978d1 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -575,6 +575,7 @@ void shiftValue(SortArray& A, size_t a, size_t b, size_t len) { for (size_t i = 0; i < len; ++i) { + A[a + i].get(); A.swap(a + i, b + i); } } @@ -1736,7 +1737,7 @@ int binSearch(SortArray& A, int a, int b, int d, int p) while (a < b) { int m = (a + b) / 2; - int ele = A[m]; + int ele = A[m].get(); int result = static_cast(getDigit2(static_cast(ele), static_cast(p), static_cast(base))); if (result >= d) { b = m; } else { a = m + 1; } @@ -1793,7 +1794,7 @@ void RotateRadixSortMSD(SortArray& A) i = b; while (b < len) { - int ele = A[b]; + int ele = A[b].get(); if (shift(ele, q + 1) == shift(m, q + 1)) { ++b; } else { break; } } From 264ad6c0d94230058178858cd865f361c970e6e3 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 19:56:19 +0800 Subject: [PATCH 216/289] Inner loop in DoDelay() to respond upon termination --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 2dcda4513..1be4715eb 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -90,7 +90,7 @@ void WSortView::DoDelay(double delay) while (m_stepwise) { wxSemaError se = m_step_semaphore.WaitTimeout(200); - if (se == wxSEMA_NO_ERROR) + if (se == wxSEMA_NO_ERROR || wmain->m_thread_terminate) break; // else timeout, recheck m_stepwise and loop wxMilliSleep(1); From 86beaa19744d8ccd27c0605f45006c7e29290134 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 20:02:33 +0800 Subject: [PATCH 217/289] Reverted change --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 1be4715eb..2dcda4513 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -90,7 +90,7 @@ void WSortView::DoDelay(double delay) while (m_stepwise) { wxSemaError se = m_step_semaphore.WaitTimeout(200); - if (se == wxSEMA_NO_ERROR || wmain->m_thread_terminate) + if (se == wxSEMA_NO_ERROR) break; // else timeout, recheck m_stepwise and loop wxMilliSleep(1); From a384bd79dba41f8abdd70519d3468e1254198d1c Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 21:48:43 +0800 Subject: [PATCH 218/289] Verifying if any unnecessary changes have been made --- src/SortArray.cpp | 1 - src/WMain.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 3cb5cc6ef..20069c4e1 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -77,7 +77,6 @@ static const std::array perm = { 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; - static const std::array groupSizes = { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; void ArrayItem::OnAccess(const ArrayItem& a) diff --git a/src/WMain.cpp b/src/WMain.cpp index e81adc93b..c909fb93e 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -83,7 +83,7 @@ WMain::WMain(wxWindow* parent) // Set the audio format sdlaudiospec.freq = 44100; sdlaudiospec.format = AUDIO_S16SYS; - sdlaudiospec.channels = 1; /* 1 = mono, 2 = stereo */ + sdlaudiospec.channels = 2; /* 1 = mono, 2 = stereo */ sdlaudiospec.samples = 4096; /* Good low-latency value for callback */ sdlaudiospec.callback = SoundCallback; sdlaudiospec.userdata = sortview; @@ -171,7 +171,7 @@ void WMain::AbortAlgorithm() if (!m_thread) return; m_thread_terminate = true; - if (m_thread->IsPaused()) m_thread->Resume(); + if (m_thread->IsPaused()) { m_thread->Resume(); } sortview->SetStepwise(false); m_thread->Wait(); From fd681bbabd40f24ed0c2a3b135eef1bb41438649 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 30 Oct 2024 21:55:30 +0800 Subject: [PATCH 219/289] Switched Stereo to Mono --- src/WMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index c909fb93e..56a8f498a 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -83,7 +83,7 @@ WMain::WMain(wxWindow* parent) // Set the audio format sdlaudiospec.freq = 44100; sdlaudiospec.format = AUDIO_S16SYS; - sdlaudiospec.channels = 2; /* 1 = mono, 2 = stereo */ + sdlaudiospec.channels = 1; /* 1 = mono, 2 = stereo */ sdlaudiospec.samples = 4096; /* Good low-latency value for callback */ sdlaudiospec.callback = SoundCallback; sdlaudiospec.userdata = sortview; From f4f91e15e9eb33794a91881c03f9079c2ec60030 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 01:45:45 +0800 Subject: [PATCH 220/289] Fixed crash on Many Similar and Iterative Circle Sort This change fixes incorrect sorting result of Iterative Circle Sort, as well as the program crashing when Many Similar is selected for prime numbers and numbers with 2 as the smallest divisor. --- src/SortAlgo.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++ src/SortArray.cpp | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 46c4978d1..fc3f21c7c 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -114,6 +114,12 @@ const struct AlgoEntry g_algolist[] = _("This variant sorts from both directions of the array simultaneously.") }, { _("Circle Sort"), &CircleSort, UINT_MAX, UINT_MAX, _("Circle Sort is a recursive sorting algorithm that works by comparing and swapping elements in a circular manner.") }, + { _("Iterative Circle Sort"), &CircleSort2, UINT_MAX, UINT_MAX, + _("A variant of Circle Sort that avoids recursion overhead.") }, + { _("Introspective Circle Sort"), &IntroCircleSort, UINT_MAX, UINT_MAX, + _("A variant of Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, + { _("Introspective Iterative Circle Sort"), &IntroIteCircleSort, UINT_MAX, UINT_MAX, + _("A variant of Iterative Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, wxEmptyString }, { _("Optimized Gnome Sort"), &OptimizedGnomeSort, UINT_MAX, UINT_MAX, @@ -1203,12 +1209,73 @@ bool CircleSortRec(SortArray& A, size_t low, size_t high) return swapped || firstHalf || secondHalf; } +bool CircleSortIte(SortArray& A, size_t length) +{ + bool swapped = false; + for (size_t gap = length / 2; gap > 0; gap /= 2) + { + for (size_t start = 0; start + gap < length; start += 2 * gap - 1) + { + size_t high = start + 2 * gap - 1, low = start; + while (low < high) + { + if (high < length && A[low] > A[high]) + { + A.swap(low, high); + swapped = true; + } + ++low; --high; + } + } + } + return swapped; +} + void CircleSort(SortArray& A) { size_t n = A.size(); while (CircleSortRec(A, 0, n - 1)) {} } +void CircleSort2(SortArray& A) +{ + size_t len = A.size(); + while (CircleSortIte(A, len)) {} +} + +void IntroCircleSort(SortArray& A) +{ + size_t len = A.size(), threshold = 0, n = 1, iterations = 0; + for (; n < len; n *= 2, ++threshold) {} + threshold /= 2; + do + { + ++iterations; + if (iterations >= threshold) + { + InsertSort(A, 0, len); + break; + } + } + while (CircleSortRec(A, 0, len - 1)); +} + +void IntroIteCircleSort(SortArray& A) +{ + size_t len = A.size(), threshold = 0, n = 1, iterations = 0; + for (; n < len; n *= 2, ++threshold) {} + threshold /= 2; + do + { + ++iterations; + if (iterations >= threshold) + { + InsertSort(A, 0, len); + break; + } + } while (CircleSortIte(A, len)); +} + // **************************************************************************** // *** Gnome Sort diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 20069c4e1..1ea36d7f4 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -77,7 +77,7 @@ static const std::array perm = { 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; -static const std::array groupSizes = { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; +static const std::array groupSizes = { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; void ArrayItem::OnAccess(const ArrayItem& a) { From 5b30f6720d13237cbb9fb6a51c5c862c5ce10948 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 02:36:34 +0800 Subject: [PATCH 221/289] Increased recursion depth limit on Introspective Iterative Circle Sort --- src/SortAlgo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index fc3f21c7c..8f9c7cf8d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1264,6 +1264,7 @@ void IntroIteCircleSort(SortArray& A) { size_t len = A.size(), threshold = 0, n = 1, iterations = 0; for (; n < len; n *= 2, ++threshold) {} + threshold += threshold / 2; threshold /= 2; do { From c631c8239ac09abd355b5be9c1c4d6e4498cf223 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 12:19:19 +0800 Subject: [PATCH 222/289] Vastly improve performance of Recursive and Iterative Circle Sort This is based on the implementation from ArrayV, this change also vastly affects the performance of Introspective Circle Sort, both the recursive and iterative variant --- src/SortAlgo.cpp | 50 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 8f9c7cf8d..dead14bc0 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -115,7 +115,7 @@ const struct AlgoEntry g_algolist[] = { _("Circle Sort"), &CircleSort, UINT_MAX, UINT_MAX, _("Circle Sort is a recursive sorting algorithm that works by comparing and swapping elements in a circular manner.") }, { _("Iterative Circle Sort"), &CircleSort2, UINT_MAX, UINT_MAX, - _("A variant of Circle Sort that avoids recursion overhead.") }, + _("A variant of Circle Sort that has less recursion overhead.") }, { _("Introspective Circle Sort"), &IntroCircleSort, UINT_MAX, UINT_MAX, _("A variant of Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, { _("Introspective Iterative Circle Sort"), &IntroIteCircleSort, UINT_MAX, UINT_MAX, @@ -1181,45 +1181,49 @@ void DualCocktailShakerSort(SortArray& A) // **************************************************************************** // *** Circle Sort -bool CircleSortRec(SortArray& A, size_t low, size_t high) +bool CircleSortRec(SortArray& A, size_t low, size_t high, size_t len) { bool swapped = false; if (low == high) { return false; } size_t lo = low, hi = high; while (lo < hi) { - if (A[lo] > A[hi]) + if (hi < len && A[lo] > A[hi]) { A.swap(lo, hi); swapped = true; } ++lo; --hi; } - if (lo == hi) + + size_t mid = (high - low) / 2; + bool firstHalf = CircleSortRec(A, low, low + mid, len); + bool secondHalf = false; + if (low + mid + 1 < len) { - if (A[lo] > A[hi + 1]) - { - A.swap(lo, hi + 1); - swapped = true; - } + secondHalf = CircleSortRec(A, low + mid + 1, high, len); } - size_t mid = (high - low) / 2; - bool firstHalf = CircleSortRec(A, low, low + mid); - bool secondHalf = CircleSortRec(A, low + mid + 1, high); return swapped || firstHalf || secondHalf; } -bool CircleSortIte(SortArray& A, size_t length) +void CircleSort(SortArray& A) +{ + size_t len = A.size(), n = 1; + for (; n < len; n *= 2) {} + while (CircleSortRec(A, 0, n - 1, len)) {} +} + +bool CircleSortIte(SortArray& A, size_t length, size_t arr_len) { bool swapped = false; for (size_t gap = length / 2; gap > 0; gap /= 2) { - for (size_t start = 0; start + gap < length; start += 2 * gap - 1) + for (size_t start = 0; start + gap < arr_len; start += 2 * gap) { size_t high = start + 2 * gap - 1, low = start; while (low < high) { - if (high < length && A[low] > A[high]) + if (high < arr_len && A[low] > A[high]) { A.swap(low, high); swapped = true; @@ -1231,16 +1235,11 @@ bool CircleSortIte(SortArray& A, size_t length) return swapped; } -void CircleSort(SortArray& A) -{ - size_t n = A.size(); - while (CircleSortRec(A, 0, n - 1)) {} -} - void CircleSort2(SortArray& A) { - size_t len = A.size(); - while (CircleSortIte(A, len)) {} + size_t len = A.size(), n = 1; + for (; n < len; n *= 2) {} + while (CircleSortIte(A, n, len)) {} } void IntroCircleSort(SortArray& A) @@ -1257,14 +1256,13 @@ void IntroCircleSort(SortArray& A) break; } } - while (CircleSortRec(A, 0, len - 1)); + while (CircleSortRec(A, 0, n - 1, len)); } void IntroIteCircleSort(SortArray& A) { size_t len = A.size(), threshold = 0, n = 1, iterations = 0; for (; n < len; n *= 2, ++threshold) {} - threshold += threshold / 2; threshold /= 2; do { @@ -1274,7 +1272,7 @@ void IntroIteCircleSort(SortArray& A) InsertSort(A, 0, len); break; } - } while (CircleSortIte(A, len)); + } while (CircleSortIte(A, n, len)); } // **************************************************************************** From 07a8d066bc8c4bc74da76611fec5d1d7bb1e783d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 12:49:25 +0800 Subject: [PATCH 223/289] Verifying if any unnecessary changes have been made --- src/SortAlgo.cpp | 5 ++--- src/SortAlgo.h | 3 +++ src/WMain.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index dead14bc0..576f94f9a 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1195,7 +1195,6 @@ bool CircleSortRec(SortArray& A, size_t low, size_t high, size_t len) } ++lo; --hi; } - size_t mid = (high - low) / 2; bool firstHalf = CircleSortRec(A, low, low + mid, len); bool secondHalf = false; @@ -1252,7 +1251,7 @@ void IntroCircleSort(SortArray& A) ++iterations; if (iterations >= threshold) { - InsertSort(A, 0, len); + BinaryInsertSort(A, 0, len); break; } } @@ -1269,7 +1268,7 @@ void IntroIteCircleSort(SortArray& A) ++iterations; if (iterations >= threshold) { - InsertSort(A, 0, len); + BinaryInsertSort(A, 0, len); break; } } while (CircleSortIte(A, n, len)); diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 36e0ade15..98250cc20 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -93,6 +93,9 @@ void OptimizedGnomeSort(class SortArray& a); void OddEvenSort(class SortArray& a); void TargetedBubbleSort(class SortArray& a); void CircleSort(class SortArray& a); +void CircleSort2(class SortArray& a); +void IntroCircleSort(class SortArray& a); +void IntroIteCircleSort(class SortArray& a); void ShellSort(SortArray& a); void HeapSort(class SortArray& a); diff --git a/src/WMain.cpp b/src/WMain.cpp index 56a8f498a..c909fb93e 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -83,7 +83,7 @@ WMain::WMain(wxWindow* parent) // Set the audio format sdlaudiospec.freq = 44100; sdlaudiospec.format = AUDIO_S16SYS; - sdlaudiospec.channels = 1; /* 1 = mono, 2 = stereo */ + sdlaudiospec.channels = 2; /* 1 = mono, 2 = stereo */ sdlaudiospec.samples = 4096; /* Good low-latency value for callback */ sdlaudiospec.callback = SoundCallback; sdlaudiospec.userdata = sortview; From 7e13ed925ce8c1bce6b9f8401c30201311fe2595 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 12:51:41 +0800 Subject: [PATCH 224/289] Checking if any changes might have been missed From 60bfcb0568704e2140c8f4d2c2c3833a16095bef Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 12:59:27 +0800 Subject: [PATCH 225/289] Made Introspective Circle Sort use Insertion Sort I would prefer the Introspective Circle Sort to use the normal Insertion Sort now after some observations. --- src/SortAlgo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 576f94f9a..b717a760b 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1251,7 +1251,7 @@ void IntroCircleSort(SortArray& A) ++iterations; if (iterations >= threshold) { - BinaryInsertSort(A, 0, len); + InsertSort(A, 0, len); break; } } @@ -1268,7 +1268,7 @@ void IntroIteCircleSort(SortArray& A) ++iterations; if (iterations >= threshold) { - BinaryInsertSort(A, 0, len); + InsertSort(A, 0, len); break; } } while (CircleSortIte(A, n, len)); From f0ef25f507f69c4f9eafb422665e4baf4de582ef Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 17:46:44 +0800 Subject: [PATCH 226/289] Fixed ambiguous lerp() method This warning happens when the project is compiled on C++20, this change fixes that warning. --- src/SortArray.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index 1ea36d7f4..f28626d35 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -215,7 +215,7 @@ static float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } -static float lerp(float t, float a, float b) { return a + t * (b - a); } +static float mlerp(float t, float a, float b) { return a + t * (b - a); } static float gradient(int hash, float x) { return (hash & 1) == 0 ? x : -x; } @@ -246,7 +246,7 @@ static float returnPerlinNoise(float x) { int X = static_cast(floor(x)) & 255; x -= floor(x); float u = fade(x); - return lerp(u, gradient(perm[X], x), gradient(perm[X + 1], x - 1)) * 2; + return mlerp(u, gradient(perm[X], x), gradient(perm[X + 1], x - 1)) * 2; } void SortArray::FillData(unsigned int schema, size_t arraysize) From ef36e91ce369f50f989e3ca55933a4fbd94fdf7f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 18:53:23 +0800 Subject: [PATCH 227/289] Fixed volatile decrement/increment warnings These warnings occur if the project is compiled on C++20. These warnings have been fixed now for most methods except QuickSortLRTernary. --- src/SortAlgo.cpp | 153 +++++++++++++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 58 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index b717a760b..f64491eb5 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -179,6 +179,8 @@ const struct AlgoEntry g_algolist[] = _("An optimized variant of Pancake Sort that performs 1/2 as many flips.") }, { _("Adjacency Pancake Sort"), &AdjacencyPancakeSort, UINT_MAX, UINT_MAX, _("An improvement upon Pancake Sort, which performs only 5/3 N + O(1) flips.") }, + { _("Time Sort"), &TimeSortMul10, 10, UINT_MAX, + wxEmptyString }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, wxEmptyString }, { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, @@ -763,41 +765,52 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and watch volatile ssize_t p = QuickSortSelectPivot(A, lo, hi+1); + size_t p1 = static_cast(p); - value_type pivot = A[p]; + value_type pivot = A[p1]; A.watch(&p, 2); volatile ssize_t i = lo, j = hi; + size_t j1 = static_cast(j), i1 = static_cast(i); A.watch(&i, 3); A.watch(&j, 3); - while (i <= j) + while (i1 <= j1) { - while (A[i] < pivot) - i++; + while (A[i1] < pivot) + { + i1++; + i = static_cast(i1); + } - while (A[j] > pivot) - j--; + while (A[j1] > pivot) + { + j1--; + j = static_cast(j1); + } - if (i <= j) + if (i1 <= j1) { - A.swap(i,j); + A.swap(i1, j1); // follow pivot if it is swapped - if (p == i) p = j; - else if (p == j) p = i; + if (p1 == i1) p1 = j1; + else if (p1 == j1) p1 = i1; + p = static_cast(p1); - i++, j--; + i1++, j1--; + i = static_cast(i1); + j = static_cast(j1); } } A.unwatch_all(); if (lo < j) - QuickSortLR(A, lo, j); + QuickSortLR(A, lo, static_cast(j1)); if (i < hi) - QuickSortLR(A, i, hi); + QuickSortLR(A, static_cast(i1), hi); } void QuickSortLR(SortArray& A) @@ -820,21 +833,23 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) A.mark(hi-1); volatile ssize_t i = lo; + size_t i1 = static_cast(i); A.watch(&i, 3); for (size_t j = lo; j < hi-1; ++j) { if (A[j] <= pivot) { - A.swap(i, j); - ++i; + A.swap(i1, j); + ++i1; + i = static_cast(i1); } } - A.swap(i, hi-1); + A.swap(i1, hi-1); A.unmark(hi-1); A.unwatch_all(); - return i; + return i1; } void QuickSortLL(SortArray& A, size_t lo, size_t hi) @@ -955,18 +970,21 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t A.mark(hi-1); volatile ssize_t i = lo, k = hi-1; + size_t i1 = static_cast(i), k1 = static_cast(k); A.watch(&i, 3); - for (ssize_t j = lo; j < k; ++j) + for (size_t j = lo; j < k1; ++j) { int cmp = A[j].cmp(pivot); // ternary comparison if (cmp == 0) { - A.swap(--k, j); + A.swap(--k1, j); + k = static_cast(k1); --j; // reclassify A[j] - A.mark(k,4); + A.mark(k1, 4); } else if (cmp < 0) { - A.swap(i++, j); + A.swap(i1++, j); + i = static_cast(i1); } } @@ -975,10 +993,10 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t A.unwatch_all(); ssize_t j = i + (hi-k); - - for (ssize_t s = 0; s < hi-k; ++s) { - A.swap(i+s, hi-1-s); - A.mark_swap(i+s, hi-1-s); + size_t hi1 = static_cast(hi); + for (size_t s = 0; s < hi1-k1; ++s) { + A.swap(i1 + s, hi1 - 1 - s); + A.mark_swap(i1 + s, hi1 - 1 - s); } A.unmark_all(); @@ -1023,40 +1041,51 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) volatile ssize_t l = left + 1; volatile ssize_t g = right - 1; volatile ssize_t k = l; + size_t l1 = static_cast(l), g1 = static_cast(g), k1 = static_cast(k); a.watch(&l, 3); a.watch(&g, 3); a.watch(&k, 3); - while (k <= g) + while (k1 <= g1) { - if (a[k] < p) { - a.swap(k, l); - ++l; + if (a[k1] < p) { + a.swap(k1, l1); + ++l1; + l = static_cast(l1); } - else if (a[k] >= q) { - while (a[g] > q && k < g) --g; - a.swap(k, g); - --g; - - if (a[k] < p) { - a.swap(k, l); - ++l; + else if (a[k1] >= q) { + while (a[g1] > q && k1 < g1) + { + --g1; + g = static_cast(g1); + } + a.swap(k1, g1); + --g1; + g = static_cast(g1); + + if (a[k1] < p) { + a.swap(k1, l1); + ++l1; + l = static_cast(l1); } } - ++k; + ++k1; + k = static_cast(k1); } - --l; - ++g; - a.swap(left, l); - a.swap(right, g); + --l1; + ++g1; + l = static_cast(l1); + g = static_cast(g1); + a.swap(left, l1); + a.swap(right, g1); a.unmark_all(); a.unwatch_all(); - dualPivotYaroslavskiy(a, left, l - 1); - dualPivotYaroslavskiy(a, l + 1, g - 1); - dualPivotYaroslavskiy(a, g + 1, right); + dualPivotYaroslavskiy(a, left, static_cast(l1 - 1)); + dualPivotYaroslavskiy(a, static_cast(l1 + 1), static_cast(g1 - 1)); + dualPivotYaroslavskiy(a, static_cast(g1 + 1), right); } } @@ -3065,42 +3094,50 @@ void SlowSort(SortArray& A) void CycleSort(SortArray& array, ssize_t n) { volatile ssize_t cycleStart = 0; + size_t cycleStart1 = static_cast(cycleStart), n1 = static_cast(n); array.watch(&cycleStart, 16); volatile ssize_t rank = 0; + size_t rank1 = static_cast(rank); array.watch(&rank, 3); // Loop through the array to find cycles to rotate. - for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) + for (cycleStart1 = 0; cycleStart1 < n1 - 1; ++cycleStart1) { - value_type& item = array.get_mutable(cycleStart); - + cycleStart = static_cast(cycleStart1); + value_type& item = array.get_mutable(cycleStart1); do { // Find where to put the item. - rank = cycleStart; - for (ssize_t i = cycleStart + 1; i < n; ++i) + rank1 = cycleStart1; + for (size_t i = cycleStart1 + 1; i < n1; ++i) { if (array[i] < item) - rank++; + { + rank1++; + rank = static_cast(rank1); + } } // If the item is already there, this is a 1-cycle. - if (rank == cycleStart) { - array.mark(rank, 2); + if (rank1 == cycleStart1) { + array.mark(rank1, 2); break; } // Otherwise, put the item after any duplicates. - while (item == array[rank]) - rank++; + while (item == array[rank1]) + { + rank1++; + rank = static_cast(rank1); + } // Put item into right place and colorize - counted_swap(array.get_mutable(rank), item); - array.mark(rank, 2); + counted_swap(array.get_mutable(rank1), item); + array.mark(rank1, 2); // Continue for rest of the cycle. } - while (rank != cycleStart); + while (rank1 != cycleStart1); } array.unwatch_all(); From 64e35d2fb8f0a9583e185f1c9b7135738f9bed9e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 18:54:15 +0800 Subject: [PATCH 228/289] Removed Time Sort It is still purely experimental, it might never be added. --- src/SortAlgo.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f64491eb5..043318794 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -179,8 +179,6 @@ const struct AlgoEntry g_algolist[] = _("An optimized variant of Pancake Sort that performs 1/2 as many flips.") }, { _("Adjacency Pancake Sort"), &AdjacencyPancakeSort, UINT_MAX, UINT_MAX, _("An improvement upon Pancake Sort, which performs only 5/3 N + O(1) flips.") }, - { _("Time Sort"), &TimeSortMul10, 10, UINT_MAX, - wxEmptyString }, { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, wxEmptyString }, { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, @@ -4268,4 +4266,4 @@ void sortArray(SortArray& A, int a, int b) void BufferPartitionMergeSort(SortArray& A) { sortArray(A, 0, A.size()); -} \ No newline at end of file +} From d9a84bdf7efde578bffbc1b482296b69081b498f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 20:28:39 +0800 Subject: [PATCH 229/289] Fixed ++/-- volatile warning on Quick Sort LR Ternary Also simplified ++/-- volatile warning fixes on Cycle Sort and other Quick Sort variants --- src/SortAlgo.cpp | 107 ++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 043318794..2b995f287 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -763,13 +763,13 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and watch volatile ssize_t p = QuickSortSelectPivot(A, lo, hi+1); - size_t p1 = static_cast(p); + ssize_t p1 = p; value_type pivot = A[p1]; A.watch(&p, 2); volatile ssize_t i = lo, j = hi; - size_t j1 = static_cast(j), i1 = static_cast(i); + ssize_t j1 = j, i1 = i; A.watch(&i, 3); A.watch(&j, 3); @@ -778,13 +778,13 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) while (A[i1] < pivot) { i1++; - i = static_cast(i1); + i = i1; } while (A[j1] > pivot) { j1--; - j = static_cast(j1); + j = j1; } if (i1 <= j1) @@ -794,21 +794,21 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) // follow pivot if it is swapped if (p1 == i1) p1 = j1; else if (p1 == j1) p1 = i1; - p = static_cast(p1); + p = p1; i1++, j1--; - i = static_cast(i1); - j = static_cast(j1); + i = i1; + j = j1; } } A.unwatch_all(); if (lo < j) - QuickSortLR(A, lo, static_cast(j1)); + QuickSortLR(A, lo, j1); if (i < hi) - QuickSortLR(A, static_cast(i1), hi); + QuickSortLR(A, i1, hi); } void QuickSortLR(SortArray& A) @@ -831,7 +831,7 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) A.mark(hi-1); volatile ssize_t i = lo; - size_t i1 = static_cast(i); + ssize_t i1 = i; A.watch(&i, 3); for (size_t j = lo; j < hi-1; ++j) @@ -839,7 +839,7 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) if (A[j] <= pivot) { A.swap(i1, j); ++i1; - i = static_cast(i1); + i = i1; } } @@ -887,6 +887,8 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) // schema: |p === |i <<< | ??? |j >>> |q === |piv volatile ssize_t i = lo, j = hi-1; volatile ssize_t p = lo, q = hi-1; + ssize_t i1 = i, j1 = j; + ssize_t p1 = p, q1 = q; A.watch(&i, 3); A.watch(&j, 3); @@ -894,29 +896,35 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) for (;;) { // partition on left - while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) + while (i1 <= j1 && (cmp = A[i1].cmp(pivot)) <= 0) { if (cmp == 0) { - A.mark(p,4); - A.swap(i, p++); + A.mark(p1,4); + A.swap(i1, p1++); + p = p1; } - ++i; + ++i1; + i = i1; } // partition on right - while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) + while (i1 <= j1 && (cmp = A[j1].cmp(pivot)) >= 0) { if (cmp == 0) { - A.mark(q,4); - A.swap(j, q--); + A.mark(q1,4); + A.swap(j1, q1--); + q = q1; } - --j; + --j1; + j = j1; } if (i > j) break; // swap item between < > regions - A.swap(i++, j--); + A.swap(i1++, j1--); + i = i1; + j = j1; } // swap pivot to right place @@ -927,16 +935,20 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) ssize_t num_greater = q - j; // swap equal ranges into center, but avoid swapping equal elements - j = i-1; i = i+1; + j1 = i1-1; i1 = i1+1; + i = i1; + j = j1; ssize_t pe = lo + std::min(p-lo, num_less); - for (ssize_t k = lo; k < pe; k++, j--) { + for (ssize_t k = lo; k < pe; k++, j1--) { + j = j1; A.swap(k,j); A.mark_swap(k,j); } ssize_t qe = hi-1 - std::min(hi-1-q, num_greater-1); // one already greater at end - for (ssize_t k = hi-1; k > qe; k--, i++) { + for (ssize_t k = hi-1; k > qe; k--, i1++) { + i = i1; A.swap(i,k); A.mark_swap(i,k); } @@ -968,21 +980,21 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t A.mark(hi-1); volatile ssize_t i = lo, k = hi-1; - size_t i1 = static_cast(i), k1 = static_cast(k); + ssize_t i1 = i, k1 = k; A.watch(&i, 3); - for (size_t j = lo; j < k1; ++j) + for (ssize_t j = lo; j < k1; ++j) { int cmp = A[j].cmp(pivot); // ternary comparison if (cmp == 0) { A.swap(--k1, j); - k = static_cast(k1); + k = k1; --j; // reclassify A[j] A.mark(k1, 4); } else if (cmp < 0) { A.swap(i1++, j); - i = static_cast(i1); + i = i1; } } @@ -990,11 +1002,10 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t // in the first step of the following swap loop. A.unwatch_all(); - ssize_t j = i + (hi-k); - size_t hi1 = static_cast(hi); - for (size_t s = 0; s < hi1-k1; ++s) { - A.swap(i1 + s, hi1 - 1 - s); - A.mark_swap(i1 + s, hi1 - 1 - s); + ssize_t j = i1 + (hi - k1); + for (ssize_t s = 0; s < hi - k1; ++s) { + A.swap(i1 + s, hi - 1 - s); + A.mark_swap(i1 + s, hi - 1 - s); } A.unmark_all(); @@ -1039,7 +1050,7 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) volatile ssize_t l = left + 1; volatile ssize_t g = right - 1; volatile ssize_t k = l; - size_t l1 = static_cast(l), g1 = static_cast(g), k1 = static_cast(k); + ssize_t l1 = l, g1 = g, k1 = k; a.watch(&l, 3); a.watch(&g, 3); @@ -1050,31 +1061,31 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) if (a[k1] < p) { a.swap(k1, l1); ++l1; - l = static_cast(l1); + l = l1; } else if (a[k1] >= q) { while (a[g1] > q && k1 < g1) { --g1; - g = static_cast(g1); + g = g1; } a.swap(k1, g1); --g1; - g = static_cast(g1); + g = g1; if (a[k1] < p) { a.swap(k1, l1); ++l1; - l = static_cast(l1); + l = l1; } } ++k1; - k = static_cast(k1); + k = k; } --l1; ++g1; - l = static_cast(l1); - g = static_cast(g1); + l = l1; + g = g1; a.swap(left, l1); a.swap(right, g1); @@ -3092,27 +3103,27 @@ void SlowSort(SortArray& A) void CycleSort(SortArray& array, ssize_t n) { volatile ssize_t cycleStart = 0; - size_t cycleStart1 = static_cast(cycleStart), n1 = static_cast(n); + ssize_t cycleStart1 = cycleStart; array.watch(&cycleStart, 16); volatile ssize_t rank = 0; - size_t rank1 = static_cast(rank); + ssize_t rank1 = rank; array.watch(&rank, 3); // Loop through the array to find cycles to rotate. - for (cycleStart1 = 0; cycleStart1 < n1 - 1; ++cycleStart1) + for (cycleStart1 = 0; cycleStart1 < n - 1; ++cycleStart1) { - cycleStart = static_cast(cycleStart1); + cycleStart = cycleStart1; value_type& item = array.get_mutable(cycleStart1); do { // Find where to put the item. rank1 = cycleStart1; - for (size_t i = cycleStart1 + 1; i < n1; ++i) + for (ssize_t i = cycleStart1 + 1; i < n; ++i) { if (array[i] < item) { rank1++; - rank = static_cast(rank1); + rank = rank1; } } @@ -3126,7 +3137,7 @@ void CycleSort(SortArray& array, ssize_t n) while (item == array[rank1]) { rank1++; - rank = static_cast(rank1); + rank = rank1; } // Put item into right place and colorize @@ -4266,4 +4277,4 @@ void sortArray(SortArray& A, int a, int b) void BufferPartitionMergeSort(SortArray& A) { sortArray(A, 0, A.size()); -} +} \ No newline at end of file From bd89d262c17c3c5b94e52d0a4adaf4e5bab5bead Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 31 Oct 2024 21:09:24 +0800 Subject: [PATCH 230/289] Reverted ++/-- warning fixes I have been advised that these might cause issues, the real fix is to make use of atomic instead which will take some time for me to do. In the meantime, the fixes I provided for Quick Sort and Cycle Sort has been reverted. --- src/SortAlgo.cpp | 231 +++++++++++++++++++---------------------------- 1 file changed, 92 insertions(+), 139 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 2b995f287..c0d18c7fa 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -762,53 +762,42 @@ wxArrayString QuickSortPivotText() void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and watch - volatile ssize_t p = QuickSortSelectPivot(A, lo, hi+1); - ssize_t p1 = p; + volatile ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); - value_type pivot = A[p1]; + value_type pivot = A[p]; A.watch(&p, 2); volatile ssize_t i = lo, j = hi; - ssize_t j1 = j, i1 = i; A.watch(&i, 3); A.watch(&j, 3); - while (i1 <= j1) + while (i <= j) { - while (A[i1] < pivot) - { - i1++; - i = i1; - } + while (A[i] < pivot) + i++; - while (A[j1] > pivot) - { - j1--; - j = j1; - } + while (A[j] > pivot) + j--; - if (i1 <= j1) + if (i <= j) { - A.swap(i1, j1); + A.swap(i, j); // follow pivot if it is swapped - if (p1 == i1) p1 = j1; - else if (p1 == j1) p1 = i1; - p = p1; + if (p == i) p = j; + else if (p == j) p = i; - i1++, j1--; - i = i1; - j = j1; + i++, j--; } } A.unwatch_all(); if (lo < j) - QuickSortLR(A, lo, j1); + QuickSortLR(A, lo, j); if (i < hi) - QuickSortLR(A, i1, hi); + QuickSortLR(A, i, hi); } void QuickSortLR(SortArray& A) @@ -827,27 +816,25 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) size_t p = QuickSortSelectPivot(A, lo, hi); value_type pivot = A[p]; - A.swap(p, hi-1); - A.mark(hi-1); + A.swap(p, hi - 1); + A.mark(hi - 1); volatile ssize_t i = lo; - ssize_t i1 = i; A.watch(&i, 3); - for (size_t j = lo; j < hi-1; ++j) + for (size_t j = lo; j < hi - 1; ++j) { if (A[j] <= pivot) { - A.swap(i1, j); - ++i1; - i = i1; + A.swap(i, j); + ++i; } } - A.swap(i1, hi-1); - A.unmark(hi-1); + A.swap(i, hi - 1); + A.unmark(hi - 1); A.unwatch_all(); - return i1; + return i; } void QuickSortLL(SortArray& A, size_t lo, size_t hi) @@ -878,17 +865,15 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) int cmp; // pick pivot and swap to back - ssize_t piv = QuickSortSelectPivot(A, lo, hi+1); + ssize_t piv = QuickSortSelectPivot(A, lo, hi + 1); A.swap(piv, hi); A.mark(hi); const value_type& pivot = A[hi]; // schema: |p === |i <<< | ??? |j >>> |q === |piv - volatile ssize_t i = lo, j = hi-1; - volatile ssize_t p = lo, q = hi-1; - ssize_t i1 = i, j1 = j; - ssize_t p1 = p, q1 = q; + volatile ssize_t i = lo, j = hi - 1; + volatile ssize_t p = lo, q = hi - 1; A.watch(&i, 3); A.watch(&j, 3); @@ -896,61 +881,51 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) for (;;) { // partition on left - while (i1 <= j1 && (cmp = A[i1].cmp(pivot)) <= 0) + while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) { if (cmp == 0) { - A.mark(p1,4); - A.swap(i1, p1++); - p = p1; + A.mark(p, 4); + A.swap(i, p++); } - ++i1; - i = i1; + ++i; } // partition on right - while (i1 <= j1 && (cmp = A[j1].cmp(pivot)) >= 0) + while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) { if (cmp == 0) { - A.mark(q1,4); - A.swap(j1, q1--); - q = q1; + A.mark(q, 4); + A.swap(j, q--); } - --j1; - j = j1; + --j; } if (i > j) break; // swap item between < > regions - A.swap(i1++, j1--); - i = i1; - j = j1; + A.swap(i++, j--); } // swap pivot to right place - A.swap(i,hi); - A.mark_swap(i,hi); + A.swap(i, hi); + A.mark_swap(i, hi); ssize_t num_less = i - p; ssize_t num_greater = q - j; // swap equal ranges into center, but avoid swapping equal elements - j1 = i1-1; i1 = i1+1; - i = i1; - j = j1; + j = i - 1; i = i + 1; - ssize_t pe = lo + std::min(p-lo, num_less); - for (ssize_t k = lo; k < pe; k++, j1--) { - j = j1; - A.swap(k,j); - A.mark_swap(k,j); + ssize_t pe = lo + std::min(p - lo, num_less); + for (ssize_t k = lo; k < pe; k++, j--) { + A.swap(k, j); + A.mark_swap(k, j); } - ssize_t qe = hi-1 - std::min(hi-1-q, num_greater-1); // one already greater at end - for (ssize_t k = hi-1; k > qe; k--, i1++) { - i = i1; - A.swap(i,k); - A.mark_swap(i,k); + ssize_t qe = hi - 1 - std::min(hi - 1 - q, num_greater - 1); // one already greater at end + for (ssize_t k = hi - 1; k > qe; k--, i++) { + A.swap(i, k); + A.mark_swap(i, k); } A.unwatch_all(); @@ -970,31 +945,28 @@ void QuickSortTernaryLR(SortArray& A) // by myself (Timo Bingmann) -std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) +std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and swap to back ssize_t p = QuickSortSelectPivot(A, lo, hi); value_type pivot = A[p]; - A.swap(p, hi-1); - A.mark(hi-1); + A.swap(p, hi - 1); + A.mark(hi - 1); - volatile ssize_t i = lo, k = hi-1; - ssize_t i1 = i, k1 = k; + volatile ssize_t i = lo, k = hi - 1; A.watch(&i, 3); - for (ssize_t j = lo; j < k1; ++j) + for (ssize_t j = lo; j < k; ++j) { int cmp = A[j].cmp(pivot); // ternary comparison if (cmp == 0) { - A.swap(--k1, j); - k = k1; + A.swap(--k, j); --j; // reclassify A[j] - A.mark(k1, 4); + A.mark(k, 4); } else if (cmp < 0) { - A.swap(i1++, j); - i = i1; + A.swap(i++, j); } } @@ -1002,14 +974,15 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t // in the first step of the following swap loop. A.unwatch_all(); - ssize_t j = i1 + (hi - k1); - for (ssize_t s = 0; s < hi - k1; ++s) { - A.swap(i1 + s, hi - 1 - s); - A.mark_swap(i1 + s, hi - 1 - s); + ssize_t j = i + (hi - k); + + for (ssize_t s = 0; s < hi - k; ++s) { + A.swap(i + s, hi - 1 - s); + A.mark_swap(i + s, hi - 1 - s); } A.unmark_all(); - return std::make_pair((ssize_t)i,j); + return std::make_pair((ssize_t)i, j); } void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) @@ -1050,51 +1023,40 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) volatile ssize_t l = left + 1; volatile ssize_t g = right - 1; volatile ssize_t k = l; - ssize_t l1 = l, g1 = g, k1 = k; a.watch(&l, 3); a.watch(&g, 3); a.watch(&k, 3); - while (k1 <= g1) + while (k <= g) { - if (a[k1] < p) { - a.swap(k1, l1); - ++l1; - l = l1; + if (a[k] < p) { + a.swap(k, l); + ++l; } - else if (a[k1] >= q) { - while (a[g1] > q && k1 < g1) - { - --g1; - g = g1; - } - a.swap(k1, g1); - --g1; - g = g1; - - if (a[k1] < p) { - a.swap(k1, l1); - ++l1; - l = l1; + else if (a[k] >= q) { + while (a[g] > q && k < g) --g; + a.swap(k, g); + --g; + + if (a[k] < p) { + a.swap(k, l); + ++l; } } - ++k1; - k = k; + ++k; } - --l1; - ++g1; - l = l1; - g = g1; - a.swap(left, l1); - a.swap(right, g1); + --l; + ++g; + a.swap(left, l); + a.swap(right, g); a.unmark_all(); a.unwatch_all(); - dualPivotYaroslavskiy(a, left, static_cast(l1 - 1)); - dualPivotYaroslavskiy(a, static_cast(l1 + 1), static_cast(g1 - 1)); - dualPivotYaroslavskiy(a, static_cast(g1 + 1), right); + dualPivotYaroslavskiy(a, left, l - 1); + dualPivotYaroslavskiy(a, l + 1, g - 1); + dualPivotYaroslavskiy(a, g + 1, right); } } @@ -3103,50 +3065,41 @@ void SlowSort(SortArray& A) void CycleSort(SortArray& array, ssize_t n) { volatile ssize_t cycleStart = 0; - ssize_t cycleStart1 = cycleStart; array.watch(&cycleStart, 16); volatile ssize_t rank = 0; - ssize_t rank1 = rank; array.watch(&rank, 3); // Loop through the array to find cycles to rotate. - for (cycleStart1 = 0; cycleStart1 < n - 1; ++cycleStart1) + for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) { - cycleStart = cycleStart1; - value_type& item = array.get_mutable(cycleStart1); + value_type& item = array.get_mutable(cycleStart); + do { // Find where to put the item. - rank1 = cycleStart1; - for (ssize_t i = cycleStart1 + 1; i < n; ++i) + rank = cycleStart; + for (ssize_t i = cycleStart + 1; i < n; ++i) { if (array[i] < item) - { - rank1++; - rank = rank1; - } + rank++; } // If the item is already there, this is a 1-cycle. - if (rank1 == cycleStart1) { - array.mark(rank1, 2); + if (rank == cycleStart) { + array.mark(rank, 2); break; } // Otherwise, put the item after any duplicates. - while (item == array[rank1]) - { - rank1++; - rank = rank1; - } + while (item == array[rank]) + rank++; // Put item into right place and colorize - counted_swap(array.get_mutable(rank1), item); - array.mark(rank1, 2); + std::swap(array.get_mutable(rank), item); + array.mark(rank, 2); // Continue for rest of the cycle. - } - while (rank1 != cycleStart1); + } while (rank != cycleStart); } array.unwatch_all(); From 031e5d502ba0b9489f845c53ad4c1fbaab52fcfa Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 1 Nov 2024 14:14:39 +0800 Subject: [PATCH 231/289] Added Ninthers pivot rule selection To make up for that horrible mistake, I decided to provide a new pivot rule selection known as "Ninthers", it takes 9 samples from the input array, divides the nine samples into 3 groups, get the median from these 3 groups, and then get the median of the medians of the groups. To make up for this change, Median of Three is now a separate method and it takes a middle argument. As such, Median of Three pivot selection has been adjusted for this change by now computing the middle value first, and then passing the middle value to the method, which the method will return the median. --- src/SortAlgo.cpp | 31 +++++++++++++++++++++++-------- src/SortAlgo.h | 2 +- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index c0d18c7fa..2ebce3de0 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -708,6 +708,18 @@ void WeaveMergeSort(SortArray& A) QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST; +ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) +{ + // cases if two are equal + if (A[lo] == A[mid]) return lo; + if (A[lo] == A[hi - 1] || A[mid] == A[hi - 1]) return hi - 1; + + // cases if three are different + return A[lo] < A[mid] + ? (A[mid] < A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? hi - 1 : lo)) + : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); +} + // some quicksort variants use hi inclusive and some exclusive, we require it // to be _exclusive_. hi == array.end()! ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) @@ -727,15 +739,17 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) if (g_quicksort_pivot == PIVOT_MEDIAN3) { ssize_t mid = (lo + hi) / 2; + return SingleMedianOfThree(A, lo, mid, hi); + } - // cases if two are equal - if (A[lo] == A[mid]) return lo; - if (A[lo] == A[hi-1] || A[mid] == A[hi-1]) return hi-1; - - // cases if three are different - return A[lo] < A[mid] - ? (A[mid] < A[hi-1] ? mid : (A[lo] < A[hi-1] ? hi-1 : lo)) - : (A[mid] > A[hi-1] ? mid : (A[lo] < A[hi-1] ? lo : hi-1)); + if (g_quicksort_pivot == PIVOT_NINTHER) + { + if (A.size() < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment_size = (hi - lo) / 9; + ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); + ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); + ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); + return SingleMedianOfThree(A, g1, g2, g3); } return lo; @@ -750,6 +764,7 @@ wxArrayString QuickSortPivotText() sl.Add( _("Middle Item") ); sl.Add( _("Random Item") ); sl.Add( _("Median of Three") ); + sl.Add( _("Ninthers")); return sl; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 98250cc20..8f955088a 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3 }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_NINTHER }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From e7825906e66a0fce1175c27deb05ea5e01fd8ad3 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 00:30:54 +0800 Subject: [PATCH 232/289] Added Median of Five pivot rule This essentially takes 5 sampled elements using a pre-determined formula, puts the elements into an std::array, sort the 5 elements using Insertion Sort, and then pick the element in the middle. This pivot rule should have less computational overhead than Ninther, but it is of course less accurate. --- src/SortAlgo.cpp | 38 ++++++++++++++++++++++++++++++++++++-- src/SortAlgo.h | 2 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 2ebce3de0..5ee3da24d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include typedef ArrayItem value_type; @@ -720,6 +721,21 @@ ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); } +void PivotInsertionSort(std::array& arr) +{ + for (size_t i = 1; i < arr.size(); ++i) + { + value_type key = arr[i]; + size_t j = i; + while (j >= 1 && arr[j - 1] > key) + { + arr[j] = arr[j - 1]; + --j; + } + arr[j] = key; + } +} + // some quicksort variants use hi inclusive and some exclusive, we require it // to be _exclusive_. hi == array.end()! ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) @@ -742,6 +758,23 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) return SingleMedianOfThree(A, lo, mid, hi); } + if (g_quicksort_pivot == PIVOT_MEDIAN5) + { + if (A.size() < 5) { SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 5; + ssize_t lo_mid = lo + segment, mid = lo + 2 * segment, mid_hi = lo + 3 * segment, high = lo + 4 * segment; + value_type piv_lo = A[lo], piv_lo_mid = A[lo_mid], piv_mid = A[mid], piv_mid_hi = A[mid_hi], piv_hi = A[high]; + std::array nums = { piv_lo, piv_lo_mid, piv_mid, piv_mid_hi, piv_hi }; + PivotInsertionSort(nums); + value_type p = nums[2]; // If Quick Sort asks for the pivot *element*, then this should be returned immediately + // Otherwise, check what index does p belong to + if (p == piv_lo) { return lo; } + else if (p == piv_lo_mid) { return lo_mid; } + else if (p == piv_mid) { return mid; } + else if (p == piv_mid_hi) { return mid_hi; } + else if (p == piv_hi) { return high; } + } + if (g_quicksort_pivot == PIVOT_NINTHER) { if (A.size() < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } @@ -764,7 +797,8 @@ wxArrayString QuickSortPivotText() sl.Add( _("Middle Item") ); sl.Add( _("Random Item") ); sl.Add( _("Median of Three") ); - sl.Add( _("Ninthers")); + sl.Add( _("Median of Five") ); + sl.Add( _("Ninther")); return sl; } @@ -883,7 +917,7 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) ssize_t piv = QuickSortSelectPivot(A, lo, hi + 1); A.swap(piv, hi); A.mark(hi); - + const value_type& pivot = A[hi]; // schema: |p === |i <<< | ??? |j >>> |q === |piv diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 8f955088a..9d898a2ec 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_NINTHER }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN5, PIVOT_NINTHER }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From 74b61c9ab66136086d9a92abc2d226e464b05409 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 00:35:04 +0800 Subject: [PATCH 233/289] Simplified Median of Five index condition The p element is guaranteed to be 1 of the five sampled elements, so if p doesn't match the first 4 elements, then p is definitely in the high index. --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 5ee3da24d..47d17c5d4 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -772,7 +772,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) else if (p == piv_lo_mid) { return lo_mid; } else if (p == piv_mid) { return mid; } else if (p == piv_mid_hi) { return mid_hi; } - else if (p == piv_hi) { return high; } + else { return high; } } if (g_quicksort_pivot == PIVOT_NINTHER) From 1778e0f9a9f5477926493b6fe3c4afb57f47e896 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 00:50:19 +0800 Subject: [PATCH 234/289] Simplified PivotInsertionSort logic The PivotInsertionSort has also been renamed, this is incase I might add Median of Seven From b2a124bfb513d73cd8cd51779b35c0ef079537ea Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 00:51:25 +0800 Subject: [PATCH 235/289] Simplified PivotInsertionSort logic The PivotInsertionSort has also been renamed, this is incase I might add Median of Seven --- src/SortAlgo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 47d17c5d4..dbcf13540 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -721,13 +721,13 @@ ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); } -void PivotInsertionSort(std::array& arr) +void PivotInsertionSort5(std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { value_type key = arr[i]; size_t j = i; - while (j >= 1 && arr[j - 1] > key) + while (j > 0 && arr[j - 1] > key) { arr[j] = arr[j - 1]; --j; @@ -765,7 +765,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) ssize_t lo_mid = lo + segment, mid = lo + 2 * segment, mid_hi = lo + 3 * segment, high = lo + 4 * segment; value_type piv_lo = A[lo], piv_lo_mid = A[lo_mid], piv_mid = A[mid], piv_mid_hi = A[mid_hi], piv_hi = A[high]; std::array nums = { piv_lo, piv_lo_mid, piv_mid, piv_mid_hi, piv_hi }; - PivotInsertionSort(nums); + PivotInsertionSort5(nums); value_type p = nums[2]; // If Quick Sort asks for the pivot *element*, then this should be returned immediately // Otherwise, check what index does p belong to if (p == piv_lo) { return lo; } From 445b77743f28c2c42c26e50a97d33512bc3e807f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 01:18:55 +0800 Subject: [PATCH 236/289] Small correction on PIVOT_MEDIAN5 condition --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index dbcf13540..444235679 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -760,7 +760,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) if (g_quicksort_pivot == PIVOT_MEDIAN5) { - if (A.size() < 5) { SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (A.size() < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 5; ssize_t lo_mid = lo + segment, mid = lo + 2 * segment, mid_hi = lo + 3 * segment, high = lo + 4 * segment; value_type piv_lo = A[lo], piv_lo_mid = A[lo_mid], piv_mid = A[mid], piv_mid_hi = A[mid_hi], piv_hi = A[high]; From 852dc0ad4b8748332dcc15bc67961e248bcf6329 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 15:04:30 +0800 Subject: [PATCH 237/289] Added even more pivot rules Why not Random Ninther? I tried, but it always goes out of bounds, so instead I provided a Random Median of Nine which should be a good equivalent --- src/SortAlgo.cpp | 254 +++++++++++++++++++++++++++++++++++++---------- src/SortAlgo.h | 2 +- 2 files changed, 205 insertions(+), 51 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 444235679..34966161d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -736,70 +736,224 @@ void PivotInsertionSort5(std::array& arr) } } -// some quicksort variants use hi inclusive and some exclusive, we require it -// to be _exclusive_. hi == array.end()! -ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) +void PivotInsertionSort7(std::array& arr) { - if (g_quicksort_pivot == PIVOT_FIRST) - return lo; - - if (g_quicksort_pivot == PIVOT_LAST) - return hi-1; - - if (g_quicksort_pivot == PIVOT_MID) - return (lo + hi) / 2; - - if (g_quicksort_pivot == PIVOT_RANDOM) - return lo + (rand() % (hi - lo)); - - if (g_quicksort_pivot == PIVOT_MEDIAN3) + for (size_t i = 1; i < arr.size(); ++i) { - ssize_t mid = (lo + hi) / 2; - return SingleMedianOfThree(A, lo, mid, hi); + value_type key = arr[i]; + size_t j = i; + while (j > 0 && arr[j - 1] > key) + { + arr[j] = arr[j - 1]; + --j; + } + arr[j] = key; } +} - if (g_quicksort_pivot == PIVOT_MEDIAN5) +void PivotInsertionSort9(std::array& arr) +{ + for (size_t i = 1; i < arr.size(); ++i) { - if (A.size() < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment = (hi - lo) / 5; - ssize_t lo_mid = lo + segment, mid = lo + 2 * segment, mid_hi = lo + 3 * segment, high = lo + 4 * segment; - value_type piv_lo = A[lo], piv_lo_mid = A[lo_mid], piv_mid = A[mid], piv_mid_hi = A[mid_hi], piv_hi = A[high]; - std::array nums = { piv_lo, piv_lo_mid, piv_mid, piv_mid_hi, piv_hi }; - PivotInsertionSort5(nums); - value_type p = nums[2]; // If Quick Sort asks for the pivot *element*, then this should be returned immediately - // Otherwise, check what index does p belong to - if (p == piv_lo) { return lo; } - else if (p == piv_lo_mid) { return lo_mid; } - else if (p == piv_mid) { return mid; } - else if (p == piv_mid_hi) { return mid_hi; } - else { return high; } + value_type key = arr[i]; + size_t j = i; + while (j > 0 && arr[j - 1] > key) + { + arr[j] = arr[j - 1]; + --j; + } + arr[j] = key; } +} - if (g_quicksort_pivot == PIVOT_NINTHER) +// some quicksort variants use hi inclusive and some exclusive, we require it +// to be _exclusive_. hi == array.end()! +std::random_device rd1; // Seed generator +std::mt19937 gen1(rd1()); // Mersenne Twister engine +ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) +{ + switch (g_quicksort_pivot) { - if (A.size() < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment_size = (hi - lo) / 9; - ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); - ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); - ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); - return SingleMedianOfThree(A, g1, g2, g3); - } - - return lo; + case PIVOT_FIRST: + { + return lo; + } + case PIVOT_LAST: + { + return hi - 1; + } + case PIVOT_MID: + { + return (lo + hi) / 2; + } + case PIVOT_RANDOM: + { + return lo + (rand() % (hi - lo)); + } + case PIVOT_MEDIAN3: + { + ssize_t mid = (lo + hi) / 2; + return SingleMedianOfThree(A, lo, mid, hi); + } + case PIVOT_MEDIAN3RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + case PIVOT_MEDIAN5: + { + if (A.size() < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 5; + ssize_t lo_mid = lo + segment, mid = lo + 2 * segment, mid_hi = lo + 3 * segment, high = lo + 4 * segment; + value_type piv_lo = A[lo], piv_lo_mid = A[lo_mid], piv_mid = A[mid], piv_mid_hi = A[mid_hi], piv_hi = A[high]; + std::array nums = { piv_lo, piv_lo_mid, piv_mid, piv_mid_hi, piv_hi }; + PivotInsertionSort5(nums); + value_type p = nums[2]; // If Quick Sort asks for the pivot *element*, then this should be returned immediately + // Otherwise, check what index does p belong to + if (p == piv_lo) { return lo; } + else if (p == piv_lo_mid) { return lo_mid; } + else if (p == piv_mid) { return mid; } + else if (p == piv_mid_hi) { return mid_hi; } + else { return high; } + } + case PIVOT_MEDIAN5RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (A.size() < 5) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); + value_type piv1 = A[lo1], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5]; + std::array samples = { piv1, piv2, piv3, piv4, piv5 }; + PivotInsertionSort5(samples); + value_type p = samples[2]; + if (p == piv1) { return lo1; } + else if (p == piv2) { return lo2; } + else if (p == piv3) { return lo3; } + else if (p == piv4) { return lo4; } + else { return lo5; } + } + case PIVOT_MEDIAN7: + { + if (A.size() < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 7; + ssize_t lo2 = lo + segment, lo3 = lo + segment * 2, lo4 = lo + segment * 3, lo5 = lo + segment * 4; + ssize_t lo6 = lo + segment * 5, lo7 = lo + segment * 6; + value_type piv1 = A[lo], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5], piv6 = A[lo6], piv7 = A[lo7]; + std::array samples = { piv1, piv2, piv3, piv4, piv5, piv6, piv7 }; + PivotInsertionSort7(samples); + value_type p = samples[3]; + if (p == piv1) { return lo; } + else if (p == piv2) { return lo2; } + else if (p == piv3) { return lo3; } + else if (p == piv4) { return lo4; } + else if (p == piv5) { return lo5; } + else if (p == piv6) { return lo6; } + else { return lo7; } + } + case PIVOT_MEDIAN7RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (A.size() < 7) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); + ssize_t lo6 = dist(gen1), lo7 = dist(gen1); + value_type piv1 = A[lo1], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5]; + value_type piv6 = A[lo6], piv7 = A[lo7]; + std::array samples = { piv1, piv2, piv3, piv4, piv5, piv6, piv7 }; + PivotInsertionSort7(samples); + value_type p = samples[3]; + if (p == piv1) { return lo1; } + else if (p == piv2) { return lo2; } + else if (p == piv3) { return lo3; } + else if (p == piv4) { return lo4; } + else if (p == piv5) { return lo5; } + else if (p == piv6) { return lo6; } + else { return lo7; } + } + case PIVOT_NINTHER: + { + if (A.size() < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment_size = (hi - lo) / 9; + ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); + ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); + ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); + return SingleMedianOfThree(A, g1, g2, g3); + } + case PIVOT_MEDIAN9RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (A.size() < 9) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); + ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); + value_type piv1 = A[lo1], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5]; + value_type piv6 = A[lo6], piv7 = A[lo7], piv8 = A[lo8], piv9 = A[lo9]; + std::array samples = { piv1, piv2, piv3, piv4, piv5, piv6, piv7, piv8, piv9}; + PivotInsertionSort9(samples); + value_type p = samples[5]; + if (p == piv1) { return lo1; } + else if (p == piv2) { return lo2; } + else if (p == piv3) { return lo3; } + else if (p == piv4) { return lo4; } + else if (p == piv5) { return lo5; } + else if (p == piv6) { return lo6; } + else if (p == piv7) { return lo7; } + else if (p == piv8) { return lo8; } + else { return lo9; } + } + default: + { + return lo; + } + } } wxArrayString QuickSortPivotText() { wxArrayString sl; - sl.Add( _("First Item") ); - sl.Add( _("Last Item") ); - sl.Add( _("Middle Item") ); - sl.Add( _("Random Item") ); - sl.Add( _("Median of Three") ); - sl.Add( _("Median of Five") ); - sl.Add( _("Ninther")); - + sl.Add(_("First Item")); + sl.Add(_("Last Item")); + sl.Add(_("Middle Item")); + sl.Add(_("Random Item")); + sl.Add(_("Median of Three")); + sl.Add(_("Random Median of Three")); + sl.Add(_("Median of Five")); + sl.Add(_("Random Median of Five")); + sl.Add(_("Median of Seven")); + sl.Add(_("Random Median of Seven")); + sl.Add(_("Ninther")); + sl.Add(_("Random Median of Nine")); return sl; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 9d898a2ec..5bb8120a1 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN5, PIVOT_NINTHER }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_MEDIAN9RANDOM }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From a865632ba2353ccb580b0174f174bff33523f3e0 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 16:12:15 +0800 Subject: [PATCH 238/289] Added Random Ninther Credits to @Flainlaina and @arctic in "The Studio" Discord for leading me to the right way, Random Ninther has now been added and it is ensured to never go out of bounds. --- src/SortAlgo.cpp | 21 +++++++++++++++++++++ src/SortAlgo.h | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 34966161d..0d2c09745 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -901,6 +901,26 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); return SingleMedianOfThree(A, g1, g2, g3); } + case PIVOT_RANDOMNINTHER: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (A.size() < 9) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); + ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); + ssize_t g1 = SingleMedianOfThree(A, lo1, lo2, lo3 + 1); + ssize_t g2 = SingleMedianOfThree(A, lo4, lo5, lo6 + 1); + ssize_t g3 = SingleMedianOfThree(A, lo7, lo8, lo9 + 1); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } case PIVOT_MEDIAN9RANDOM: { if (lo > hi) @@ -953,6 +973,7 @@ wxArrayString QuickSortPivotText() sl.Add(_("Median of Seven")); sl.Add(_("Random Median of Seven")); sl.Add(_("Ninther")); + sl.Add(_("Random Ninther")); sl.Add(_("Random Median of Nine")); return sl; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 5bb8120a1..ed0806a91 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_MEDIAN9RANDOM }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9RANDOM }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From bfde9b883e24fcf19cee098e831a7abd169df268 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 16:33:41 +0800 Subject: [PATCH 239/289] Provided correction on Ninther --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 0d2c09745..83eeebbdd 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -899,7 +899,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); - return SingleMedianOfThree(A, g1, g2, g3); + return SingleMedianOfThree(A, g1, g2, g3 + 1); } case PIVOT_RANDOMNINTHER: { From da91dc514eba7e7311ffd28ba7ff01a15335ffd1 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 22:24:29 +0800 Subject: [PATCH 240/289] Optimized pivot lookup for all the new Median of N The previous implementations of all the new Median of N keeps the pivot elements directly onto the copy vector, and sorts it, and then checks the index of the element in the middle of the copy vector. I realized that this approach is horribly slow particularly for even larger Median of N, such as Median of Nine, which requires 9 additional conditions just to check what index does the middle pivot belong to. With this new approach, the indices will now be kept instead of the elements themselves, and the Insertion Sort methods used to sort the elements before has now been adjusted to sort the indices based on their values in the original array. With this approach, all Median of N after Median of Three should now have an even more streamlined approach, and it should be way more efficient now, since after the Insertion Sort is done, the value in the middle of copy vector is returned immediately, no more checking. This approach is suitable since in this project, all Quick Sort implementations need the pivot index, not the pivot element. --- src/SortAlgo.cpp | 97 ++++++++++++------------------------------------ 1 file changed, 24 insertions(+), 73 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 83eeebbdd..fad2539ad 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -721,13 +721,13 @@ ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); } -void PivotInsertionSort5(std::array& arr) +void PivotInsertionSort5(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { - value_type key = arr[i]; + ssize_t key = arr[i]; size_t j = i; - while (j > 0 && arr[j - 1] > key) + while (j > 0 && A[arr[j - 1]] > A[key]) { arr[j] = arr[j - 1]; --j; @@ -736,13 +736,13 @@ void PivotInsertionSort5(std::array& arr) } } -void PivotInsertionSort7(std::array& arr) +void PivotInsertionSort7(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { - value_type key = arr[i]; + ssize_t key = arr[i]; size_t j = i; - while (j > 0 && arr[j - 1] > key) + while (j > 0 && A[arr[j - 1]] > A[key]) { arr[j] = arr[j - 1]; --j; @@ -751,13 +751,13 @@ void PivotInsertionSort7(std::array& arr) } } -void PivotInsertionSort9(std::array& arr) +void PivotInsertionSort9(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { - value_type key = arr[i]; + ssize_t key = arr[i]; size_t j = i; - while (j > 0 && arr[j - 1] > key) + while (j > 0 && A[arr[j - 1]] > A[key]) { arr[j] = arr[j - 1]; --j; @@ -810,17 +810,9 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) { if (A.size() < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 5; - ssize_t lo_mid = lo + segment, mid = lo + 2 * segment, mid_hi = lo + 3 * segment, high = lo + 4 * segment; - value_type piv_lo = A[lo], piv_lo_mid = A[lo_mid], piv_mid = A[mid], piv_mid_hi = A[mid_hi], piv_hi = A[high]; - std::array nums = { piv_lo, piv_lo_mid, piv_mid, piv_mid_hi, piv_hi }; - PivotInsertionSort5(nums); - value_type p = nums[2]; // If Quick Sort asks for the pivot *element*, then this should be returned immediately - // Otherwise, check what index does p belong to - if (p == piv_lo) { return lo; } - else if (p == piv_lo_mid) { return lo_mid; } - else if (p == piv_mid) { return mid; } - else if (p == piv_mid_hi) { return mid_hi; } - else { return high; } + std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; + PivotInsertionSort5(A, nums); + return nums[2]; } case PIVOT_MEDIAN5RANDOM: { @@ -835,34 +827,17 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); - value_type piv1 = A[lo1], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5]; - std::array samples = { piv1, piv2, piv3, piv4, piv5 }; - PivotInsertionSort5(samples); - value_type p = samples[2]; - if (p == piv1) { return lo1; } - else if (p == piv2) { return lo2; } - else if (p == piv3) { return lo3; } - else if (p == piv4) { return lo4; } - else { return lo5; } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotInsertionSort5(A, samples); + return samples[2]; } case PIVOT_MEDIAN7: { if (A.size() < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 7; - ssize_t lo2 = lo + segment, lo3 = lo + segment * 2, lo4 = lo + segment * 3, lo5 = lo + segment * 4; - ssize_t lo6 = lo + segment * 5, lo7 = lo + segment * 6; - value_type piv1 = A[lo], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5], piv6 = A[lo6], piv7 = A[lo7]; - std::array samples = { piv1, piv2, piv3, piv4, piv5, piv6, piv7 }; - PivotInsertionSort7(samples); - value_type p = samples[3]; - if (p == piv1) { return lo; } - else if (p == piv2) { return lo2; } - else if (p == piv3) { return lo3; } - else if (p == piv4) { return lo4; } - else if (p == piv5) { return lo5; } - else if (p == piv6) { return lo6; } - else { return lo7; } + std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; + PivotInsertionSort7(A, samples); + return samples[3]; } case PIVOT_MEDIAN7RANDOM: { @@ -877,20 +852,9 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); - ssize_t lo6 = dist(gen1), lo7 = dist(gen1); - value_type piv1 = A[lo1], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5]; - value_type piv6 = A[lo6], piv7 = A[lo7]; - std::array samples = { piv1, piv2, piv3, piv4, piv5, piv6, piv7 }; - PivotInsertionSort7(samples); - value_type p = samples[3]; - if (p == piv1) { return lo1; } - else if (p == piv2) { return lo2; } - else if (p == piv3) { return lo3; } - else if (p == piv4) { return lo4; } - else if (p == piv5) { return lo5; } - else if (p == piv6) { return lo6; } - else { return lo7; } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotInsertionSort7(A, samples); + return samples[3]; } case PIVOT_NINTHER: { @@ -934,22 +898,9 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); - ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); - value_type piv1 = A[lo1], piv2 = A[lo2], piv3 = A[lo3], piv4 = A[lo4], piv5 = A[lo5]; - value_type piv6 = A[lo6], piv7 = A[lo7], piv8 = A[lo8], piv9 = A[lo9]; - std::array samples = { piv1, piv2, piv3, piv4, piv5, piv6, piv7, piv8, piv9}; - PivotInsertionSort9(samples); - value_type p = samples[5]; - if (p == piv1) { return lo1; } - else if (p == piv2) { return lo2; } - else if (p == piv3) { return lo3; } - else if (p == piv4) { return lo4; } - else if (p == piv5) { return lo5; } - else if (p == piv6) { return lo6; } - else if (p == piv7) { return lo7; } - else if (p == piv8) { return lo8; } - else { return lo9; } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotInsertionSort9(A, samples); + return samples[5]; } default: { From e4bb158a3e4ce34e3dee0c41907ab02a31ca3097 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 2 Nov 2024 22:51:12 +0800 Subject: [PATCH 241/289] Small correction on Random Median of Nine --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index fad2539ad..0a85c525a 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -900,7 +900,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort9(A, samples); - return samples[5]; + return samples[4]; } default: { From 51852655c3e8e382ccfeec3290acc6bfdba99cd2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 02:06:41 +0800 Subject: [PATCH 242/289] Improved performance on all higher Median of N pivot rule If a Median of N receives an array size or the high and low bounds are below its expected range (5 for Median of Five, 7 for Median of Seven...), the pivot rule will now fall back to Median of Three to avoid clustering and to improve performance. --- src/SortAlgo.cpp | 23 ++++++++++++++++------- src/SortAlgo.h | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 0a85c525a..abe22adbc 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -808,7 +808,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN5: { - if (A.size() < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 5; std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; PivotInsertionSort5(A, nums); @@ -823,7 +823,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (A.size() < 5) + if (hi - lo < 5) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -833,7 +833,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN7: { - if (A.size() < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 7; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; PivotInsertionSort7(A, samples); @@ -848,7 +848,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (A.size() < 7) + if (hi - lo < 7) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -858,7 +858,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_NINTHER: { - if (A.size() < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment_size = (hi - lo) / 9; ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); @@ -874,7 +874,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (A.size() < 9) + if (hi - lo < 9) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -885,6 +885,14 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) ssize_t g3 = SingleMedianOfThree(A, lo7, lo8, lo9 + 1); return SingleMedianOfThree(A, g1, g2, g3 + 1); } + case PIVOT_MEDIAN9: + { + if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 9; + std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8 }; + PivotInsertionSort9(A, samples); + return samples[4]; + } case PIVOT_MEDIAN9RANDOM: { if (lo > hi) @@ -894,7 +902,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (A.size() < 9) + if (hi - lo < 9) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -925,6 +933,7 @@ wxArrayString QuickSortPivotText() sl.Add(_("Random Median of Seven")); sl.Add(_("Ninther")); sl.Add(_("Random Ninther")); + sl.Add(_("Median of Nine")); sl.Add(_("Random Median of Nine")); return sl; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index ed0806a91..58ebc2441 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9RANDOM }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From 9f52a95e7d09cdefacc8da04f87e4cdfbb820a5e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 03:49:42 +0800 Subject: [PATCH 243/289] Prioritized fallback to Median of Three condition This changing should avoid declaring the uniform_int_distribution entirely if it is not going to be used due to the fallback condition, slightly reducing overhead even more. --- src/SortAlgo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index abe22adbc..3325d8436 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -822,11 +822,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } - std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 5) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } + std::uniform_int_distribution dist(lo, hi - 1); std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort5(A, samples); return samples[2]; @@ -847,11 +847,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } - std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 7) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } + std::uniform_int_distribution dist(lo, hi - 1); std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort7(A, samples); return samples[3]; @@ -873,11 +873,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } - std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 9) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } + std::uniform_int_distribution dist(lo, hi - 1); ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); ssize_t g1 = SingleMedianOfThree(A, lo1, lo2, lo3 + 1); @@ -901,11 +901,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } - std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 9) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } + std::uniform_int_distribution dist(lo, hi - 1); std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort9(A, samples); return samples[4]; From 0c1ef8092c040c697ab77c75c7a472b2f4c65742 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 03:53:02 +0800 Subject: [PATCH 244/289] Reverted changes My bad! I am sleepy while reading the code --- src/SortAlgo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 3325d8436..abe22adbc 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -822,11 +822,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } + std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 5) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - std::uniform_int_distribution dist(lo, hi - 1); std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort5(A, samples); return samples[2]; @@ -847,11 +847,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } + std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 7) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - std::uniform_int_distribution dist(lo, hi - 1); std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort7(A, samples); return samples[3]; @@ -873,11 +873,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } + std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 9) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - std::uniform_int_distribution dist(lo, hi - 1); ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); ssize_t g1 = SingleMedianOfThree(A, lo1, lo2, lo3 + 1); @@ -901,11 +901,11 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) lo = hi; hi = temp; } + std::uniform_int_distribution dist(lo, hi - 1); if (hi - lo < 9) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } - std::uniform_int_distribution dist(lo, hi - 1); std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; PivotInsertionSort9(A, samples); return samples[4]; From 289b303ab433b5896abbde71337e11d97e225c91 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 16:13:01 +0800 Subject: [PATCH 245/289] Flan Sort will now use the random_device and mt19937 of SortAlgo.cpp --- src/algorithms/flansort.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algorithms/flansort.cpp b/src/algorithms/flansort.cpp index c863b3287..a1962e491 100644 --- a/src/algorithms/flansort.cpp +++ b/src/algorithms/flansort.cpp @@ -46,8 +46,8 @@ const int MIN_INSERT = 32; const int G = 7; const int R = 3; -std::random_device rd; -std::mt19937 eng(rd()); +extern std::random_device rd1; +extern std::mt19937 gen1; void shiftBW(SortArray& A, int a, int m, int b) { @@ -66,7 +66,7 @@ int randGapSearch(SortArray& A, int a, int b, int val) else if (randCnt++ < 1) { std::uniform_int_distribution<> distr(0, ((b - a) / s) - 1); - m = a + distr(eng) * s; + m = a + distr(gen1) * s; ele = A[m].get(); if (val < ele) { b = m; } else if (val > ele) { a = m + s; } From 52a34aa61945d16ecaa38731871da784df3d9218 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 16:13:56 +0800 Subject: [PATCH 246/289] Minor code cleanup Also made Median of Five and Ninther modular, in preparation for Median of Fifteen and Median of Three Ninther --- src/SortAlgo.cpp | 49 ++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index abe22adbc..edf73202d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -196,6 +196,9 @@ const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; +std::random_device rd1; +std::mt19937 gen1(rd1()); + // **************************************************************************** // *** Selection Sort @@ -709,7 +712,7 @@ void WeaveMergeSort(SortArray& A) QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST; -ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) +static ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) { // cases if two are equal if (A[lo] == A[mid]) return lo; @@ -721,7 +724,7 @@ ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); } -void PivotInsertionSort5(SortArray& A, std::array& arr) +static void PivotInsertionSort5(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { @@ -736,7 +739,7 @@ void PivotInsertionSort5(SortArray& A, std::array& arr) } } -void PivotInsertionSort7(SortArray& A, std::array& arr) +static void PivotInsertionSort7(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { @@ -751,7 +754,7 @@ void PivotInsertionSort7(SortArray& A, std::array& arr) } } -void PivotInsertionSort9(SortArray& A, std::array& arr) +static void PivotInsertionSort9(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { @@ -766,10 +769,27 @@ void PivotInsertionSort9(SortArray& A, std::array& arr) } } +static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 5; + std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; + PivotInsertionSort5(A, nums); + return nums[2]; +} + +static ssize_t NintherPivot(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment_size = (hi - lo) / 9; + ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); + ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); + ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); + return SingleMedianOfThree(A, g1, g2, g3 + 1); +} + // some quicksort variants use hi inclusive and some exclusive, we require it // to be _exclusive_. hi == array.end()! -std::random_device rd1; // Seed generator -std::mt19937 gen1(rd1()); // Mersenne Twister engine ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) { switch (g_quicksort_pivot) @@ -808,11 +828,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN5: { - if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment = (hi - lo) / 5; - std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; - PivotInsertionSort5(A, nums); - return nums[2]; + return MedianOfFive(A, lo, hi); } case PIVOT_MEDIAN5RANDOM: { @@ -858,12 +874,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_NINTHER: { - if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment_size = (hi - lo) / 9; - ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); - ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); - ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); - return SingleMedianOfThree(A, g1, g2, g3 + 1); + return NintherPivot(A, lo, hi); } case PIVOT_RANDOMNINTHER: { @@ -2271,9 +2282,7 @@ void BogoSort(SortArray& A) if (BogoCheckSorted(A)) break; // pick a random permutation of indexes - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(perm.begin(), perm.end(), g); + std::shuffle(perm.begin(), perm.end(), gen1); // permute array in-place std::vector pmark(A.size(), 0); From 4961d069c4ffbafd8672f6acce9533d779a018c6 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 16:58:06 +0800 Subject: [PATCH 247/289] Added Median of Fifteen and Median of Three Ninther Inspired by the Median of Fifteen in Flux Sort by @Scandum, and Median of Three Ninther in Flan Sort by @aphitorite and @Flanlaina --- src/SortAlgo.cpp | 20 ++++++++++++++++++++ src/SortAlgo.h | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index edf73202d..583086a80 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -921,6 +921,24 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) PivotInsertionSort9(A, samples); return samples[4]; } + case PIVOT_MEDIAN15: + { + if (hi - lo < 15) { return MedianOfFive(A, lo, hi); } + ssize_t segment = (hi - lo) / 3; + ssize_t g1 = MedianOfFive(A, lo, lo + segment); + ssize_t g2 = MedianOfFive(A, lo + segment, lo + segment * 2); + ssize_t g3 = MedianOfFive(A, lo + segment * 2, hi); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } + case PIVOT_THREENINTHER: + { + if (hi - lo < 27) { return NintherPivot(A, lo, hi); } + ssize_t segment = (hi - lo) / 3; + ssize_t g1 = NintherPivot(A, lo, lo + segment); + ssize_t g2 = NintherPivot(A, lo + segment, lo + segment * 2); + ssize_t g3 = NintherPivot(A, lo + segment * 2, hi); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } default: { return lo; @@ -946,6 +964,8 @@ wxArrayString QuickSortPivotText() sl.Add(_("Random Ninther")); sl.Add(_("Median of Nine")); sl.Add(_("Random Median of Nine")); + sl.Add(_("Median of Fifteen")); + sl.Add(_("Median of Three Ninther")); return sl; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 58ebc2441..f2d1311ee 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM, PIVOT_MEDIAN15, PIVOT_THREENINTHER }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From 0d34bb4f732f2398f2a8eb9ff36d6ad4bcb4d017 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sun, 3 Nov 2024 19:01:58 +0800 Subject: [PATCH 248/289] Removed duplicate PivotInsertionSort() methods --- src/SortAlgo.cpp | 45 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 583086a80..6bf7d0850 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -724,37 +724,8 @@ static ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_ : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); } -static void PivotInsertionSort5(SortArray& A, std::array& arr) -{ - for (size_t i = 1; i < arr.size(); ++i) - { - ssize_t key = arr[i]; - size_t j = i; - while (j > 0 && A[arr[j - 1]] > A[key]) - { - arr[j] = arr[j - 1]; - --j; - } - arr[j] = key; - } -} - -static void PivotInsertionSort7(SortArray& A, std::array& arr) -{ - for (size_t i = 1; i < arr.size(); ++i) - { - ssize_t key = arr[i]; - size_t j = i; - while (j > 0 && A[arr[j - 1]] > A[key]) - { - arr[j] = arr[j - 1]; - --j; - } - arr[j] = key; - } -} - -static void PivotInsertionSort9(SortArray& A, std::array& arr) +template +static void PivotInsertionSort(SortArray& A, std::array& arr) { for (size_t i = 1; i < arr.size(); ++i) { @@ -774,7 +745,7 @@ static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 5; std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; - PivotInsertionSort5(A, nums); + PivotInsertionSort(A, nums); return nums[2]; } @@ -844,7 +815,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; - PivotInsertionSort5(A, samples); + PivotInsertionSort(A, samples); return samples[2]; } case PIVOT_MEDIAN7: @@ -852,7 +823,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) if (hi - lo < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 7; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; - PivotInsertionSort7(A, samples); + PivotInsertionSort(A, samples); return samples[3]; } case PIVOT_MEDIAN7RANDOM: @@ -869,7 +840,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; - PivotInsertionSort7(A, samples); + PivotInsertionSort(A, samples); return samples[3]; } case PIVOT_NINTHER: @@ -901,7 +872,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 9; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8 }; - PivotInsertionSort9(A, samples); + PivotInsertionSort(A, samples); return samples[4]; } case PIVOT_MEDIAN9RANDOM: @@ -918,7 +889,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; - PivotInsertionSort9(A, samples); + PivotInsertionSort(A, samples); return samples[4]; } case PIVOT_MEDIAN15: From 9cf84fa14440ca311cf516246078d096dcf3930d Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 4 Nov 2024 01:36:07 +0800 Subject: [PATCH 249/289] Minor improvement on PivotInsertionSort() Instead of calling arr.size(), the loop will now use the constant N for loop checking. --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 6bf7d0850..1144e91a4 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -727,7 +727,7 @@ static ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_ template static void PivotInsertionSort(SortArray& A, std::array& arr) { - for (size_t i = 1; i < arr.size(); ++i) + for (size_t i = 1; i < N; ++i) { ssize_t key = arr[i]; size_t j = i; From 092383a76a0be1b7375a34ffc275e1d4f352139f Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 4 Nov 2024 13:32:59 +0800 Subject: [PATCH 250/289] Fixed volatile ++/-- warning in C++20 This change makes watch() (and m_watch) to not expect a volatile variable anymore. Apparently, even if watch() receives a non-volatile variable, it still works just fine, this can be observed on all sorting algorithms that use watch() to track an index in real-time. Credits to @Morwenn for guiding me here. The volatile keyword is supposed to be used if the data that a variable contains could change outside of the program, which only happens on low-level, such as handling hardware addresses and registers. To be honest, I really don't think that say, p, a pivot index in Quick Sort, might be changed outside of the program's knowledge for watch() to really need a volatile index. The volatile keyword has a very specific use case now, and if it is going to be used for "multi-threading" purposes, std::atomic must be used instead as this will provide a true guarantee on multi-threaded environments. The volatile keyword only enforces a reread on memory, but it doesn't really protect from deadlocks or data races. Hence, the volatile keyword here is pointless. It doesn't do its job completely well for multi-threading, if that is the purpose of volatile keyword here. If the purpose of the volatile keyword instead is to indicate that the data watch() and m_watch() might change outside of the program instead, then it is also pointless as that should never happen unless the program experiences some form of data corruption or perhaps, the program was hacked or had its values manipulated externally, which should never happen anyway in most cases too. This change will allow the project to compile without warnings on C++20, if it is desired to truly make watch() and m_watch expect a volatile keyword, then a volatile copy must be used alongside non-volatile copies every time watch() will be used, but this is too much work, extra variables will be declared which is a waste of memory, and it is not a true fix. The true fix is to use std::atomic as already mentioned above. --- src/SortAlgo.cpp | 32 ++++++++++++++++---------------- src/SortArray.cpp | 3 ++- src/SortArray.h | 7 +++---- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 1144e91a4..54d39b3e6 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -206,8 +206,8 @@ void DoubleSelectionSort(SortArray& A) { size_t left = 0; size_t right = A.size() - 1, n = right; - volatile ssize_t max_idx = 0; - volatile ssize_t low_idx = 0; + ssize_t max_idx = 0; + ssize_t low_idx = 0; A.watch(&max_idx, 4); A.watch(&low_idx, 5); while (left < right) @@ -242,7 +242,7 @@ void DoubleSelectionSort(SortArray& A) void SelectionSort(SortArray& A) { - volatile ssize_t jMin = 0; + ssize_t jMin = 0; A.watch(&jMin, 3); for (size_t i = 0; i < A.size()-1; ++i) @@ -948,12 +948,12 @@ wxArrayString QuickSortPivotText() void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and watch - volatile ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); + ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); value_type pivot = A[p]; A.watch(&p, 2); - volatile ssize_t i = lo, j = hi; + ssize_t i = lo, j = hi; A.watch(&i, 3); A.watch(&j, 3); @@ -1005,7 +1005,7 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) A.swap(p, hi - 1); A.mark(hi - 1); - volatile ssize_t i = lo; + ssize_t i = lo; A.watch(&i, 3); for (size_t j = lo; j < hi - 1; ++j) @@ -1058,8 +1058,8 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) const value_type& pivot = A[hi]; // schema: |p === |i <<< | ??? |j >>> |q === |piv - volatile ssize_t i = lo, j = hi - 1; - volatile ssize_t p = lo, q = hi - 1; + ssize_t i = lo, j = hi - 1; + ssize_t p = lo, q = hi - 1; A.watch(&i, 3); A.watch(&j, 3); @@ -1140,7 +1140,7 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t A.swap(p, hi - 1); A.mark(hi - 1); - volatile ssize_t i = lo, k = hi - 1; + ssize_t i = lo, k = hi - 1; A.watch(&i, 3); for (ssize_t j = lo; j < k; ++j) @@ -1206,9 +1206,9 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) a.mark(left); a.mark(right); - volatile ssize_t l = left + 1; - volatile ssize_t g = right - 1; - volatile ssize_t k = l; + ssize_t l = left + 1; + ssize_t g = right - 1; + ssize_t k = l; a.watch(&l, 3); a.watch(&g, 3); @@ -3248,11 +3248,11 @@ void SlowSort(SortArray& A) void CycleSort(SortArray& array, ssize_t n) { - volatile ssize_t cycleStart = 0; + ssize_t cycleStart = 0; array.watch(&cycleStart, 16); - volatile ssize_t rank = 0; - array.watch(&rank, 3); + ssize_t rank = 0; + array.watch(&rank, 5); // Loop through the array to find cycles to rotate. for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) @@ -3279,7 +3279,7 @@ void CycleSort(SortArray& array, ssize_t n) rank++; // Put item into right place and colorize - std::swap(array.get_mutable(rank), item); + counted_swap(array.get_mutable(rank), item); array.mark(rank, 2); // Continue for rest of the cycle. diff --git a/src/SortArray.cpp b/src/SortArray.cpp index f28626d35..cbe8074db 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -928,7 +928,8 @@ unsigned short SortArray::InWatchList(ssize_t idx) const if (m_watch[i].first == nullptr) continue; // compare watched value - if (*m_watch[i].first != idx) continue; + // std::atomic_ref(*m_watch[i].first).load() <-- C++20 + if (*m_watch[i].first!= idx) continue; return m_watch[i].second; } diff --git a/src/SortArray.h b/src/SortArray.h index eb01edd4e..1be1bc4cc 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -313,7 +313,7 @@ class SortArray std::vector m_mark; /// custom watched index pointers in the array, set by algorithm - std::vector< std::pair > m_watch; + std::vector< std::pair > m_watch; /// flag for sorted array bool m_is_sorted; @@ -572,9 +572,8 @@ class SortArray m_access_list.clear(); } - /// Highly experimental method to _track_ array live indexes. For this, the - /// index must be marked volatile!. - void watch(volatile ssize_t* idxptr, unsigned char color = 2) + // Highly experimental method to _track_ array live indexes. + void watch(ssize_t* idxptr, unsigned char color = 2) { wxMutexLocker lock(m_mutex); ASSERT(lock.IsOk()); From dd5c95424197e432949d19dd5a6d76c29fb7d415 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 4 Nov 2024 21:24:32 +0800 Subject: [PATCH 251/289] watch() and m_watch will now hold std::atomic After a lot of research and some consultation, I landed into the conclusion that in exchange for volatile, std::atomic will be used. This will allow watch() to certainly be thread-safe as std::atomic prevents data races, thread access conflicts, and similar issues. This will make watch() "slightly" harder to use since it will now require an std::atomic, but using std::atomic isn't too hard, and this will also help the program meet the standards of higher C++ compiler versions. Due to this change, all sorting algorithms that use watch() now has a dedicated std::atomic to be used for watch(). Some sorting algorithms such as Quick Sort might have to use std::atomic entirely, but since all sorting algorithms here are single-threaded only, it is most likely not needed. What matters is that watch() is now thread-safe, which is what volatile is most likely meant for, but it is not fit for that purpose. --- src/SortAlgo.cpp | 117 +++++++++++++++++++++++++++++++++++----------- src/SortArray.cpp | 5 +- src/SortArray.h | 10 ++-- 3 files changed, 97 insertions(+), 35 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 54d39b3e6..b6a13d515 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -208,8 +208,11 @@ void DoubleSelectionSort(SortArray& A) size_t right = A.size() - 1, n = right; ssize_t max_idx = 0; ssize_t low_idx = 0; - A.watch(&max_idx, 4); - A.watch(&low_idx, 5); + std::atomic max_i, low_i; + max_i.store(max_idx); + low_i.store(low_idx); + A.watch(&max_i, 4); + A.watch(&low_i, 5); while (left < right) { max_idx = right; @@ -220,11 +223,13 @@ void DoubleSelectionSort(SortArray& A) { A.mark_swap(i, low_idx); low_idx = i; + low_i.store(i); } else if (A[i] > A[max_idx]) { A.mark_swap(i, max_idx); max_idx = i; + max_i.store(i); } } A.swap(left, low_idx); @@ -243,17 +248,21 @@ void DoubleSelectionSort(SortArray& A) void SelectionSort(SortArray& A) { ssize_t jMin = 0; - A.watch(&jMin, 3); + std::atomic kMin; + kMin.store(jMin); + A.watch(&kMin, 3); for (size_t i = 0; i < A.size()-1; ++i) { jMin = i; + kMin.store(jMin); for (size_t j = i+1; j < A.size(); ++j) { if (A[j] < A[jMin]) { A.mark_swap(j, jMin); jMin = j; + kMin.store(jMin); } } @@ -949,21 +958,32 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and watch ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); + std::atomic p1, i1, j1; value_type pivot = A[p]; - A.watch(&p, 2); + p1.store(p); + A.watch(&p1, 2); ssize_t i = lo, j = hi; - A.watch(&i, 3); - A.watch(&j, 3); + i1.store(i); + j1.store(j); + A.watch(&i1, 3); + A.watch(&j1, 3); while (i <= j) { while (A[i] < pivot) + { i++; + i1.store(i); + } + while (A[j] > pivot) + { j--; + j1.store(j); + } if (i <= j) { @@ -972,8 +992,11 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) // follow pivot if it is swapped if (p == i) p = j; else if (p == j) p = i; + p1.store(p); i++, j--; + i1.store(i); + j1.store(j); } } @@ -1006,13 +1029,16 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) A.mark(hi - 1); ssize_t i = lo; - A.watch(&i, 3); + std::atomic i1; + i1.store(i); + A.watch(&i1, 3); for (size_t j = lo; j < hi - 1; ++j) { if (A[j] <= pivot) { A.swap(i, j); ++i; + i1.store(i); } } @@ -1060,9 +1086,11 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) // schema: |p === |i <<< | ??? |j >>> |q === |piv ssize_t i = lo, j = hi - 1; ssize_t p = lo, q = hi - 1; - - A.watch(&i, 3); - A.watch(&j, 3); + std::atomic i1, j1; + i1.store(i); + j1.store(j); + A.watch(&i1, 3); + A.watch(&j1, 3); for (;;) { @@ -1074,6 +1102,7 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) A.swap(i, p++); } ++i; + i1.store(i); } // partition on right @@ -1084,12 +1113,15 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) A.swap(j, q--); } --j; + j1.store(j); } if (i > j) break; // swap item between < > regions A.swap(i++, j--); + i1.store(i); + j1.store(j); } // swap pivot to right place @@ -1101,15 +1133,19 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) // swap equal ranges into center, but avoid swapping equal elements j = i - 1; i = i + 1; + i1.store(i); + j1.store(j); ssize_t pe = lo + std::min(p - lo, num_less); for (ssize_t k = lo; k < pe; k++, j--) { + j1.store(j); A.swap(k, j); A.mark_swap(k, j); } ssize_t qe = hi - 1 - std::min(hi - 1 - q, num_greater - 1); // one already greater at end for (ssize_t k = hi - 1; k > qe; k--, i++) { + i1.store(i); A.swap(i, k); A.mark_swap(i, k); } @@ -1141,7 +1177,9 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t A.mark(hi - 1); ssize_t i = lo, k = hi - 1; - A.watch(&i, 3); + std::atomic i1; + i1.store(i); + A.watch(&i1, 3); for (ssize_t j = lo; j < k; ++j) { @@ -1153,6 +1191,7 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t } else if (cmp < 0) { A.swap(i++, j); + i1.store(i); } } @@ -1209,31 +1248,44 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) ssize_t l = left + 1; ssize_t g = right - 1; ssize_t k = l; + std::atomic l1, g1, k1; + l1.store(l); + g1.store(g); + k1.store(k); - a.watch(&l, 3); - a.watch(&g, 3); - a.watch(&k, 3); + a.watch(&l1, 3); + a.watch(&g1, 3); + a.watch(&k1, 3); while (k <= g) { if (a[k] < p) { a.swap(k, l); ++l; + l1.store(l); } else if (a[k] >= q) { - while (a[g] > q && k < g) --g; + while (a[g] > q && k < g) + { + --g; + g1.store(g); + } a.swap(k, g); - --g; - + --g; + g1.store(g); if (a[k] < p) { a.swap(k, l); ++l; + l1.store(l); } } ++k; + k1.store(k); } --l; ++g; + l1.store(l); + g1.store(g); a.swap(left, l); a.swap(right, g); @@ -3246,47 +3298,56 @@ void SlowSort(SortArray& A) // Adapted from http://en.wikipedia.org/wiki/Cycle_sort -void CycleSort(SortArray& array, ssize_t n) +void CycleSort(SortArray& vec_arr, ssize_t n) { + std::atomic cStart, cRank; ssize_t cycleStart = 0; - array.watch(&cycleStart, 16); + cStart.store(cycleStart); + vec_arr.watch(&cStart, 16); ssize_t rank = 0; - array.watch(&rank, 5); + cRank.store(rank); + vec_arr.watch(&cRank, 5); // Loop through the array to find cycles to rotate. for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) { - value_type& item = array.get_mutable(cycleStart); - + value_type& item = vec_arr.get_mutable(cycleStart); + cStart.store(cycleStart); do { // Find where to put the item. rank = cycleStart; for (ssize_t i = cycleStart + 1; i < n; ++i) { - if (array[i] < item) + if (vec_arr[i] < item) + { rank++; + cRank.store(rank); + } } // If the item is already there, this is a 1-cycle. if (rank == cycleStart) { - array.mark(rank, 2); + vec_arr.mark(rank, 2); break; } // Otherwise, put the item after any duplicates. - while (item == array[rank]) + while (item == vec_arr[rank]) + { rank++; + cRank.store(rank); + } // Put item into right place and colorize - counted_swap(array.get_mutable(rank), item); - array.mark(rank, 2); + counted_swap(vec_arr.get_mutable(rank), item); + vec_arr.mark(rank, 2); // Continue for rest of the cycle. } while (rank != cycleStart); } - array.unwatch_all(); + vec_arr.unwatch_all(); } void CycleSort(SortArray& A) diff --git a/src/SortArray.cpp b/src/SortArray.cpp index cbe8074db..037fc0544 100644 --- a/src/SortArray.cpp +++ b/src/SortArray.cpp @@ -97,7 +97,7 @@ void ArrayItem::OnComparison(const ArrayItem& a, const ArrayItem& b) SortArray::SortArray() : m_calc_inversions(false), - m_delay(nullptr) + m_delay(nullptr) { } @@ -929,7 +929,7 @@ unsigned short SortArray::InWatchList(ssize_t idx) const // compare watched value // std::atomic_ref(*m_watch[i].first).load() <-- C++20 - if (*m_watch[i].first!= idx) continue; + if (m_watch[i].first->load() != idx) continue; return m_watch[i].second; } @@ -939,7 +939,6 @@ unsigned short SortArray::InWatchList(ssize_t idx) const int SortArray::GetIndexColor(size_t idx) { int clr, acl = InAccessList(idx); - // select color if (idx == m_access1.index) { diff --git a/src/SortArray.h b/src/SortArray.h index 1be1bc4cc..7c5327fcb 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -25,6 +25,7 @@ #define SORT_ARRAY_HEADER #include +#include #include #include @@ -313,7 +314,7 @@ class SortArray std::vector m_mark; /// custom watched index pointers in the array, set by algorithm - std::vector< std::pair > m_watch; + std::vector< std::pair*,unsigned char> > m_watch; /// flag for sorted array bool m_is_sorted; @@ -376,7 +377,7 @@ class SortArray void FinishFill(); /// save access to array, forwards to sound system - void SaveAccess(size_t i); + // void SaveAccess(size_t i); /// check if index matches one of the watched pointers short InAccessList(ssize_t idx); @@ -573,12 +574,13 @@ class SortArray } // Highly experimental method to _track_ array live indexes. - void watch(ssize_t* idxptr, unsigned char color = 2) + // The index must be created as std::atomic to ensure thread safety + void watch(std::atomic* idxptr, unsigned char color = 2) { wxMutexLocker lock(m_mutex); ASSERT(lock.IsOk()); - m_watch.push_back( std::make_pair(idxptr,color) ); + m_watch.push_back( std::make_pair(idxptr, color)); } /// Release all tracked live array indexes. From 72e640fa4ce7368883bbc450b4f4b7d0019913bc Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 14:15:44 +0800 Subject: [PATCH 252/289] Fixed "cannot terminate thread: The handle is invalid" So, this fix certainly has some story to it, my god! It took me weeks to fix this issue and it is finally over! It took me weeks to know what's happening here. The visualizer is reliant upon DoDelay() to end the thread gracefully. Removing wxThread::Exit() or removing the Exit() call on DoDelay() will kill the visualizer. The reason why the visualizer is producing the "cannot terminate thread" error is because of AbortAlgorithm() calling Wait() on m_thread *after* m_thread has exited using Exit() (which calls wxThread::Exit()), on lower delays this issue isn't so common, but it still has a chance to appear if Wait() is called when m_thread is already invalidated. This new change now makes it so that Wait() is never called, on the OnRunButton, if m_thread is not nullptr, and it is not alive, simply clearing the pointer will suffice, as waiting for a !IsAlive() thread will produce the "cannot terminate thread" error (which is what also happens in AbortAlgorithm()). The most major change here is AbortAlgorithm(). Instead of calling Wait(), what AbortAlgorithm() now does is run on a while loop, which checks if m_thread is still alive, if it is alive, the GUI thread will sleep for 1 millisecond, giving DoDelay() time to see the m_thread_terminate flag and exit the thread, once the thread has actually exited with wxThread::Exit(), the thread is no longer alive, making this while loop stop and clearing the pointer. This fix has been tested on 0.0 ms delay, with array size = 3909, for more than a minute of rapid clicking on the "Random" button using my rapid clicker button, the program doesn't produce the "cannot terminate thread" error. Replacing the while loop with Wait() makes the error come back again. --- src/WMain.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index c909fb93e..512bcfc5a 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -25,6 +25,7 @@ #include #include "wxg/WAbout_wxg.h" +#include WMain::WMain(wxWindow* parent) : WMain_wxg(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE) @@ -174,7 +175,7 @@ void WMain::AbortAlgorithm() if (m_thread->IsPaused()) { m_thread->Resume(); } sortview->SetStepwise(false); - m_thread->Wait(); + while (m_thread->IsAlive()) { wxMilliSleep(1); } g_algo_running = false; delete m_thread; @@ -186,9 +187,7 @@ void WMain::OnRunButton(wxCommandEvent &event) // join finished thread if (m_thread && !m_thread->IsAlive()) { - m_thread->Wait(); g_algo_running = false; - delete m_thread; m_thread = nullptr; } @@ -324,13 +323,13 @@ void WMain::SetDelay(size_t pos) // 0.001 ms formula, tested on Windows // Warning! The slider will never go past 0.005 ms with this formula // g_delay = pow(base, pos / 15000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 800.0; - g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; + g_delay = pow(base, pos / 2200.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; #else // other systems probably have sucking real-time performance anyway g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0) / log(base)); #endif - if (pos == 0) g_delay = 0.1; + if (pos == 0) g_delay = 0.0; if (g_delay > 10) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); From 5789b0ebbcf55a6cf80a7b489cc94d73c8775639 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 14:16:59 +0800 Subject: [PATCH 253/289] Removed and reverted unnecessary changes --- src/WMain.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 512bcfc5a..6e71b8f5d 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -25,7 +25,6 @@ #include #include "wxg/WAbout_wxg.h" -#include WMain::WMain(wxWindow* parent) : WMain_wxg(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE) @@ -323,13 +322,13 @@ void WMain::SetDelay(size_t pos) // 0.001 ms formula, tested on Windows // Warning! The slider will never go past 0.005 ms with this formula // g_delay = pow(base, pos / 15000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 800.0; - g_delay = pow(base, pos / 2200.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; + g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0 * 10.0) / log(base)) / 10.0; #else // other systems probably have sucking real-time performance anyway g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0) / log(base)); #endif - if (pos == 0) g_delay = 0.0; + if (pos == 0) g_delay = 0.01; if (g_delay > 10) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); From 388d02766fb8e5b47a561f32cdf73e20f3150db3 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 15:59:28 +0800 Subject: [PATCH 254/289] Changed Stereo to Mono --- src/WMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 6e71b8f5d..9bee9f0b6 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -83,7 +83,7 @@ WMain::WMain(wxWindow* parent) // Set the audio format sdlaudiospec.freq = 44100; sdlaudiospec.format = AUDIO_S16SYS; - sdlaudiospec.channels = 2; /* 1 = mono, 2 = stereo */ + sdlaudiospec.channels = 1; /* 1 = mono, 2 = stereo */ sdlaudiospec.samples = 4096; /* Good low-latency value for callback */ sdlaudiospec.callback = SoundCallback; sdlaudiospec.userdata = sortview; From 1601e1a67eef24e72ff0c7f13eaf405650fd1896 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 16:11:05 +0800 Subject: [PATCH 255/289] Raised minimum speed delay and framerate cap Capping the visualizer to 45 FPS allows for smoother animations, 45 -> 60 FPS doesn't make much of a difference, so 45 FPS should be the sweet spot. 0.01 speed delay feels very unstable, so I raised the minimum speed delay to 0.1 ms again --- src/WMain.cpp | 2 +- src/WMain.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 9bee9f0b6..df30b57f0 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -328,7 +328,7 @@ void WMain::SetDelay(size_t pos) g_delay = pow(base, pos / 2000.0 * log(2 * 1000.0) / log(base)); #endif - if (pos == 0) g_delay = 0.01; + if (pos == 0) g_delay = 0.1; if (g_delay > 10) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); diff --git a/src/WMain.h b/src/WMain.h index fbf52f770..f5c4be10d 100644 --- a/src/WMain.h +++ b/src/WMain.h @@ -33,7 +33,7 @@ // ---------------------------------------------------------------------------- // --- Global Constants and Variables -static const size_t g_framerate = 30; +static const size_t g_framerate = 45; // ---------------------------------------------------------------------------- From 1096f9d78930ee8721af2b4fa709d452865be0be Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 18:45:14 +0800 Subject: [PATCH 256/289] Fixed "lagging" sound during algorithm reset This issue isn't very noticeable on low delays, but on high delays, the sound takes a while to disappear after the sorting algorithm has been requested to reset. To resolve this, the sound will now be paused when the Reset button is pressed, and the sound button will be unpressed. Calling SoundReset() to fix this problem isn't enough, this change will fix it. --- src/WMain.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index df30b57f0..3a9208a1b 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -169,8 +169,11 @@ void WMain::OnDClick(wxSplitterEvent& event) { event.Veto(); } void WMain::AbortAlgorithm() { if (!m_thread) return; - + m_thread_terminate = true; + SDL_PauseAudio(1); + soundButton->SetValue(false); + if (m_thread->IsPaused()) { m_thread->Resume(); } sortview->SetStepwise(false); From c7fbdefb14db209dbe4189f06289514c54f57aed Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 18:50:46 +0800 Subject: [PATCH 257/289] Improved lagging sound fix --- src/WMain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WMain.cpp b/src/WMain.cpp index 3a9208a1b..2a5ad430c 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -171,6 +171,7 @@ void WMain::AbortAlgorithm() if (!m_thread) return; m_thread_terminate = true; + g_sound_on = false; SDL_PauseAudio(1); soundButton->SetValue(false); From f31c0aa44f398a05b8e5c9df7f39a46c6c39b70a Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 20:10:10 +0800 Subject: [PATCH 258/289] Improved lagging sound fix during reset This fix will not reset the Sound button anymore when the algorithm is reset, while also preventing any leftover lagging sound from being produced when the algorithm is reset on high delay. --- src/WMain.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 2a5ad430c..81f831318 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -171,15 +171,23 @@ void WMain::AbortAlgorithm() if (!m_thread) return; m_thread_terminate = true; - g_sound_on = false; - SDL_PauseAudio(1); - soundButton->SetValue(false); + if (soundButton->GetValue() == true) + { + SoundReset(); + g_sound_on = false; + SDL_PauseAudio(1); + } if (m_thread->IsPaused()) { m_thread->Resume(); } sortview->SetStepwise(false); while (m_thread->IsAlive()) { wxMilliSleep(1); } g_algo_running = false; + if (soundButton->GetValue() == true) + { + g_sound_on = true; + SDL_PauseAudio(0); + } delete m_thread; m_thread = nullptr; From c047d80cd16737b25a7caee2fdf436c4bc945f29 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 22:20:01 +0800 Subject: [PATCH 259/289] Improved DoDelay() algorithm reset responsiveness The visualizer has another apparent issue where, the higher the delay is, the longer it takes for the algorithm reset to take effect which is not so good, if say the delay is set to 2000 ms, then the application will hang up for 2 seconds before the reset takes effect. This change fixes that by making it so that the reset request now only has a microsecond/millisecond interval, and it will always remain this way regardless of how big the delay is. Even if the delay is set to 1 minute (if TSoS is allowed to have such high delay), the reset will still take effect immediately. --- src/WSortView.cpp | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 2dcda4513..2165fa9fa 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -95,15 +95,43 @@ void WSortView::DoDelay(double delay) // else timeout, recheck m_stepwise and loop wxMilliSleep(1); } - -#if __WXGTK__ - wxMicroSleep(delay * 1000.0); -#elif MSW_PERFORMANCECOUNTER - mswMicroSleep(delay * 1000.0); -#else - // wxMSW does not have a high resolution timer, maybe others do? - wxMilliSleep(delay); -#endif + double microDelay = delay * 1000.0, secs = 0; + #if __WXGTK__ + while (secs <= microDelay) + { + wxMicroSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + #elif MSW_PERFORMANCECOUNTER + while (secs <= microDelay) + { + mswMicroSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + #else + // wxMSW does not have a high resolution timer, maybe others do? + wxMilliSleep(delay); + while (secs <= delay) + { + wxMilliSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + #endif } void WSortView::OnAccess() From 54b4b439fd8c4e6b7b398327ec7cdb7cb687f458 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 22:30:12 +0800 Subject: [PATCH 260/289] Readded old sleep intervals This is incase someone wants to revert back to the old sleep intervals, but this will also make the reset requesto take just as long as the configured delay interval. If the delay interval is set to 1 minute, then the application will also hang up for 1 minute to reset the sorting algorithm. --- src/WSortView.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 2165fa9fa..c9b224036 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -97,6 +97,7 @@ void WSortView::DoDelay(double delay) } double microDelay = delay * 1000.0, secs = 0; #if __WXGTK__ + // wxMicroSleep(delay * 1000.0); while (secs <= microDelay) { wxMicroSleep(1); @@ -108,6 +109,7 @@ void WSortView::DoDelay(double delay) } } #elif MSW_PERFORMANCECOUNTER + // mswMicroSleep(delay * 1000.0); while (secs <= microDelay) { mswMicroSleep(1); @@ -120,6 +122,7 @@ void WSortView::DoDelay(double delay) } #else // wxMSW does not have a high resolution timer, maybe others do? + // wxMilliSleep(delay); wxMilliSleep(delay); while (secs <= delay) { From 6d38ababa274b93e1fe11eb814f29e0f770554e5 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Wed, 6 Nov 2024 23:58:21 +0800 Subject: [PATCH 261/289] Introduced MilliSleep loop to avoid potential overflow Although this doesn't completely protect the visualizer from a potential overflow during delay * 1000, this is considered as a partial futureproof solution. The way this change works is that if the delay is lower than 1 ms, DoDelay() will switch to microsecond sleeping to accurately represent this delay value, however, if the delay value is bigger than 1ms, DoDelay() will resort to millisecond sleeping to help reduce overhead and avoid potential overflow when delay * 1000 is performed. The millisecond sleep loop will treat values such as 2.65 and 3.25 as whole numbers, but I believe this is a necessary sacrifice as the goal of this change is to avoid calculation overflow. --- src/WSortView.cpp | 61 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index c9b224036..e08233886 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -95,35 +95,68 @@ void WSortView::DoDelay(double delay) // else timeout, recheck m_stepwise and loop wxMilliSleep(1); } - double microDelay = delay * 1000.0, secs = 0; + double secs = 0; #if __WXGTK__ // wxMicroSleep(delay * 1000.0); - while (secs <= microDelay) + if (delay < 1) { - wxMicroSleep(1); - secs += 1.0; - if (wmain->m_thread_terminate) + double microDelay = delay * 1000.0; + while (secs <= microDelay) { - wmain->m_thread->Exit(); - return; + wxMicroSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + } + else + { + while (secs <= delay) + { + wxMilliSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } } } #elif MSW_PERFORMANCECOUNTER // mswMicroSleep(delay * 1000.0); - while (secs <= microDelay) + if (delay < 1) { - mswMicroSleep(1); - secs += 1.0; - if (wmain->m_thread_terminate) + double microDelay = delay * 1000.0; + while (secs <= microDelay) { - wmain->m_thread->Exit(); - return; + mswMicroSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + } + else + { + while (secs <= delay) + { + mswMicroSleep(1000); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } } } #else // wxMSW does not have a high resolution timer, maybe others do? // wxMilliSleep(delay); - wxMilliSleep(delay); while (secs <= delay) { wxMilliSleep(1); From 3fa60e956e6b985869a1a9c603c665e15cb1d2be Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 01:46:22 +0800 Subject: [PATCH 262/289] Removed decimal places on 1 ms and above Since decimal places are not considered for speed delays anymore in 1 ms and above, it is best not to show them anymore, as they could just lead to confusion. --- src/WMain.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 81f831318..1b2e09bac 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -342,10 +342,8 @@ void WMain::SetDelay(size_t pos) #endif if (pos == 0) g_delay = 0.1; - if (g_delay > 10) + if (g_delay > 1) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); - else if (g_delay > 1) - labelDelayValue->SetLabel(wxString::Format(_("%.2f ms"), g_delay)); else labelDelayValue->SetLabel(wxString::Format(_("%.3f ms"), g_delay)); } From 8af2d146fc525c84aec058a5562ddeca8babfba2 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 01:54:33 +0800 Subject: [PATCH 263/289] Slight correction --- src/WMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index 1b2e09bac..db815a41e 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -342,7 +342,7 @@ void WMain::SetDelay(size_t pos) #endif if (pos == 0) g_delay = 0.1; - if (g_delay > 1) + if (g_delay >= 1) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); else labelDelayValue->SetLabel(wxString::Format(_("%.3f ms"), g_delay)); From 5c8ffd3caecce53b116d3890168fe91b02c74a08 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 01:54:47 +0800 Subject: [PATCH 264/289] Slight correction From 296a1f86274381b62ade74998af943957a305819 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 21:41:56 +0800 Subject: [PATCH 265/289] Minor text correction --- SortAlgo.cpp | 4478 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4478 insertions(+) create mode 100644 SortAlgo.cpp diff --git a/SortAlgo.cpp b/SortAlgo.cpp new file mode 100644 index 000000000..cb69800fd --- /dev/null +++ b/SortAlgo.cpp @@ -0,0 +1,4478 @@ +/****************************************************************************** + * src/SortAlgo.cpp + * + * Implementations is many sorting algorithms. + * + * Note that these implementations may not be as good/fast as possible. Some + * are modified so that the visualization is more instructive. + * + * Futhermore, some algorithms are annotated using the mark() and watch() + * functions from SortArray. These functions add colors to the illustratation + * and thereby makes the algorithm's visualization easier to explain. + * + ****************************************************************************** + * The algorithms in this file are copyrighted by the original authors. All + * code is freely available. + * + * The source code added by myself (Timo Bingmann) and all modifications are + * copyright (C) 2013-2014 Timo Bingmann + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + *****************************************************************************/ + +#include "SortAlgo.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef ArrayItem value_type; + +// inversion count limit for iterator instrumented algorithms +const unsigned int inversion_count_instrumented = 512; + +const struct AlgoEntry g_algolist[] = +{ + { _("Selection Sort"), &SelectionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Double Selection Sort"), &DoubleSelectionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, + _("Also known as Exchange Sort.") }, + { _("Double Sandpaper Sort"), &DoubleSandpaperSort, UINT_MAX, UINT_MAX, + _("A variant of Exchange Sort that sorts the array bidirectionally.") }, + { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Merge Sort"), &MergeSort, UINT_MAX, 512, + _("Merge sort which merges two sorted sequences into a shadow array, and then copies it back to the shown array.") }, + { _("Merge Sort (iterative)"), &MergeSortIterative, UINT_MAX, 512, + _("Merge sort variant which iteratively merges " + "subarrays of sizes of powers of two.") }, + { _("Pairwise Merge Sort (Recursive)"), &PairwiseSort, UINT_MAX, 512, + wxEmptyString }, + { _("Pairwise Merge Sort (Iterative)"), &PairwiseIterativeSort, UINT_MAX, 512, + wxEmptyString }, + { _("Weave Merge Sort"), &WeaveMergeSort, UINT_MAX, 512, + _("An in-place merge sort variant that interleaves 2 halves of the input array, and then uses Insertion Sort to sort the array.")}, + { _("New Shuffle Merge Sort"), &NewShuffleMergeSort, UINT_MAX, 512, + _("An improvement upon Weave Merge Sort, with faster weave time, and inserting now makes comparisons with a worst-case similar to Merge Sort.") }, + { _("Andrey's In-Place Merge Sort"), &AndreyMergeSort, UINT_MAX, 512, + wxEmptyString }, + { _("Proportion Extend Merge Sort"), &ProportionMergeSort, UINT_MAX, 512, + wxEmptyString }, + { _("Buffer Partition Merge Sort"), &BufferPartitionMergeSort, UINT_MAX, 512, + wxEmptyString }, + { _("Strand Sort"), &StrandSort, UINT_MAX, 512, + wxEmptyString }, + { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, + _("Quick sort variant with left and right pointers.") }, + { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, + _("Quick sort variant from 3rd edition of CLRS: two pointers on left.") }, + { _("Quick Sort (ternary, LR ptrs)"), &QuickSortTernaryLR, UINT_MAX, UINT_MAX, + _("Ternary-split quick sort variant, adapted from multikey quicksort by " + "Bentley & Sedgewick: partitions \"==\" using two pairs of pointers " + "at left and right, then copied to middle.") }, + { _("Quick Sort (ternary, LL ptrs)"), &QuickSortTernaryLL, UINT_MAX, UINT_MAX, + _("Ternary-split quick sort variant: partitions \"<>?=\" using two " + "pointers at left and one at right. Afterwards copies the \"=\" to middle.") }, + { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, + _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " + "two at left and one at right.") }, + { _("PDQ Sort"), &PDQSort, UINT_MAX, inversion_count_instrumented, + _("Pattern-defeating Quick Sort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" + " with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, + { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, + _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, + { _("Flan Sort (Quick Library Sort)"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, + _("An in-place Library Sort variant that uses Quick Sort partitioning to make space.") }, + { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, + _("This variant terminates early if the array is already sorted.") }, + { _("Targeted Bubble Sort"), &TargetedBubbleSort, UINT_MAX, 1024, + _("This variant of Bubble Sort is capable of adjusting the sorting boundaries based on the input array.") }, + { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, + _("This variant sorts from both directions of the array simultaneously.") }, + { _("Circle Sort"), &CircleSort, UINT_MAX, UINT_MAX, + _("Circle Sort is a recursive sorting algorithm that works by comparing and swapping elements in a circular manner.") }, + { _("Iterative Circle Sort"), &CircleSort2, UINT_MAX, UINT_MAX, + _("A variant of Circle Sort that has less recursion overhead.") }, + { _("Introspective Circle Sort"), &IntroCircleSort, UINT_MAX, UINT_MAX, + _("A variant of Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, + { _("Introspective Iterative Circle Sort"), &IntroIteCircleSort, UINT_MAX, UINT_MAX, + _("A variant of Iterative Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, + { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Optimized Gnome Sort"), &OptimizedGnomeSort, UINT_MAX, UINT_MAX, + _("This variant avoids scanning through sorted portions of the array after a number has been placed in its correct spot") }, + { _("Comb Sort"), &CombSort, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Shell Sort"), &ShellSort, UINT_MAX, 1024, + wxEmptyString }, + { _("Heap Sort"), &HeapSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("Smooth Sort"), &SmoothSort, UINT_MAX, 1024, + wxEmptyString }, + { _("Odd-Even Sort"), &OddEvenSort, UINT_MAX, 1024, + wxEmptyString }, + // older sequential implementation, which really makes little sense to do + //{ _("Bitonic Sort"), &BitonicSort, UINT_MAX, UINT_MAX, wxEmptyString }, + { _("Batcher's Bitonic Sort"), &BitonicSortNetwork, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Batcher's Odd-Even Merge Sort"), &BatcherSortNetwork, UINT_MAX, UINT_MAX, + wxEmptyString }, + { _("Cycle Sort"), &CycleSort, 512, UINT_MAX, + wxEmptyString }, + { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, + _("Least significant digit radix sort, which copies item into a shadow " + "array during counting.") }, + { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, UINT_MAX, + _("Least significant digit radix sort, performed in O(1) space.") }, + { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, 512, + _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, + { _("Rotate Radix Sort (MSD)"), &RotateRadixSortMSD, UINT_MAX, 512, + wxEmptyString }, + { _("Rotate Radix Sort (LSD)"), &RotateRadixSortLSD, UINT_MAX, 512, + wxEmptyString }, + { _("American Flag Sort"), &AmericanFlagSort, UINT_MAX, inversion_count_instrumented, + _("American Flag Sort is an efficient, in-place variant of radix sort that distributes items into hundreds of buckets.") }, + { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("std::stable_sort (gcc)"), &StlStableSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("std::sort_heap (gcc)"), &StlHeapSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("Tim Sort"), &TimSort, UINT_MAX, inversion_count_instrumented, + wxEmptyString }, + { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, + _("An O(1) place O(n log n) time stable merge sort.") }, + { _("Grail Sort (O(1) buffer)"), &GrailSort, UINT_MAX, inversion_count_instrumented, + _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, + { _("Grail Sort (external buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, + _("A variant of Grail Sort that uses an external buffer for a potential speedup.") }, + { _("Bead Sort"), &BeadSort, UINT_MAX, UINT_MAX, + _("This is a non-comparison based sorting algorithm that uses the concept of stacked beads to sort the elements.") }, + { _("Gravity Sort"), &GravitySort, UINT_MAX, UINT_MAX, + _("A non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, + { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, + _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, + { _("Optimized Pancake Sort"), &OptimizedPancakeSort, UINT_MAX, UINT_MAX, + _("An optimized variant of Pancake Sort that performs 1/2 as many flips.") }, + { _("Adjacency Pancake Sort"), &AdjacencyPancakeSort, UINT_MAX, UINT_MAX, + _("An improvement upon Pancake Sort, which performs only 5/3 N + O(1) flips.") }, + { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, + wxEmptyString }, + { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, + wxEmptyString }, + { _("Stooge Sort"), &StoogeSort, 256, inversion_count_instrumented, + wxEmptyString }, + { _("Slow Sort"), &SlowSort, 128, inversion_count_instrumented, + wxEmptyString }, + { _("Bad Sort"), &BadSort, 128, inversion_count_instrumented, + _("A humorous sorting algorithm with a time complexity of O(n^3).") } +}; + +const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); + +const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; + +std::random_device rd1; +std::mt19937 gen1(rd1()); + +// **************************************************************************** +// *** Selection Sort + +void DoubleSelectionSort(SortArray& A) +{ + size_t left = 0; + size_t right = A.size() - 1, n = right; + ssize_t max_idx = 0; + ssize_t low_idx = 0; + std::atomic max_i, low_i; + max_i.store(max_idx); + low_i.store(low_idx); + A.watch(&max_i, 4); + A.watch(&low_i, 5); + while (left < right) + { + max_idx = right; + low_idx = left; + for (size_t i = left; i <= right; ++i) + { + if (A[i] < A[low_idx]) + { + A.mark_swap(i, low_idx); + low_idx = i; + low_i.store(i); + } + else if (A[i] > A[max_idx]) + { + A.mark_swap(i, max_idx); + max_idx = i; + max_i.store(i); + } + } + A.swap(left, low_idx); + ssize_t l = left; // This removes comparison warning + if (max_idx == l) { max_idx = low_idx; } + A.swap(right, max_idx); + if (left > 0) { A.unmark(left - 1); } + if (right < n) { A.unmark(right + 1); } + A.mark(left); + A.mark(right); + ++left; --right; + } + A.unwatch_all(); +} + +void SelectionSort(SortArray& A) +{ + ssize_t jMin = 0; + std::atomic kMin; + kMin.store(jMin); + A.watch(&kMin, 3); + + for (size_t i = 0; i < A.size()-1; ++i) + { + jMin = i; + kMin.store(jMin); + + for (size_t j = i+1; j < A.size(); ++j) + { + if (A[j] < A[jMin]) { + A.mark_swap(j, jMin); + jMin = j; + kMin.store(jMin); + } + } + + A.swap(i, jMin); + + // mark the last good element + if (i > 0) A.unmark(i-1); + A.mark(i); + } + A.unwatch_all(); +} + +// **************************************************************************** +// *** Sandpaper and Double Sandpaper Sort +// Double Sandpaper Sort by Taihennami + +void DoubleSandpaperSort(SortArray& A) +{ + for (size_t left = 0, right = A.size() - 1; left < right; ++left, --right) + { + if (A[left] > A[right]) + { + A.swap(left, right); + } + for (size_t i = left + 1; i < right; ++i) + { + if (A[left] > A[i]) + { + A.swap(i, left); + } + else if (A[i] > A[right]) + { + A.swap(i, right); + } + } + } +} + +void SandpaperSort(SortArray& A) +{ + size_t n = A.size(); + for (size_t i = 0; i < n; ++i) + { + for (size_t j = i + 1; j < n; ++j) + { + if (A[i] > A[j]) + { + A.swap(i, j); + } + } + } +} + +// **************************************************************************** +// *** Insertion Sort + +void InsertSort(SortArray& A, size_t start, size_t end) +{ + int begin = static_cast(start); + for (size_t i = start; i < end; ++i) + { + A.mark(i); + int j = i - 1; + value_type key = A[i]; + while (j >= begin && A[j] > key) + { + A.set(j + 1, A[j]); + --j; + } + int index = j + 1; + A.set(index, key); + + A.unmark(i); + } +} + +// with extra item on stack +void InsertionSort(SortArray& A) +{ + InsertSort(A, 0, A.size()); +} + +// swaps every time (keeps all values visible) +void InsertionSort2(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ++i) + { + value_type key = A[i]; + A.mark(i); + + ssize_t j = i - 1; + while (j >= 0 && A[j] > key) + { + A.swap(j, j + 1); + j--; + } + + A.unmark(i); + } +} + +// swaps every time (keeps all values visible) +void BinaryInsertionSort2(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ++i) + { + value_type key = A[i]; + A.mark(i); + + int lo = 0, hi = i; + while (lo < hi) { + int mid = (lo + hi) / 2; + if (key < A[mid]) + hi = mid; + else + lo = mid + 1; + } + + // item has to go into position lo + + ssize_t j = i - 1; + while (j >= lo) + { + A.swap(j, j + 1); + j--; + } + + A.unmark(i); + } +} + +void BinaryInsertSort(SortArray& A, size_t start, size_t end) +{ + for (size_t i = start; i < end; ++i) + { + value_type key = A[i]; + A.mark(i); + + size_t lo = start, hi = i; + while (lo < hi) { + size_t mid = (lo + hi) / 2; + if (key < A[mid]) + hi = mid; + else + lo = mid + 1; + } + + size_t j = i; + while (j > lo) + { + A.set(j, A[j - 1]); + j--; + } + A.set(lo, key); + A.unmark(i); + } +} + +void BinaryInsertionSort(SortArray& A) +{ + BinaryInsertSort(A, 0, A.size()); +} + +// **************************************************************************** +// *** Merge Sort (out-of-place with sentinels) + +// by myself (Timo Bingmann) + +void Merge(SortArray& A, size_t lo, size_t mid, size_t hi) +{ + // mark merge boundaries + A.mark(lo); + A.mark(mid,3); + A.mark(hi-1); + + // allocate output + std::vector out(hi-lo); + + // merge + size_t i = lo, j = mid, o = 0; // first and second halves + while (i < mid && j < hi) + { + // copy out for fewer time steps + value_type ai = A[i], aj = A[j]; + + out[o++] = (ai < aj ? (++i, ai) : (++j, aj)); + } + + // copy rest + while (i < mid) out[o++] = A[i++]; + while (j < hi) out[o++] = A[j++]; + + ASSERT(o == hi-lo); + + A.unmark(mid); + + // copy back + for (i = 0; i < hi-lo; ++i) + A.set(lo + i, out[i]); + + A.unmark(lo); + A.unmark(hi-1); +} + +void MergeSort(SortArray& A, size_t lo, size_t hi) +{ + if (lo + 1 < hi) + { + size_t mid = (lo + hi) / 2; + + MergeSort(A, lo, mid); + MergeSort(A, mid, hi); + + Merge(A, lo, mid, hi); + } +} + +void MergeSort(SortArray& A) +{ + return MergeSort(A, 0, A.size()); +} + +void MergeSortIterative(SortArray& A) +{ + for (size_t s = 1; s < A.size(); s *= 2) + { + for (size_t i = 0; i + s < A.size(); i += 2 * s) + { + Merge(A, i, i + s, + std::min(i + 2 * s, A.size())); + } + } +} + +/* + MIT License + + Copyright (c) 2020 aphitorite/2021 EmeraldBlock + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void weaveMerge2(SortArray& A, std::vector& tmp, size_t len, size_t residue, size_t modulus) +{ + if (residue + modulus >= len) { return; } + + size_t low = residue, high = residue + modulus, dmodulus = modulus << 1; + + weaveMerge2(A, tmp, len, low, dmodulus); + weaveMerge2(A, tmp, len, high, dmodulus); + + size_t next = residue; + for (; low < len && high < len; next += modulus) + { + int cmp = 0; + if (A[low] > A[high]) { cmp = 1; } + else if (A[low] < A[high]) { cmp = -1; } + + if (cmp == 1 || (cmp == 0 && low > high)) + { + tmp[next] = A[high]; + high += dmodulus; + } + else + { + tmp[next] = A[low]; + low += dmodulus; + } + } + + if (low >= len) + { + while (high < len) + { + tmp[next] = A[high]; + next += modulus; + high += dmodulus; + + } + } + else + { + while (low < len) + { + tmp[next] = A[low]; + next += modulus; + low += dmodulus; + } + } + + for (size_t i = residue; i < len; i += modulus) + { + A.set(i, tmp[i]); + A[i].get(); + } +} + +void WeaveMergeSort2(SortArray& A) +{ + size_t len = A.size(); + std::vector tmp(len); + weaveMerge2(A, tmp, len, 0, 1); +} + +void insertTo(SortArray& A, size_t a, size_t b) +{ + value_type temp = A[a]; + while (a > b) { A.set(a, A[a - 1]); --a; } + A.set(b, temp); +} + +void shiftValue(SortArray& A, size_t a, size_t b, size_t len) +{ + for (size_t i = 0; i < len; ++i) + { + A[a + i].get(); + A.swap(a + i, b + i); + } +} + +void rotate(SortArray& A, int a, int m, int b) +{ + int l = m - a, r = b - m; + while (l > 0 && r > 0) + { + if (r < l) + { + shiftValue(A, static_cast(m - r), static_cast(m), static_cast(r)); + b -= r; + m -= r; + l -= r; + } + + else + { + shiftValue(A, static_cast(a), static_cast(m), static_cast(l)); + a += l; + m += l; + r -= l; + } + } +} + +void bitReversal(SortArray& A, size_t a, size_t b) +{ + size_t len = b - a, m = 0; + size_t d1 = len >> 1, d2 = d1 + (d1 >> 1); + for (size_t i = 1; i < len - 1; ++i) + { + size_t j = d1; + for (size_t k = i, n = d2; (k & 1) == 0; j -= n, k >>= 1, n >>= 1) {} + m += j; + if (m > i) + { + A.swap(a + i, a + m); + } + } +} + +void weaveInsert(SortArray& A, size_t a, size_t b, bool right) +{ + size_t i = a, j = i + 1; + while (j < b) + { + while (i < j && ((right == true && A[i] <= A[j]) || (right == false && A[i] < A[j]))) { ++i; } + if (i == j) + { + right = !right; + ++j; + } + else + { + insertTo(A, j, i++); + j += 2; + } + } +} + +void weaveMerge(SortArray& A, size_t a, size_t m, size_t b) +{ + if (b - a < 2) { return; } + size_t a1 = a, b1 = b; + bool right = true; + if ((b - a) % 2 == 1) + { + if (m - a < b - m) + { + --a1; + right = false; + } + else { ++b1; } + } + + for (size_t e = b1, f; e - a1 > 2; e = f) + { + m = (a1 + e) / 2; + size_t p = 1 << static_cast(log(m - a1) / log(2)); + rotate(A, static_cast(m - p), static_cast(m), static_cast(e - p)); + + m = e - p; + f = m - p; + + bitReversal(A, f, m); + bitReversal(A, m, e); + bitReversal(A, f, e); + } + weaveInsert(A, a, b, right); +} + +void WeaveMergeSort(SortArray& A) +{ + size_t n = A.size(), d = 1 << static_cast(log(n - 1) / log(2) + 1); + while (d > 1) + { + size_t i = 0, dec = 0; + while (i < n) + { + size_t j = i; + dec += n; + while (dec >= d) + { + dec -= d; + ++j; + } + size_t k = j; + dec += n; + while (dec >= d) + { + dec -= d; + ++k; + } + weaveMerge(A, i, j, k); + i = k; + } + d /= 2; + } +} +// **************************************************************************** +// *** Quick Sort Pivot Selection + +QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST; + +static ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) +{ + // cases if two are equal + if (A[lo] == A[mid]) return lo; + if (A[lo] == A[hi - 1] || A[mid] == A[hi - 1]) return hi - 1; + + // cases if three are different + return A[lo] < A[mid] + ? (A[mid] < A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? hi - 1 : lo)) + : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); +} + +template +static void PivotInsertionSort(SortArray& A, std::array& arr) +{ + for (size_t i = 1; i < N; ++i) + { + ssize_t key = arr[i]; + size_t j = i; + while (j > 0 && A[arr[j - 1]] > A[key]) + { + arr[j] = arr[j - 1]; + --j; + } + arr[j] = key; + } +} + +static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 5; + std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; + PivotInsertionSort(A, nums); + return nums[2]; +} + +static ssize_t NintherPivot(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment_size = (hi - lo) / 9; + ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); + ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); + ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); + return SingleMedianOfThree(A, g1, g2, g3 + 1); +} + +// some quicksort variants use hi inclusive and some exclusive, we require it +// to be _exclusive_. hi == array.end()! +ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) +{ + switch (g_quicksort_pivot) + { + case PIVOT_FIRST: + { + return lo; + } + case PIVOT_LAST: + { + return hi - 1; + } + case PIVOT_MID: + { + return (lo + hi) / 2; + } + case PIVOT_RANDOM: + { + return lo + (rand() % (hi - lo)); + } + case PIVOT_MEDIAN3: + { + ssize_t mid = (lo + hi) / 2; + return SingleMedianOfThree(A, lo, mid, hi); + } + case PIVOT_MEDIAN3RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + case PIVOT_MEDIAN5: + { + return MedianOfFive(A, lo, hi); + } + case PIVOT_MEDIAN5RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (hi - lo < 5) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotInsertionSort(A, samples); + return samples[2]; + } + case PIVOT_MEDIAN7: + { + if (hi - lo < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 7; + std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; + PivotInsertionSort(A, samples); + return samples[3]; + } + case PIVOT_MEDIAN7RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (hi - lo < 7) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotInsertionSort(A, samples); + return samples[3]; + } + case PIVOT_NINTHER: + { + return NintherPivot(A, lo, hi); + } + case PIVOT_RANDOMNINTHER: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (hi - lo < 9) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); + ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); + ssize_t g1 = SingleMedianOfThree(A, lo1, lo2, lo3 + 1); + ssize_t g2 = SingleMedianOfThree(A, lo4, lo5, lo6 + 1); + ssize_t g3 = SingleMedianOfThree(A, lo7, lo8, lo9 + 1); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } + case PIVOT_MEDIAN9: + { + if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 9; + std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8 }; + PivotInsertionSort(A, samples); + return samples[4]; + } + case PIVOT_MEDIAN9RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (hi - lo < 9) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotInsertionSort(A, samples); + return samples[4]; + } + case PIVOT_MEDIAN15: + { + if (hi - lo < 15) { return MedianOfFive(A, lo, hi); } + ssize_t segment = (hi - lo) / 3; + ssize_t g1 = MedianOfFive(A, lo, lo + segment); + ssize_t g2 = MedianOfFive(A, lo + segment, lo + segment * 2); + ssize_t g3 = MedianOfFive(A, lo + segment * 2, hi); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } + case PIVOT_THREENINTHER: + { + if (hi - lo < 27) { return NintherPivot(A, lo, hi); } + ssize_t segment = (hi - lo) / 3; + ssize_t g1 = NintherPivot(A, lo, lo + segment); + ssize_t g2 = NintherPivot(A, lo + segment, lo + segment * 2); + ssize_t g3 = NintherPivot(A, lo + segment * 2, hi); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } + default: + { + return lo; + } + } +} + +wxArrayString QuickSortPivotText() +{ + wxArrayString sl; + + sl.Add(_("First Item")); + sl.Add(_("Last Item")); + sl.Add(_("Middle Item")); + sl.Add(_("Random Item")); + sl.Add(_("Median of Three")); + sl.Add(_("Random Median of Three")); + sl.Add(_("Median of Five")); + sl.Add(_("Random Median of Five")); + sl.Add(_("Median of Seven")); + sl.Add(_("Random Median of Seven")); + sl.Add(_("Ninther")); + sl.Add(_("Random Ninther")); + sl.Add(_("Median of Nine")); + sl.Add(_("Random Median of Nine")); + sl.Add(_("Median of Fifteen")); + sl.Add(_("Median of Three Ninther")); + return sl; +} + +// **************************************************************************** +// *** Quick Sort LR (in-place, pointers at left and right, pivot is middle element) + +// by myself (Timo Bingmann), based on Hoare's original code + +void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) +{ + // pick pivot and watch + ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); + std::atomic p1, i1, j1; + + value_type pivot = A[p]; + p1.store(p); + A.watch(&p1, 2); + + ssize_t i = lo, j = hi; + i1.store(i); + j1.store(j); + A.watch(&i1, 3); + A.watch(&j1, 3); + + while (i <= j) + { + while (A[i] < pivot) + { + i++; + i1.store(i); + } + + + while (A[j] > pivot) + { + j--; + j1.store(j); + } + + if (i <= j) + { + A.swap(i, j); + + // follow pivot if it is swapped + if (p == i) p = j; + else if (p == j) p = i; + p1.store(p); + + i++, j--; + i1.store(i); + j1.store(j); + } + } + + A.unwatch_all(); + + if (lo < j) + QuickSortLR(A, lo, j); + + if (i < hi) + QuickSortLR(A, i, hi); +} + +void QuickSortLR(SortArray& A) +{ + return QuickSortLR(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) + +// by myself (Timo Bingmann), based on CLRS' 3rd edition + +size_t PartitionLL(SortArray& A, size_t lo, size_t hi) +{ + // pick pivot and move to back + size_t p = QuickSortSelectPivot(A, lo, hi); + + value_type pivot = A[p]; + A.swap(p, hi - 1); + A.mark(hi - 1); + + ssize_t i = lo; + std::atomic i1; + i1.store(i); + A.watch(&i1, 3); + + for (size_t j = lo; j < hi - 1; ++j) + { + if (A[j] <= pivot) { + A.swap(i, j); + ++i; + i1.store(i); + } + } + + A.swap(i, hi - 1); + A.unmark(hi - 1); + A.unwatch_all(); + + return i; +} + +void QuickSortLL(SortArray& A, size_t lo, size_t hi) +{ + if (lo + 1 < hi) + { + size_t mid = PartitionLL(A, lo, hi); + + QuickSortLL(A, lo, mid); + QuickSortLL(A, mid+1, hi); + } +} + +void QuickSortLL(SortArray& A) +{ + return QuickSortLL(A, 0, A.size()); +} + +// **************************************************************************** +// *** Quick Sort Ternary (in-place, two pointers at left, pivot is first element and moved to right) + +// by myself (Timo Bingmann), loosely based on multikey quicksort by B&S + +void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi <= lo) return; + + int cmp; + + // pick pivot and swap to back + ssize_t piv = QuickSortSelectPivot(A, lo, hi + 1); + A.swap(piv, hi); + A.mark(hi); + + const value_type& pivot = A[hi]; + + // schema: |p === |i <<< | ??? |j >>> |q === |piv + ssize_t i = lo, j = hi - 1; + ssize_t p = lo, q = hi - 1; + std::atomic i1, j1; + i1.store(i); + j1.store(j); + A.watch(&i1, 3); + A.watch(&j1, 3); + + for (;;) + { + // partition on left + while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) + { + if (cmp == 0) { + A.mark(p, 4); + A.swap(i, p++); + } + ++i; + i1.store(i); + } + + // partition on right + while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) + { + if (cmp == 0) { + A.mark(q, 4); + A.swap(j, q--); + } + --j; + j1.store(j); + } + + if (i > j) break; + + // swap item between < > regions + A.swap(i++, j--); + i1.store(i); + j1.store(j); + } + + // swap pivot to right place + A.swap(i, hi); + A.mark_swap(i, hi); + + ssize_t num_less = i - p; + ssize_t num_greater = q - j; + + // swap equal ranges into center, but avoid swapping equal elements + j = i - 1; i = i + 1; + i1.store(i); + j1.store(j); + + ssize_t pe = lo + std::min(p - lo, num_less); + for (ssize_t k = lo; k < pe; k++, j--) { + j1.store(j); + A.swap(k, j); + A.mark_swap(k, j); + } + + ssize_t qe = hi - 1 - std::min(hi - 1 - q, num_greater - 1); // one already greater at end + for (ssize_t k = hi - 1; k > qe; k--, i++) { + i1.store(i); + A.swap(i, k); + A.mark_swap(i, k); + } + + A.unwatch_all(); + A.unmark_all(); + + QuickSortTernaryLR(A, lo, lo + num_less - 1); + QuickSortTernaryLR(A, hi - num_greater + 1, hi); +} + +void QuickSortTernaryLR(SortArray& A) +{ + return QuickSortTernaryLR(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) + +// by myself (Timo Bingmann) + +std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) +{ + // pick pivot and swap to back + ssize_t p = QuickSortSelectPivot(A, lo, hi); + + value_type pivot = A[p]; + A.swap(p, hi - 1); + A.mark(hi - 1); + + ssize_t i = lo, k = hi - 1; + std::atomic i1; + i1.store(i); + A.watch(&i1, 3); + + for (ssize_t j = lo; j < k; ++j) + { + int cmp = A[j].cmp(pivot); // ternary comparison + if (cmp == 0) { + A.swap(--k, j); + --j; // reclassify A[j] + A.mark(k, 4); + } + else if (cmp < 0) { + A.swap(i++, j); + i1.store(i); + } + } + + // unwatch i, because the pivot is swapped there + // in the first step of the following swap loop. + A.unwatch_all(); + + ssize_t j = i + (hi - k); + + for (ssize_t s = 0; s < hi - k; ++s) { + A.swap(i + s, hi - 1 - s); + A.mark_swap(i + s, hi - 1 - s); + } + A.unmark_all(); + + return std::make_pair((ssize_t)i, j); +} + +void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) +{ + if (lo + 1 < hi) + { + std::pair mid = PartitionTernaryLL(A, lo, hi); + + QuickSortTernaryLL(A, lo, mid.first); + QuickSortTernaryLL(A, mid.second, hi); + } +} + +void QuickSortTernaryLL(SortArray& A) +{ + return QuickSortTernaryLL(A, 0, A.size()); +} + +// **************************************************************************** +// *** Dual-Pivot Quick Sort + +// by Sebastian Wild + +void dualPivotYaroslavskiy(class SortArray& a, int left, int right) +{ + if (right > left) + { + if (a[left] > a[right]) { + a.swap(left, right); + } + + const value_type p = a[left]; + const value_type q = a[right]; + + a.mark(left); + a.mark(right); + + ssize_t l = left + 1; + ssize_t g = right - 1; + ssize_t k = l; + std::atomic l1, g1, k1; + l1.store(l); + g1.store(g); + k1.store(k); + + a.watch(&l1, 3); + a.watch(&g1, 3); + a.watch(&k1, 3); + + while (k <= g) + { + if (a[k] < p) { + a.swap(k, l); + ++l; + l1.store(l); + } + else if (a[k] >= q) { + while (a[g] > q && k < g) + { + --g; + g1.store(g); + } + a.swap(k, g); + --g; + g1.store(g); + if (a[k] < p) { + a.swap(k, l); + ++l; + l1.store(l); + } + } + ++k; + k1.store(k); + } + --l; + ++g; + l1.store(l); + g1.store(g); + a.swap(left, l); + a.swap(right, g); + + a.unmark_all(); + a.unwatch_all(); + + dualPivotYaroslavskiy(a, left, l - 1); + dualPivotYaroslavskiy(a, l + 1, g - 1); + dualPivotYaroslavskiy(a, g + 1, right); + } +} + +void QuickSortDualPivot(class SortArray& a) +{ + return dualPivotYaroslavskiy(a, 0, a.size()-1); +} + +// **************************************************************************** +// *** Bubble Sort + +void BubbleSort(SortArray& A) +{ + for (size_t i = 0; i < A.size()-1; ++i) + { + for (size_t j = 0; j < A.size()-1 - i; ++j) + { + if (A[j] > A[j + 1]) + { + A.swap(j, j+1); + } + } + } +} + +void OptimizedBubbleSort(SortArray& A) +{ + for (size_t i = 0; i < A.size() - 1; ++i) + { + bool sorted = true; + for (size_t j = 0; j < A.size() - 1 - i; ++j) + { + if (A[j] > A[j + 1]) + { + A.swap(j, j + 1); + sorted = false; + } + } + if (sorted == true) { break; } + } +} + +void TargetedBubbleSort(SortArray& A) +{ + bool sorted = false; + size_t target = A.size() - 1, lastSwapped = 0; + while (!sorted) + { + sorted = true; + for (size_t i = 0; i < target; ++i) + { + if (A[i] > A[i + 1]) + { + A.swap(i, i + 1); + lastSwapped = i; + sorted = false; + } + } + target = lastSwapped; + } +} + +// **************************************************************************** +// *** Cocktail Shaker Sort + +// from http://de.wikibooks.org/wiki/Algorithmen_und_Datenstrukturen_in_C/_Shakersort + +void CocktailShakerSort(SortArray& A) +{ + size_t lo = 0, hi = A.size()-1, mov = lo; + + while (lo < hi) + { + for (size_t i = hi; i > lo; --i) + { + if (A[i-1] > A[i]) + { + A.swap(i-1, i); + mov = i; + } + } + + lo = mov; + + for (size_t i = lo; i < hi; ++i) + { + if (A[i] > A[i+1]) + { + A.swap(i, i+1); + mov = i; + } + } + + hi = mov; + } +} + +void DualCocktailShakerSort(SortArray& A) +{ + size_t lo = 0, hi = A.size() - 1; + while (lo < hi) + { + size_t lo_mov = 0, hi_mov = 0; + for (size_t i = lo + 1, j = hi - 1; i <= hi; ++i, --j) + { + if (A[i - 1] > A[i]) + { + A.swap(i - 1, i); + lo_mov = i; + } + if (A[j + 1] < A[j]) + { + A.swap(j + 1, j); + hi_mov = j; + } + } + lo = hi_mov; + hi = lo_mov; + } +} + +// **************************************************************************** +// *** Circle Sort + +bool CircleSortRec(SortArray& A, size_t low, size_t high, size_t len) +{ + bool swapped = false; + if (low == high) { return false; } + size_t lo = low, hi = high; + while (lo < hi) + { + if (hi < len && A[lo] > A[hi]) + { + A.swap(lo, hi); + swapped = true; + } + ++lo; --hi; + } + size_t mid = (high - low) / 2; + bool firstHalf = CircleSortRec(A, low, low + mid, len); + bool secondHalf = false; + if (low + mid + 1 < len) + { + secondHalf = CircleSortRec(A, low + mid + 1, high, len); + } + return swapped || firstHalf || secondHalf; +} + +void CircleSort(SortArray& A) +{ + size_t len = A.size(), n = 1; + for (; n < len; n *= 2) {} + while (CircleSortRec(A, 0, n - 1, len)) {} +} + +bool CircleSortIte(SortArray& A, size_t length, size_t arr_len) +{ + bool swapped = false; + for (size_t gap = length / 2; gap > 0; gap /= 2) + { + for (size_t start = 0; start + gap < arr_len; start += 2 * gap) + { + size_t high = start + 2 * gap - 1, low = start; + while (low < high) + { + if (high < arr_len && A[low] > A[high]) + { + A.swap(low, high); + swapped = true; + } + ++low; --high; + } + } + } + return swapped; +} + +void CircleSort2(SortArray& A) +{ + size_t len = A.size(), n = 1; + for (; n < len; n *= 2) {} + while (CircleSortIte(A, n, len)) {} +} + +void IntroCircleSort(SortArray& A) +{ + size_t len = A.size(), threshold = 0, n = 1, iterations = 0; + for (; n < len; n *= 2, ++threshold) {} + threshold /= 2; + do + { + ++iterations; + if (iterations >= threshold) + { + InsertSort(A, 0, len); + break; + } + } + while (CircleSortRec(A, 0, n - 1, len)); +} + +void IntroIteCircleSort(SortArray& A) +{ + size_t len = A.size(), threshold = 0, n = 1, iterations = 0; + for (; n < len; n *= 2, ++threshold) {} + threshold /= 2; + do + { + ++iterations; + if (iterations >= threshold) + { + InsertSort(A, 0, len); + break; + } + } while (CircleSortIte(A, n, len)); +} + +// **************************************************************************** +// *** Gnome Sort + +// from http://en.wikipediA.org/wiki/Gnome_sort + +void GnomeSort(SortArray& A) +{ + for (size_t i = 1; i < A.size(); ) + { + if (A[i] >= A[i-1]) + { + ++i; + } + else + { + A.swap(i, i-1); + if (i > 1) --i; + } + } +} + +void OptimizedGnomeSort(SortArray& A) +{ + size_t prev = 0; + for (size_t i = 1; i < A.size(); ) + { + if (i == 0 || A[i] >= A[i - 1]) + { + if (prev != 0) { i += prev; prev = 0; } + ++i; + } + else + { + A.swap(i, i - 1); + --i; ++prev; + } + } +} + +// **************************************************************************** +// *** Comb Sort + +// from http://en.wikipediA.org/wiki/Comb_sort + +void CombSort(SortArray& A) +{ + const double shrink = 1.3; + + bool swapped = false; + size_t gap = A.size(); + + while ((gap > 1) || swapped) + { + if (gap > 1) { + gap = (size_t)((float)gap / shrink); + } + + swapped = false; + + for (size_t i = 0; gap + i < A.size(); ++i) + { + if (A[i] > A[i + gap]) + { + A.swap(i, i+gap); + swapped = true; + } + } + } +} + +// **************************************************************************** +// *** Odd-Even Sort + +// from http://en.wikipediA.org/wiki/Odd%E2%80%93even_sort + +void OddEvenSort(SortArray& A) +{ + bool sorted = false; + + while (!sorted) + { + sorted = true; + + for (size_t i = 1; i < A.size()-1; i += 2) + { + if(A[i] > A[i+1]) + { + A.swap(i, i+1); + sorted = false; + } + } + + for (size_t i = 0; i < A.size()-1; i += 2) + { + if(A[i] > A[i+1]) + { + A.swap(i, i+1); + sorted = false; + } + } + } +} + +// **************************************************************************** +// *** Shell Sort + +// with gaps by Robert Sedgewick from http://www.cs.princeton.edu/~rs/shell/shell.c + +void ShellSort(SortArray& A) +{ + size_t incs[16] = { 1391376, 463792, 198768, 86961, 33936, + 13776, 4592, 1968, 861, 336, + 112, 48, 21, 7, 3, 1 }; + + for (size_t k = 0; k < 16; k++) + { + for (size_t h = incs[k], i = h; i < A.size(); i++) + { + value_type v = A[i]; + size_t j = i; + + while (j >= h && A[j-h] > v) + { + A.set(j, A[j-h]); + j -= h; + } + + A.set(j, v); + } + } +} + +// **************************************************************************** +// *** Heap Sort + +// heavily adapted from http://www.codecodex.com/wiki/Heapsort + +bool isPowerOfTwo(size_t x) +{ + return ((x != 0) && !(x & (x - 1))); +} + +uint32_t prevPowerOfTwo(uint32_t x) +{ + x |= x >> 1; x |= x >> 2; x |= x >> 4; + x |= x >> 8; x |= x >> 16; + return x - (x >> 1); +} + +int largestPowerOfTwoLessThan(int n) +{ + int k = 1; + while (k < n) k = k << 1; + return k >> 1; +} + +void HeapSort(SortArray& A) +{ + size_t n = A.size(), i = n / 2; + + // mark heap levels with different colors + for (size_t j = i; j < n; ++j) + A.mark(j, log(prevPowerOfTwo(j+1)) / log(2) + 4); + + while (1) + { + if (i > 0) { + // build heap, sift A[i] down the heap + i--; + } + else { + // pop largest element from heap: swap front to back, and sift + // front A[0] down the heap + n--; + if (n == 0) return; + A.swap(0,n); + + A.mark(n); + if (n+1 < A.size()) A.unmark(n+1); + } + + size_t parent = i; + size_t child = i*2 + 1; + + // sift operation - push the value of A[i] down the heap + while (child < n) + { + if (child + 1 < n && A[child + 1] > A[child]) { + child++; + } + if (A[child] > A[parent]) { + A.swap(parent, child); + parent = child; + child = parent*2+1; + } + else { + break; + } + } + + // mark heap levels with different colors + A.mark(i, log(prevPowerOfTwo(i+1)) / log(2) + 4); + } + +} + +// **************************************************************************** +// *** Radix Sort (counting sort, most significant digit (MSD) first, in-place redistribute) + +// by myself (Timo Bingmann) + +void RadixSortMSD2(SortArray& A, size_t lo, size_t hi, size_t depth) +{ + A.mark(lo); A.mark(hi-1); + + // radix and base calculations + const unsigned int RADIX = 4; + + unsigned int pmax = floor( log(A.array_max()+1) / log(RADIX) ); + ASSERT(depth <= pmax); + + size_t base = pow(RADIX, pmax - depth); + + // count digits + std::vector count(RADIX, 0); + + for (size_t i = lo; i < hi; ++i) + { + size_t r = A[i].get() / base % RADIX; + ASSERT(r < RADIX); + count[r]++; + } + + // inclusive prefix sum + std::vector bkt(RADIX, 0); + std::partial_sum(count.begin(), count.end(), bkt.begin()); + + // mark bucket boundaries + for (size_t i = 0; i < bkt.size(); ++i) { + if (bkt[i] == 0) continue; + A.mark(lo + bkt[i]-1, 3); + } + + // reorder items in-place by walking cycles + for (size_t i=0, j; i < (hi-lo); ) + { + while ( (j = --bkt[ (A[lo+i].get() / base % RADIX) ]) > i ) + { + A.swap(lo + i, lo + j); + } + i += count[ (A[lo+i].get() / base % RADIX) ]; + } + + A.unmark_all(); + + // no more depth to sort? + if (depth+1 > pmax) return; + + // recurse on buckets + size_t sum = lo; + for (size_t i = 0; i < RADIX; ++i) + { + if (count[i] > 1) + RadixSortMSD2(A, sum, sum+count[i], depth+1); + sum += count[i]; + } +} + +void RadixSortMSD2(SortArray& A) +{ + return RadixSortMSD2(A, 0, A.size(), 0); +} + +/* + MIT License + + Copyright (c) 2019 w0rthy + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +size_t maxLog(SortArray& A, size_t n, size_t base) +{ + int max = A[0]; + for (size_t i = 1, j = n - 1; i <= j; ++i, --j) + { + int ele1 = A[i].get(), ele2 = A[j]; + if (ele1 > max) { max = ele1; } + if (ele2 > max) { max = ele2; } + } + size_t digit = static_cast(log(max) / log(base)); + return digit; +} + +int getDigit2(int a, double power, int radix) +{ + double digit = (a / static_cast(pow(radix, power)) % radix); + return static_cast(digit); +} + +void transcribeMSD(SortArray& A, std::vector>& registers, size_t start, size_t min) +{ + size_t total = start, temp = 0; + for (const std::vector& arr : registers) + { + total += arr.size(); + } + + for (int i = registers.size() - 1; i >= 0; --i) + { + for (int j = registers[i].size() - 1; j >= 0; --j) + { + size_t loc = total + min - temp - 1; + A.set(loc, registers[i].at(j)); + A[loc].get(); + ++temp; + } + } +} + +void radixMSD(SortArray& A, size_t len, size_t min, size_t max, size_t radix, double pow) +{ + if (min >= max || pow < 0) { return; } + A.mark(min); A.mark(max - 1); + + std::vector> registers(radix, std::vector()); + + for (size_t i = min; i < max; ++i) + { + int ele = A[i].get(); + int digit = getDigit2(ele, pow, radix); + registers[digit].push_back(A[i]); + } + + transcribeMSD(A, registers, 0, min); + A.unmark_all(); + + size_t sum = 0; + for (size_t i = 0; i < registers.size(); ++i) + { + radixMSD(A, len, sum + min, sum + min + registers[i].size(), radix, pow - 1); + sum += registers[i].size(); + registers[i].clear(); + } +} + +void RadixSortMSD(SortArray& A) +{ + size_t n = A.size(), maxPow = maxLog(A, n, 4); + radixMSD(A, n, 0, n, 4, (double)maxPow); +} + +// **************************************************************************** +// *** Radix Sort (counting sort, least significant digit (LSD) first, out-of-place redistribute) + +// by myself (Timo Bingmann) + +void RadixSortLSD(SortArray& A) +{ + // radix and base calculations + const unsigned int RADIX = 4; + + unsigned int pmax = ceil( log(A.array_max()+1) / log(RADIX) ); + + for (unsigned int p = 0; p < pmax; ++p) + { + size_t base = pow(RADIX, p); + + // count digits and copy data + std::vector count(RADIX, 0); + std::vector copy(A.size()); + + for (size_t i = 0; i < A.size(); ++i) + { + size_t r = (copy[i] = A[i]).get() / base % RADIX; + ASSERT(r < RADIX); + count[r]++; + } + + // exclusive prefix sum + std::vector bkt(RADIX+1, 0); + std::partial_sum(count.begin(), count.end(), bkt.begin()+1); + + // mark bucket boundaries + for (size_t i = 0; i < bkt.size()-1; ++i) { + if (bkt[i] >= A.size()) continue; + A.mark(bkt[i], 3); + } + + // redistribute items back into array (stable) + for (size_t i=0; i < A.size(); ++i) + { + size_t r = copy[i].get() / base % RADIX; + A.set( bkt[r]++, copy[i] ); + } + + A.unmark_all(); + } +} + +// **************************************************************************** +// *** In-Place Radix Sort LSD +/* + Copyright (c) 2019 w0rthy + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void shiftElement(SortArray& A, size_t start, size_t end) +{ + if (start < end) + { + while (start < end) + { + A[start].get(); + A.swap(start, start + 1); + ++start; + } + } + else + { + while (start > end) + { + A[start].get(); + A.swap(start, start - 1); + --start; + } + } +} + +void InPlaceRadixSortLSD(SortArray& A) +{ + size_t pos = 0, n = A.size(); + int bucket = 20; + std::vector buckets(bucket - 1, 0); + size_t maxPow = maxLog(A, n, bucket); + for (size_t p = 0; p <= maxPow; ++p) + { + for (size_t i = 0; i < buckets.size(); ++i) { buckets[i] = n - 1; } + pos = 0; + for (size_t i = 0; i < n; ++i) + { + int ele = A[pos].get(); + int digit = getDigit2(ele, (double)p, bucket); + if (digit == 0) { ++pos; } + else + { + shiftElement(A, pos, buckets[digit - 1]); + for (size_t j = digit - 1; j > 0; --j) + { + buckets[j - 1] = buckets[j - 1] - 1; + } + } + } + } +} + +// **************************************************************************** +// *** Rotate Radix MSD/LSD Sort + +/* + Copyright (c) 2020-2021 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +static const int base = 4; + +int shift(int n, int q) +{ + while (q > 0) + { + n /= base; + --q; + } + return n; +} + +int binSearch(SortArray& A, int a, int b, int d, int p) +{ + while (a < b) + { + int m = (a + b) / 2; + int ele = A[m].get(); + int result = static_cast(getDigit2(static_cast(ele), static_cast(p), static_cast(base))); + if (result >= d) { b = m; } + else { a = m + 1; } + } + return a; +} + +void rotateMerge(SortArray& A, int a, int m, int b, int da, int db, int p) +{ + if (b - a < 2 || db - da < 2) { return; } + int dm = (da + db) / 2; + int m1 = binSearch(A, a, m, dm, p); + int m2 = binSearch(A, m, b, dm, p); + rotate(A, m1, m, m2); + m = m1 + (m2 - m); + rotateMerge(A, m, m2, b, dm, db, p); + rotateMerge(A, a, m1, m, da, dm, p); +} + +void rotateMergeSort(SortArray& A, int a, int b, int p) +{ + if (b - a < 2) { return; } + int m = (a + b) / 2; + rotateMergeSort(A, a, m, p); + rotateMergeSort(A, m, b, p); + rotateMerge(A, a, m, b, 0, base, p); +} + +int dist(SortArray& A, int a, int b, int p) +{ + rotateMergeSort(A, a, b, p); + return binSearch(A, a, b, 1, p); +} + +void RotateRadixSortMSD(SortArray& A) +{ + int len = static_cast(A.size()); + int q = static_cast(maxLog(A, static_cast(len), static_cast(base))); + int m = 0, i = 0, b = len; + while (i < len) + { + int p = 0; + if (b - i < 1) { p = i; } + else { p = dist(A, i, b, q); } + if (q == 0) + { + m += base; + int t = m / base; + while (t % base == 0) + { + t /= base; + ++q; + } + i = b; + while (b < len) + { + int ele = A[b].get(); + if (shift(ele, q + 1) == shift(m, q + 1)) { ++b; } + else { break; } + } + } + else + { + b = p; + --q; + } + } +} + +void RotateRadixSortLSD(SortArray& A) +{ + int len = static_cast(A.size()); + int max = static_cast(maxLog(A, static_cast(len), static_cast(base))); + for (int i = 0; i <= max; ++i) + { + rotateMergeSort(A, 0, len, i); + } +} + +// **************************************************************************** +// *** Use STL Sorts via Iterator Adapters + +void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) +{ + int compareVal = 0; + if (isMax) { compareVal = -1; } + else { compareVal = 1; } + while (root <= dist / 2) + { + size_t leaf = 2 * root; + int compVal = 0; + + if (leaf < dist) + { + if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } + else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } + if (compVal == compareVal) { ++leaf; } + } + + if (A[start + root - 1] < A[start + leaf - 1]) { compVal = -1; } + else if (A[start + root - 1] > A[start + leaf - 1]) { compVal = 1; } + else { compVal = 0; } + + if (compVal == compareVal) + { + A.swap(start + root - 1, start + leaf - 1); + root = leaf; + } + else { break; } + } +} + +void heapifyArr(SortArray& A, size_t low, size_t high, bool isMax) +{ + size_t len = high - low; + for (size_t i = len / 2; i >= 1; --i) + { + siftDown(A, i, len, low, isMax); + } +} + +void reverseArr(SortArray& A, size_t start, size_t len) +{ + for (size_t i = start; i < start + ((len - start + 1) / 2); ++i) + { + A.swap(i, start + len - 1); + } +} + +void HeapSort2(SortArray& A, size_t start, size_t len, bool isMax) +{ + heapifyArr(A, start, len, isMax); + for (size_t i = len - start; i > 1; --i) + { + A.swap(start, start + i - 1); + siftDown(A, 1, i - 1, start, isMax); + } + + if (!isMax) + { + reverseArr(A, start, start + len - 1); + } +} + +size_t floorLogBaseTwo(size_t a) +{ + return static_cast(floor(log(a) / log(2))); +} + +value_type gccmedianof3(SortArray& A, size_t left, size_t mid, size_t right) +{ + if (A[left] < A[mid]) + { + if (A[mid] < A[right]) + { + A.swap(left, mid); + } + else if (A[left] < A[right]) + { + A.swap(left, right); + } + } + else if (A[left] < A[right]) { return A[left]; } + else if (A[mid] < A[right]) + { + A.swap(left, right); + } + else + { + A.swap(mid, right); + } + return A[left]; +} + +value_type medianof3(SortArray& A, size_t left, size_t mid, size_t right) +{ + if (A[right] < A[left]) { A.swap(left, right); } + if (A[mid] < A[left]) { A.swap(mid, left); } + if (A[right] < A[mid]) { A.swap(right, mid); } + return A[mid]; +} + +size_t partitionArr(SortArray& A, size_t lo, size_t hi, value_type x) +{ + size_t i = lo, j = hi; + while (true) + { + while (A[i] < x) { ++i; } + --j; + while (x < A[j]) { --j; } + + if (!(i < j)) { return i; } + A.swap(i, j); + ++i; + } +} + +void introsortLoop(SortArray& A, size_t lo, size_t hi, size_t depth) +{ + size_t threshold = 16; + while (hi - lo > threshold) + { + if (depth == 0) + { + HeapSort2(A, lo, hi, true); + return; + } + --depth; + size_t p = partitionArr(A, lo, hi, medianof3(A, lo, lo + ((hi - lo) / 2), hi - 1)); + introsortLoop(A, p, hi, depth); + hi = p; + } + return; +} + +void StlSort(SortArray& A) +{ + size_t n = A.size(); + introsortLoop(A, 0, n, 2 * floorLogBaseTwo(n)); + InsertionSort(A); +} + +void StlSort2(SortArray& A) +{ + std::sort(MyIterator(&A, 0), MyIterator(&A, A.size())); +} + +void StlStableSort(SortArray& A) +{ + std::stable_sort(MyIterator(&A, 0), MyIterator(&A, A.size())); +} + +void StlHeapSort2(SortArray& A) +{ + std::make_heap(MyIterator(&A, 0), MyIterator(&A, A.size())); + std::sort_heap(MyIterator(&A, 0), MyIterator(&A, A.size())); +} + +void StlHeapSort(SortArray& A) +{ + HeapSort2(A, 0, A.size(), true); +} + +// **************************************************************************** +// *** BogoSort and more slow sorts + +// by myself (Timo Bingmann) + +bool BogoCheckSorted(SortArray& A) +{ + size_t i; + A.mark(0); + for (i = 1; i < A.size(); ++i) + { + if (A[i - 1] > A[i]) break; + A.mark(i); + } + + if (i == A.size()) { + // this is amazing. + return true; + } + + // unmark + while (i > 0) A.unmark(i--); + A.unmark(0); + + return false; +} + +void BogoSort(SortArray& A) +{ + // keep a permutation of [0,size) + std::vector perm(A.size()); + + for (size_t i = 0; i < A.size(); ++i) + perm[i] = i; + + while (1) + { + // check if array is sorted + if (BogoCheckSorted(A)) break; + + // pick a random permutation of indexes + std::shuffle(perm.begin(), perm.end(), gen1); + + // permute array in-place + std::vector pmark(A.size(), 0); + + for (size_t i = 0; i < A.size(); ++i) + { + if (pmark[i]) continue; + + // walk a cycle + size_t j = i; + + //std::cout << "cycle start " << j << " -> " << perm[j] << "\n"; + + while ( perm[j] != i ) + { + ASSERT(!pmark[j]); + A.swap(j, perm[j]); + pmark[j] = 1; + + j = perm[j]; + //std::cout << "cycle step " << j << " -> " << perm[j] << "\n"; + } + //std::cout << "cycle end\n"; + + ASSERT(!pmark[j]); + pmark[j] = 1; + } + + //std::cout << "permute end\n"; + + for (size_t i = 0; i < A.size(); ++i) + ASSERT(pmark[i]); + } +} + +void BozoSort(SortArray& A) +{ + srand(time(nullptr)); + + while (1) + { + // check if array is sorted + if (BogoCheckSorted(A)) break; + + // swap two random items + A.swap(rand() % A.size(), rand() % A.size()); + } +} + +void flip(SortArray& A, size_t high) +{ + size_t low = 0; + while (low < high) + { + A[low].get(); + A.swap(low, high); + ++low; --high; + } +} + +size_t find_max(SortArray& A, size_t n) // Optimized find_max method, searching the max element in n/2 time +{ + size_t max = 0; + for (size_t low = 1, hi = n; low <= hi; ++low, --hi) + { + if (A[low] > A[max]) + { + max = low; + } + if (A[hi] > A[max]) + { + max = hi; + } + } + return max; +} + +void PancakeSort(SortArray& A) +{ + size_t n = A.size() - 1; + for (size_t cur_size = n; cur_size >= 1; --cur_size) + { + size_t max_idx = find_max(A, cur_size); + if (max_idx != cur_size) + { + if (max_idx > 0) { flip(A, max_idx); } + flip(A, cur_size); + } + } +} + + +// **************************************************************************** +// *** Optimized Pancake Sort +/* + The MIT License (MIT) + + Copyright (c) 2021-2023 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +void flip2(SortArray& A, size_t high) +{ + if (high > 0) { --high; } + size_t low = 0; + while (low < high) + { + A[low].get(); + A.swap(low, high); + ++low; --high; + } +} + + +bool mergeFlip(SortArray& A, size_t h1, size_t h2) +{ + if (h1 == 1 && h2 == 1) + { + if (A[0] > A[1]) { flip2(A, 2); } + return true; + } + size_t n = h1 + h2, m = n / 2; + if (h2 < h1) + { + if (h2 < 1) { return true; } + size_t i = 0, j = h2; + while (i < j) + { + size_t k = (i + j) / 2, loc = n - 1 - k; + A[loc].get(); + if (A[n - 1 - k - m] > A[loc]) { i = k + 1; } + else { j = k; } + } + flip2(A, n - m - i); + flip2(A, n - i); + if (mergeFlip(A, h2 - i, i + m - h2)) { flip2(A, m); } + flip2(A, n); + if (!mergeFlip(A, i, n - m - i)) { flip2(A, n - m); } + } + else + { + if (h1 < 1) { return false; } + size_t i = 0, j = h1; + while (i < j) + { + size_t k = (i + j) / 2; + A[k].get(); + if (A[k] < A[k + m]) { i = k + 1; } + else { j = k; } + } + flip2(A, i); + flip2(A, i + m); + if (mergeFlip(A, i + m - h1, h1 - i)) { flip2(A, m); } + flip2(A, n); + if (!mergeFlip(A, n - m - i, i)) { flip2(A, n - m); } + } + return true; +} + +void sortFlip(SortArray& A, size_t n) +{ + if (n < 2) { return; } + size_t h = n / 2; + sortFlip(A, h); + flip2(A, n); + sortFlip(A, n - h); + mergeFlip(A, n - h, h); +} + +void OptimizedPancakeSort(SortArray& A) +{ + sortFlip(A, A.size()); +} + +void BeadSort(SortArray& A) +{ + int max = A[0]; + int len = A.size(); + for (int n = 1; n < len; ++n) + { + int m = A[n].get(); + if (m > max) + { max = m; } + } + + std::vector> beads(len, std::vector(max, 0)); + + for (int i = 0; i < len; ++i) + { + int n = A[i].get(); + for (int j = 0; j < n; ++j) + { beads[i][j] = 1; } + } + + for (int j = 0; j < max; ++j) + { + int sum = 0; + for (int i = 0; i < len; ++i) + { + sum += beads[i][j]; + beads[i][j] = 0; + } + for (int i = len - 1; i >= len - sum; --i) + { + size_t k = static_cast(i); + A.set(k, ArrayItem(j + 1)); + A[k].get(); + } + } +} + +/* + MIT License + + Copyright (c) 2020 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void GravitySort(SortArray& A) +{ + int n = A.size(); + int min = A[0], max = A[0]; + for (int i = 1; i < n; ++i) + { + int ele = A[i].get(); + if (ele < min) { min = ele; } + if (ele > max) { max = ele; } + } + std::vector x(n, 0); + std::vector y(max - min + 1, 0); + for (int i = 0; i < n; ++i) + { + int ele = A[i].get(); + x[i] = ele - min; + y[ele - min] = y[ele - min] + 1; + } + + int y_size = static_cast(y.size() - 1); + for (int i = y_size; i > 0; --i) + { + y[i - 1] = y[i - 1] += y[i]; + } + + for (int j = y_size; j >= 0; --j) + { + for (int i = 0; i < n; ++i) + { + int val = 0, val2 = 0; + if (i >= n - y[j]) { val = 1; } + if (x[i] >= j) { val2 = 1; } + int inc = val - val2, ele = A[i].get(); + A.set(i, ArrayItem(ele + inc)); + } + } +} + +/* + MIT License + + Copyright (c) 2024 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +void dualSwap(SortArray& A, std::vector& keys, int a, int b) +{ + size_t z = static_cast(a); + A[z].get(); + A.swap(z, static_cast(b)); + value_type temp = keys[a]; + keys[a] = keys[b]; + keys[b] = temp; +} + +void reversal(SortArray& A, std::vector& keys, int a, int b) +{ + while (b - a > 1) { --b; dualSwap(A, keys, a, b); ++a; } +} + +bool isAdjacent(std::vector& keys, int a, int b, int N) +{ + return (keys[a] + 1) % N == keys[b] || (keys[b] + 1) % N == keys[a]; +} + +int findAdjacent(std::vector& keys, int e, int a, int N) +{ + while (!isAdjacent(keys, a, e, N)) { ++a; } + return a; +} + +void AdjacencyPancakeSort(SortArray& A) +{ + int a = 0, N = static_cast(A.size()), b = N; + if (N == 2) + { + reverseArr(A, a, a + 1); + return; + } + std::vector keys(N); + + for (int j = a; j < b; ++j) + { + int c = 0; + for (int i = a; i < b; ++i) + { + if (i == j) { continue; } + if (A[i] < A[j] || (A[i] == A[j] && i < j)) { ++c; } + } + keys[j - a] = ArrayItem(c); + } + + while (true) + { + int i = a; + while (i < b - 1 && isAdjacent(keys, i, i + 1, N)) { ++i; } + if (i == b - 1) { break; } + if (i == a) + { + int j = findAdjacent(keys, a, a + 2, N); + if (!isAdjacent(keys, j - 1, j, N)) + { reversal(A, keys, a, j); } + else + { + int k = findAdjacent(keys, a, j + 1, N); + if (!isAdjacent(keys, k - 1, k, N)) + { reversal(A, keys, a, k); } + else + { + reversal(A, keys, a, j + 1); + reversal(A, keys, a, j); + reversal(A, keys, a, k + 1); + reversal(A, keys, a, a + k - j); + } + } + } + else + { + int j = findAdjacent(keys, a, i + 1, N); + if (!isAdjacent(keys, j - 1, j, N)) + { reversal(A, keys, a, j); } + else + { + int k = findAdjacent(keys, i, i + 2, N); + if (k + 1 < b && isAdjacent(keys, k + 1, k, N)) + { + reversal(A, keys, a, i + 1); + reversal(A, keys, a, k + 1); + } + else + { + reversal(A, keys, a, k + 1); + reversal(A, keys, a, a + k - i); + if (!isAdjacent(keys, k - 1, k, N)) + { + if (j < k) + { + reversal(A, keys, a, k + 1); + reversal(A, keys, a, i + k - j + 1); + } + else + { + reversal(A, keys, a, j + 1); + reversal(A, keys, a, a + j - k); + } + } + } + } + } + } + + int i = a; + while (keys[i] != 0 && keys[i] != N - 1) { ++i; } + if (keys[i] == 0) + { + if (i == a) { return; } + reversal(A, keys, a, b); + i = b - 2 - (i - a); + } + else if (i == a) + { + reversal(A, keys, a, b); + return; + } + ++i; + reversal(A, keys, a, i); + reversal(A, keys, a, b); + reversal(A, keys, a, b - (i - a)); +} + +// **************************************************************************** +// *** Bitonic Sort + +// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm + +namespace BitonicSortNS { + +static const bool ASCENDING = true; // sorting direction + +static void compare(SortArray& A, int i, int j, bool dir) +{ + if (dir == (A[i] > A[j])) + A.swap(i, j); +} + +static void bitonicMerge(SortArray& A, int lo, int n, bool dir) +{ + if (n > 1) + { + int m = largestPowerOfTwoLessThan(n); + + for (int i = lo; i < lo + n - m; i++) + compare(A, i, i+m, dir); + + bitonicMerge(A, lo, m, dir); + bitonicMerge(A, lo + m, n - m, dir); + } +} + +static void bitonicSort(SortArray& A, int lo, int n, bool dir) +{ + if (n > 1) + { + int m = n / 2; + bitonicSort(A, lo, m, !dir); + bitonicSort(A, lo + m, n - m, dir); + bitonicMerge(A, lo, n, dir); + } +} + +} // namespace BitonicSortNS + +void BitonicSort(SortArray& A) +{ + BitonicSortNS::bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING); +} + +// **************************************************************************** +// *** Bitonic Sort as "Parallel" Sorting Network + +// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm + +// modified to first record the recursively generated swap sequence, and then +// sort it back into the order a parallel sorting network would perform the +// swaps in + +namespace BitonicSortNetworkNS { + +struct swappair_type +{ + // swapped positions + unsigned int i,j; + + // depth of recursions: sort / merge + unsigned int sort_depth, merge_depth; + + swappair_type(unsigned int _i, unsigned int _j, + unsigned int _sort_depth, unsigned int _merge_depth) + : i(_i), j(_j), + sort_depth(_sort_depth), merge_depth(_merge_depth) + { } + + // order relation for sorting swaps + bool operator < (const swappair_type& b) const + { + if (sort_depth != b.sort_depth) + return sort_depth > b.sort_depth; + + if (merge_depth != b.merge_depth) + return merge_depth < b.merge_depth; + + return i < b.i; + } +}; + +typedef std::vector sequence_type; +std::vector sequence; + +void replay(SortArray& A) +{ + for (sequence_type::const_iterator si = sequence.begin(); + si != sequence.end(); ++si) + { + if (A[si->i] > A[si->j]) + A.swap(si->i, si->j); + } +} + +static const bool ASCENDING = true; // sorting direction + +static void compare(SortArray& /* A */, unsigned int i, unsigned int j, bool dir, + unsigned int sort_depth, unsigned int merge_depth) +{ + // if (dir == (A[i] > A[j])) A.swap(i, j); + + if (dir) + sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); + else + sequence.push_back( swappair_type(j,i, sort_depth, merge_depth) ); +} + +static void bitonicMerge(SortArray& A, unsigned int lo, unsigned int n, bool dir, + unsigned int sort_depth, unsigned int merge_depth) +{ + if (n > 1) + { + unsigned int m = largestPowerOfTwoLessThan(n); + + for (unsigned int i = lo; i < lo + n - m; i++) + compare(A, i, i + m, dir, sort_depth, merge_depth); + + bitonicMerge(A, lo, m, dir, sort_depth, merge_depth+1); + bitonicMerge(A, lo + m, n - m, dir, sort_depth, merge_depth+1); + } +} + +static void bitonicSort(SortArray& A, unsigned int lo, unsigned int n, bool dir, + unsigned int sort_depth) +{ + if (n > 1) + { + unsigned int m = n / 2; + bitonicSort(A, lo, m, !dir, sort_depth+1); + bitonicSort(A, lo + m, n - m, dir, sort_depth+1); + bitonicMerge(A, lo, n, dir, sort_depth, 0); + } +} + +void sort(SortArray& A) +{ + sequence.clear(); + bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING, 0); + std::sort(sequence.begin(), sequence.end()); + replay(A); + sequence.clear(); +} + +} // namespace BitonicSortNS + +void BitonicSortNetwork(SortArray& A) +{ + BitonicSortNetworkNS::sort(A); +} + +// **************************************************************************** +// *** Batcher's Odd-Even Merge Sort as "Parallel" Sorting Network + +// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/oemen.htm + +// modified to first record the recursively generated swap sequence, and then +// sort it back into the order a parallel sorting network would perform the +// swaps in + +namespace BatcherSortNetworkNS { + +struct swappair_type +{ + // swapped positions + unsigned int i,j; + + // depth of recursions: sort / merge + unsigned int sort_depth, merge_depth; + + swappair_type(unsigned int _i, unsigned int _j, + unsigned int _sort_depth, unsigned int _merge_depth) + : i(_i), j(_j), + sort_depth(_sort_depth), merge_depth(_merge_depth) + { } + + // order relation for sorting swaps + bool operator < (const swappair_type& b) const + { + if (sort_depth != b.sort_depth) + return sort_depth > b.sort_depth; + + if (merge_depth != b.merge_depth) + return merge_depth > b.merge_depth; + + return i < b.i; + } +}; + +typedef std::vector sequence_type; +std::vector sequence; + +void replay(SortArray& A) +{ + for (sequence_type::const_iterator si = sequence.begin(); + si != sequence.end(); ++si) + { + if (A[si->i] > A[si->j]) + A.swap(si->i, si->j); + } +} + +static void compare(SortArray& A, unsigned int i, unsigned int j, + unsigned int sort_depth, unsigned int merge_depth) +{ + // skip all swaps beyond end of array + ASSERT(i < j); + if (j >= A.size()) return; + + sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); + + //if (A[i] > A[j]) A.swap(i, j); +} + +// lo is the starting position and n is the length of the piece to be merged, r +// is the distance of the elements to be compared +static void oddEvenMerge(SortArray& A, unsigned int lo, unsigned int n, unsigned int r, + unsigned int sort_depth, unsigned int merge_depth) +{ + unsigned int m = r * 2; + if (m < n) + { + // even subsequence + oddEvenMerge(A, lo, n, m, sort_depth, merge_depth+1); + // odd subsequence + oddEvenMerge(A, lo + r, n, m, sort_depth, merge_depth+1); + + for (unsigned int i = lo + r; i + r < lo + n; i += m) + compare(A, i, i + r, sort_depth, merge_depth); + } + else { + compare(A, lo, lo + r, sort_depth, merge_depth); + } +} + +// sorts a piece of length n of the array starting at position lo +static void oddEvenMergeSort(SortArray& A, unsigned int lo, unsigned int n, + unsigned int sort_depth) +{ + if (n > 1) + { + unsigned int m = n / 2; + oddEvenMergeSort(A, lo, m, sort_depth+1); + oddEvenMergeSort(A, lo + m, m, sort_depth+1); + oddEvenMerge(A, lo, n, 1, sort_depth, 0); + } +} + +void sort(SortArray& A) +{ + sequence.clear(); + + unsigned int n = largestPowerOfTwoLessThan(A.size()); + if (n != A.size()) n *= 2; + + oddEvenMergeSort(A, 0, n, 0); + std::sort(sequence.begin(), sequence.end()); + replay(A); + sequence.clear(); +} + +} // namespace BatcherSortNetworkNS + +void BatcherSortNetwork(SortArray& A) +{ + BatcherSortNetworkNS::sort(A); +} + +// **************************************************************************** +// *** Smooth Sort + +// from http://en.wikipediA.org/wiki/Smoothsort + +namespace SmoothSortNS { + +static const int LP[] = { + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, + 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, + 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, + 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, + 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, + 866988873 // the next number is > 31 bits. +}; + +static void sift(SortArray& A, int pshift, int head) +{ + // we do not use Floyd's improvements to the heapsort sift, because we + // are not doing what heapsort does - always moving nodes from near + // the bottom of the tree to the root. + + value_type val = A[head]; + + while (pshift > 1) + { + int rt = head - 1; + int lf = head - 1 - LP[pshift - 2]; + + if (val.cmp(A[lf]) >= 0 && val.cmp(A[rt]) >= 0) + break; + + if (A[lf].cmp(A[rt]) >= 0) { + A.set(head, A[lf]); + head = lf; + pshift -= 1; + } + else { + A.set(head, A[rt]); + head = rt; + pshift -= 2; + } + } + + A.set(head, val); +} + +static void trinkle(SortArray& A, int p, int pshift, int head, bool isTrusty) +{ + value_type val = A[head]; + + while (p != 1) + { + int stepson = head - LP[pshift]; + + if (A[stepson].cmp(val) <= 0) + break; // current node is greater than head. sift. + + // no need to check this if we know the current node is trusty, + // because we just checked the head (which is val, in the first + // iteration) + if (!isTrusty && pshift > 1) { + int rt = head - 1; + int lf = head - 1 - LP[pshift - 2]; + if (A[rt].cmp(A[stepson]) >= 0 || + A[lf].cmp(A[stepson]) >= 0) + break; + } + + A.set(head, A[stepson]); + + head = stepson; + //int trail = Integer.numberOfTrailingZeros(p & ~1); + int trail = __builtin_ctz(p & ~1); + p >>= trail; + pshift += trail; + isTrusty = false; + } + + if (!isTrusty) { + A.set(head, val); + sift(A, pshift, head); + } +} + +void sort(SortArray& A, int lo, int hi) +{ + int head = lo; // the offset of the first element of the prefix into m + + // These variables need a little explaining. If our string of heaps + // is of length 38, then the heaps will be of size 25+9+3+1, which are + // Leonardo numbers 6, 4, 2, 1. + // Turning this into a binary number, we get b01010110 = 0x56. We represent + // this number as a pair of numbers by right-shifting all the zeros and + // storing the mantissa and exponent as "p" and "pshift". + // This is handy, because the exponent is the index into L[] giving the + // size of the rightmost heap, and because we can instantly find out if + // the rightmost two heaps are consecutive Leonardo numbers by checking + // (p&3)==3 + + int p = 1; // the bitmap of the current standard concatenation >> pshift + int pshift = 1; + + while (head < hi) + { + if ((p & 3) == 3) { + // Add 1 by merging the first two blocks into a larger one. + // The next Leonardo number is one bigger. + sift(A, pshift, head); + p >>= 2; + pshift += 2; + } + else { + // adding a new block of length 1 + if (LP[pshift - 1] >= hi - head) { + // this block is its final size. + trinkle(A, p, pshift, head, false); + } else { + // this block will get merged. Just make it trusty. + sift(A, pshift, head); + } + + if (pshift == 1) { + // LP[1] is being used, so we add use LP[0] + p <<= 1; + pshift--; + } else { + // shift out to position 1, add LP[1] + p <<= (pshift - 1); + pshift = 1; + } + } + p |= 1; + head++; + } + + trinkle(A, p, pshift, head, false); + + while (pshift != 1 || p != 1) + { + if (pshift <= 1) { + // block of length 1. No fiddling needed + //int trail = Integer.numberOfTrailingZeros(p & ~1); + int trail = __builtin_ctz(p & ~1); + p >>= trail; + pshift += trail; + } + else { + p <<= 2; + p ^= 7; + pshift -= 2; + + // This block gets broken into three bits. The rightmost bit is a + // block of length 1. The left hand part is split into two, a block + // of length LP[pshift+1] and one of LP[pshift]. Both these two + // are appropriately heapified, but the root nodes are not + // necessarily in order. We therefore semitrinkle both of them + + trinkle(A, p >> 1, pshift + 1, head - LP[pshift] - 1, true); + trinkle(A, p, pshift, head - 1, true); + } + + head--; + } +} + +} // namespace SmoothSortNS + +void SmoothSort(SortArray& A) +{ + return SmoothSortNS::sort(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Stooge Sort + +void StoogeSort(SortArray& A, int i, int j) +{ + if (A[i] > A[j]) + { + A.swap(i, j); + } + + if (j - i + 1 >= 3) + { + int t = (j - i + 1) / 3; + + A.mark(i, 3); + A.mark(j, 3); + + StoogeSort(A, i, j-t); + StoogeSort(A, i+t, j); + StoogeSort(A, i, j-t); + + A.unmark(i); + A.unmark(j); + } +} + +void StoogeSort(SortArray& A) +{ + StoogeSort(A, 0, A.size()-1); +} + +void BadSort(SortArray& A) +{ + for (size_t i = 0; i < A.size(); i++) + { + size_t shortest = i; + for (size_t j = i; j < A.size(); j++) + { + bool isShortest = true; + for (size_t k = j + 1; k < A.size(); k++) + { + if (A[j] > A[k]) + { + isShortest = false; + break; + } + } + if (isShortest) + { + shortest = j; + break; + } + } + A.swap(i, shortest); + } +} + +// **************************************************************************** +// *** Slow Sort + +void SlowSort(SortArray& A, int i, int j) +{ + if (i >= j) return; + + int m = (i + j) / 2; + + SlowSort(A, i, m); + SlowSort(A, m+1, j); + + if (A[m] > A[j]) + A.swap(m, j); + + A.mark(j, 2); + + SlowSort(A, i, j-1); + + A.unmark(j); +} + +void SlowSort(SortArray& A) +{ + SlowSort(A, 0, A.size()-1); +} + +// **************************************************************************** +// *** Cycle Sort + +// Adapted from http://en.wikipedia.org/wiki/Cycle_sort + +void CycleSort(SortArray& vec_arr, ssize_t n) +{ + std::atomic cStart, cRank; + ssize_t cycleStart = 0; + cStart.store(cycleStart); + vec_arr.watch(&cStart, 16); + + ssize_t rank = 0; + cRank.store(rank); + vec_arr.watch(&cRank, 5); + + // Loop through the array to find cycles to rotate. + for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) + { + value_type& item = vec_arr.get_mutable(cycleStart); + cStart.store(cycleStart); + do { + // Find where to put the item. + rank = cycleStart; + for (ssize_t i = cycleStart + 1; i < n; ++i) + { + if (vec_arr[i] < item) + { + rank++; + cRank.store(rank); + } + } + + // If the item is already there, this is a 1-cycle. + if (rank == cycleStart) { + vec_arr.mark(rank, 2); + break; + } + + // Otherwise, put the item after any duplicates. + while (item == vec_arr[rank]) + { + rank++; + cRank.store(rank); + } + + // Put item into right place and colorize + counted_swap(vec_arr.get_mutable(rank), item); + vec_arr.mark(rank, 2); + + // Continue for rest of the cycle. + } while (rank != cycleStart); + } + + vec_arr.unwatch_all(); +} + +void CycleSort(SortArray& A) +{ + CycleSort(A, A.size()); +} + + +// **************************************************************************** +// *** Pairwise Sorting Network (Recursive and Iterative) +/* + Copyright (c) 2021 aphitorite + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void compSwap(SortArray& A, size_t a, size_t b) +{ + size_t n = A.size(); + if (b < n && A[a] > A[b]) { A.swap(a, b); } +} +void PairwiseMerge(SortArray& A, size_t a, size_t b) +{ + size_t m = (a + b) / 2, m1 = (a + m) / 2, g = m - m1; + for (size_t i = 0; m1 + i < m; ++i) + { + for (size_t j = m1, k = g; k > 0; k >>= 1, j -= k - (i & k)) + { + compSwap(A, j + i, j + i + k); + } + } + if (b - a > 4) { PairwiseMerge(A, m, b); } +} + +void PairwiseMergeSort(SortArray& A, size_t a, size_t b) +{ + size_t m = (a + b) / 2; + for (size_t i = a, j = m; i < m; ++i, ++j) + { + compSwap(A, i, j); + } + if (b - a > 2) + { + PairwiseMergeSort(A, a, m); + PairwiseMergeSort(A, m, b); + PairwiseMerge(A, a, b); + } +} + +void PairwiseSort(SortArray& A) +{ + size_t end = A.size(); + size_t n = 1; + for (; n < end; n <<= 1) {} + PairwiseMergeSort(A, 0, n); +} + +void PairwiseIterativeSort(SortArray& A) +{ + size_t end = A.size(), n = 1; + for (; n < end; n <<= 1) {} + for (size_t k = n >> 1; k > 0; k >>= 1) + { + for (size_t j = 0; j < end; j += k << 1) + { + for (size_t i = 0; i < k; ++i) + { + compSwap(A, j + i, j + i + k); + } + } + } + for (size_t k = 2; k < n; k <<= 1) + { + for (size_t j = k >> 1; j > 0; j >>= 1) + { + for (size_t i = 0; i < end; i += k << 1) + { + for (size_t m = j; m < ((k - j) << 1); m += j << 1) + { + for (size_t o = 0; o < j; ++o) + { + compSwap(A, i + m + o, i + m + j + o); + } + } + } + } + } +} + +// **************************************************************************** +// *** American Flag Sort +// Adapted from https://en.wikipedia.org/wiki/American_flag_sort +/* + Copyright 2017 Justin Wetherell + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +size_t getDigit(size_t num, size_t divisor, size_t buckets) { return (num / divisor) % buckets; } + +int getMaxNumberOfDigits(SortArray& A, size_t len, int buckets) +{ + int max = std::numeric_limits::min(); + int temp = 0; + for (size_t i = 0; i < len; ++i) + { + int ele = A[i].get(); + temp = static_cast(log(ele) / log(buckets)) + 1; + if (temp > max) { max = temp; } + } + return max; +} + +void sort(SortArray& A, size_t start, size_t len, size_t divisor) +{ + size_t buckets = 128; + std::vector count(buckets, 0); + std::vector offset(buckets, 0); + size_t digit = 0; + + for (size_t i = start; i < len; ++i) + { + int d = A[i].get(); + size_t l = d; + digit = getDigit(l, divisor, buckets); + count[digit] = count[digit] + 1; + } + int s = start; + offset[0] = s; + + for (size_t i = 1; i < buckets; ++i) + { + offset[i] = count[i - 1] + offset[i - 1]; + } + + for (size_t b = 0; b < buckets; ++b) + { + while (count[b] > 0) + { + size_t origin = offset[b], from = origin; + int num = A[from]; + do + { + size_t m = num; + digit = getDigit(m, divisor, buckets); + size_t to = offset[digit]; + + offset[digit] = offset[digit] + 1; + count[digit] = count[digit] - 1; + + int temp = A[to].get(); + A.set(to, ArrayItem(num)); + + num = temp; + from = to; + } + while (from != origin); + } + } + if (divisor > 1) + { + for (size_t i = 0; i < buckets; ++i) + { + size_t begin = 0; + if (i > 0) { begin = offset[i - 1]; } + else { begin = start; } + size_t last = offset[i]; + + if (last - begin > 1) + { + sort(A, begin, last, divisor / buckets); + } + } + } +} + +void AmericanFlagSort(SortArray& A) +{ + size_t len = A.size(); + int buckets = 128, max = 1; + int numberOfDigits = getMaxNumberOfDigits(A, len, buckets); // Max number of digits + + for (int i = 0; i < numberOfDigits - 1; ++i) { max *= buckets; } + + size_t m = max; + sort(A, 0, len, m); +} + + +// **************************************************************************** +// *** Strand Sort + +/* + MIT License + + Copyright (c) 2020-2021 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void mergeTo(SortArray& A, std::vector& subList, size_t a, size_t m, size_t b) +{ + size_t i = 0, s = m - a; + while (i < s && m < b) + { + if (subList[i] < A[m]) + { + A.set(a++, subList[i++]); + } + else + { + A.set(a++, A[m++]); + } + } + while (i < s) + { + A.set(a++, subList[i++]); + } +} + +void StrandSort(SortArray& A) +{ + size_t n = A.size(), j = n, k = j; + std::vector subList(n); + while (j > 0) + { + subList[0] = A[0]; + --k; + for (size_t i = 0, p = 0, m = 1; m < j; ++m) + { + if (A[m] >= subList[i]) + { + subList[++i] = A[m]; + --k; + } + else + { + A.set(p++, A[m]); + } + } + mergeTo(A, subList, k, j, n); + j = k; + } +} + + +// **************************************************************************** +// *** New Shuffle Merge Sort +/* + MIT License + + Copyright (c) 2021 EmeraldBlock + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/* + * Implements https://www.sciencedirect.com/science/article/pii/S1877050910005478. + * + * The shuffle algorithm is at https://arxiv.org/abs/0805.1598. + * Note that the unshuffle algorithm is not the shuffle algorithm in reverse, + * but rather, it is a variation of the shuffle algorithm. + * + * See also a proof of the time complexity at https://arxiv.org/abs/1508.00292. + * The implementation is based on the pseudocode found in this. +*/ + +void rotateEqual(SortArray& A, size_t a, size_t b, size_t size) +{ + for (size_t i = 0; i < size; ++i) + { + A.swap(a + i, b + i); + } +} + +void rotateArray(SortArray& A, size_t mid, size_t a, size_t b) +{ + while (a > 0 && b > 0) + { + if (a > b) + { + rotateEqual(A, mid - b, mid, b); + mid -= b; + a -= b; + } + else + { + rotateEqual(A, mid - a, mid, a); + mid += a; + b -= a; + } + } +} + +void shuffleEasy(SortArray& A, size_t start, size_t size) +{ + for (size_t i = 1; i < size; i *= 3) + { + value_type val = A[start + i - 1]; + for (size_t j = i * 2 % size; j != i; j = j * 2 % size) + { + value_type nval = A[start + j - 1]; + A.set(start + j - 1, val); + val = nval; + } + A.set(start + i - 1, val); + } +} + +void shuffleArray(SortArray& A, size_t start, size_t end) +{ + while (end - start > 1) + { + size_t n = (end - start) / 2, l = 1; + while (l * 3 - 1 <= 2 * n) { l *= 3; } + size_t m = (l - 1) / 2; + rotateArray(A, start + n, n - m, m); + shuffleEasy(A, start, l); + start += l - 1; + } +} + +void rotateShuffledEqual(SortArray& A, size_t a, size_t b, size_t size) +{ + for (size_t i = 0; i < size; i += 2) + { + A.swap(a + i, b + i); + } +} + +void rotateShuffled(SortArray& A, size_t mid, size_t a, size_t b) +{ + while (a > 0 && b > 0) + { + if (a > b) + { + rotateShuffledEqual(A, mid - b, mid, b); + mid -= b; + a -= b; + } + else + { + rotateShuffledEqual(A, mid - a, mid, a); + mid += a; + b -= a; + } + } +} + +void rotateShuffledOuter(SortArray& A, size_t mid, size_t a, size_t b) +{ + if (a > b) + { + rotateShuffledEqual(A, mid - b, mid + 1, b); + mid -= b; + a -= b; + rotateShuffled(A, mid, a, b); + } + else + { + rotateShuffledEqual(A, mid - a, mid + 1, a); + mid += a + 1; + b -= a; + rotateShuffled(A, mid, a, b); + } +} + +void unshuffleEasy(SortArray& A, size_t start, size_t size) +{ + for (size_t i = 1; i < size; i *= 3) + { + size_t prev = i; + value_type val = A[start + i - 1]; + for (size_t j = i * 2 % size; j != i; j = j * 2 % size) { + A.set(start + prev - 1, A[start + j - 1]); + prev = j; + } + A.set(start + prev - 1, val); + } +} + +void unshuffle(SortArray& A, size_t start, size_t end) +{ + while (end - start > 1) + { + size_t n = (end - start) / 2, l = 1; + while (l * 3 - 1 <= 2 * n) { l *= 3; } + size_t m = (l - 1) / 2; + + rotateShuffledOuter(A, start + 2 * m, 2 * m, 2 * n - 2 * m); + unshuffleEasy(A, start, l); + start += l - 1; + } +} + +void mergeUp(SortArray& A, size_t start, size_t end, bool type) +{ + size_t i = start, j = i + 1; + while (j < end) + { + if (A[i] < A[j] || (!type && A[i] == A[j])) + { + ++i; + if (i == j) + { + ++j; + type = !type; + } + } + else if (end - j == 1) + { + rotateArray(A, j, j - i, 1); + break; + } + else + { + size_t r = 0; + if (type) + { + while (j + 2 * r < end && A[j + 2 * r] <= A[i]) { ++r; } + } + else + { + while (j + 2 * r < end && A[j + 2 * r] < A[i]) { ++r; } + } + --j; + unshuffle(A, j, j + 2 * r); + rotateArray(A, j, j - i, r); + i += r + 1; + j += 2 * r + 1; + } + } +} + +void mergeArray(SortArray& A, size_t start, size_t mid, size_t end) +{ + if (mid - start <= end - mid) + { + shuffleArray(A, start, end); + mergeUp(A, start, end, true); + } + else + { + shuffleArray(A, start + 1, end); + mergeUp(A, start, end, false); + } +} + +size_t ceilPowerOfTwo(size_t x) +{ + --x; + for (size_t i = 16; i > 0; i >>= 1) { x |= x >> i; } + return ++x; +} + +void sortLarge(SortArray& A, size_t len) +{ + for (size_t subarrayCount = ceilPowerOfTwo(len), wholeI = len / subarrayCount, fracI = len % subarrayCount; subarrayCount > 1; ) + { + for (size_t whole = 0, frac = 0; whole < len; ) + { + size_t start = whole; + whole += wholeI; + frac += fracI; + if (frac >= subarrayCount) + { + ++whole; + frac -= subarrayCount; + } + size_t mid = whole; + whole += wholeI; + frac += fracI; + if (frac >= subarrayCount) + { + ++whole; + frac -= subarrayCount; + } + mergeArray(A, start, mid, whole); + } + subarrayCount >>= 1; + wholeI <<= 1; + if (fracI >= subarrayCount) + { + ++wholeI; + fracI -= subarrayCount; + } + } +} + +void mergeSortArray(SortArray& A, size_t len) +{ + if (len < 1 << 15) + { + for (size_t subarrayCount = ceilPowerOfTwo(len); subarrayCount > 1; subarrayCount >>= 1) + { + for (size_t i = 0; i < subarrayCount; i += 2) + { + mergeArray(A, len * i / subarrayCount, len * (i + 1) / subarrayCount, len * (i + 2) / subarrayCount); + } + } + } + else + { + sortLarge(A, len); + } +} + +void NewShuffleMergeSort(SortArray& A) +{ + size_t len = A.size(); + mergeSortArray(A, len); +} + +// **************************************************************************** +// *** Andrey Astrelin's In-Place Merge Sort + +void sortVector(SortArray& A, size_t a, size_t b) +{ + while (b > 1) + { + size_t k = 0; + for (size_t i = 1; i < b; ++i) + { + if (A[a + k] > A[a + i]) { k = i; } + } + A.swap(a, a + k); + ++a; --b; + } +} + +void aswap(SortArray& A, size_t arr1, size_t arr2, size_t l) +{ + while (l-- > 0) + { + A.swap(arr1, arr2); + ++arr1; ++arr2; + } +} + +int backMerge(SortArray& A, size_t arr1, size_t l1, size_t arr2, size_t l2) +{ + size_t arr0 = arr2 + l1; + for (;;) + { + if (A[arr1] > A[arr2]) + { + A.swap(arr1, arr0); + --arr1; --arr0; + if (--l1 == 0) { return 0; } + } + else + { + A.swap(arr2, arr0); + --arr2; --arr0; + if (--l2 == 0) { break; } + } + } + size_t res = l1; + do + { + A.swap(arr1, arr0); + --arr1; --arr0; + } + while (--l1 != 0); + return res; +} + +void rMerge(SortArray& A, size_t a, size_t l, size_t r) +{ + for (size_t i = 0; i < l; i += r) + { + size_t q = i; + for (size_t j = i + r; j < l; j += r) + { + if (A[a + q] > A[a + j]) { q = j; } + } + if (q != i) { aswap(A, a + i, a + q, r); } + if (i != 0) + { + aswap(A, a + l, a + i, r); + backMerge(A, a + (l + r - 1), r, a + (i - 1), r); + } + } +} + +size_t rbnd(size_t len) +{ + len = len / 2; + size_t k = 0; + for (size_t i = 1; i < len; i *= 2) { ++k; } + len /= k; + for (k = 1; k <= len; k *= 2) {} + return k; +} + +void msort(SortArray& A, size_t a, size_t len) +{ + if (len < 12) { sortVector(A, a, len); return; } + size_t r = rbnd(len), lr = (len / r - 1) * r; + for (size_t p = 2; p <= lr; p += 2) + { + if (A[a + (p - 2)] > A[a + (p - 1)]) + { A.swap(a + (p - 2), a + (p - 1)); } + if ((p & 2) != 0) { continue; } + aswap(A, a + (p - 2), a + p, 2); + size_t m = len - p, q = 2; + for (;;) + { + size_t q0 = 2 * q; + if (q0 > m || (p & q0) != 0) { break; } + backMerge(A, a + (p - q - 1), q, a + (p + q - 1), q); + q = q0; + } + backMerge(A, a + (p + q - 1), q, a + (p - q - 1), q); + size_t q1 = q; + q *= 2; + while ((q & p) == 0) + { + q *= 2; + rMerge(A, a + (p - q), q, q1); + } + } + + size_t q1 = 0; + for (size_t q = r; q < lr; q *= 2) + { + if ((lr & q) != 0) + { + q1 += q; + if (q1 != q) + { + rMerge(A, a + (lr - q1), q1, r); + } + } + } + + size_t s = len - lr; + msort(A, a + lr, s); + aswap(A, a, a + lr, s); + s += backMerge(A, a + (s - 1), s, a + (lr - 1), lr - s); + msort(A, a, s); +} + +void AndreyMergeSort(SortArray& A) +{ + msort(A, 0, A.size()); +} + + +// **************************************************************************** +// *** Proportion Extend Merge Sort + +/* + MIT License + + Copyright (c) 2023 aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +void blockSwap(SortArray& A, size_t a, size_t b, size_t s) +{ + while (s-- > 0) + { + A.swap(a, b); + ++a; ++b; + } +} + +size_t partition(SortArray& A, size_t a, size_t b, size_t p) +{ + size_t i = a - 1, j = b; + while (true) + { + do { ++i; } while (i < j && A[i] < A[p]); + do { --j; } while (j >= i && A[j] > A[p]); + if (i < j) { A.swap(i, j); } + else { return i; } + } +} + +void mergeFW(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + size_t pLen = m - a, i = 0, j = m, k = a; + blockSwap(A, a, p, pLen); + while (i < pLen && j < b) + { + if (A[p + i] <= A[j]) { A.swap(k, p + i); ++k; ++i; } + else { A.swap(k, j); ++k; ++j; } + } + while (i < pLen) { A.swap(k, p + i); ++k; ++i; } +} + +void mergeBW(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + size_t pLen = b - m; + int i = static_cast(pLen - 1), + j = static_cast(m - 1), + k = static_cast(b - 1), + z = static_cast(a); + blockSwap(A, m, p, pLen); + while (i >= 0 && j >= z) + { + if (A[p + i] >= A[j]) { A.swap(k, p + i); --k; --i; } + else { A.swap(k, j); --k; --j; } + } + while (i >= 0) { A.swap(k, p + i); --k; --i; } +} + +void smartMerge(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + if (m - a < b - m) { mergeFW(A, a, m, b, p); } + else { mergeBW(A, a, m, b, p); } +} + +void mergeTo(SortArray& A, size_t a, size_t m, size_t b, size_t p) +{ + size_t i = a, j = m; + while (i < m && j < b) + { + if (A[i] <= A[j]) { A.swap(p, i); ++p; ++i; } + else { A.swap(p, j); ++p; ++j; } + } + while (i < m) { A.swap(p, i); ++p; ++i; } + while (j < b) { A.swap(p, j); ++p; ++j; } +} + +void pingPongMerge(SortArray& A, size_t a, size_t m1, size_t m, size_t m2, size_t b, size_t p) +{ + size_t p1 = p + m - a, pEnd = p + b - a; + mergeTo(A, a, m1, m, p); + mergeTo(A, m, m2, b, p1); + mergeTo(A, p, p1, pEnd, a); +} + +void mergeSort(SortArray& A, size_t a, size_t b, size_t p) +{ + const size_t min_insert = 8; + size_t n = b - a, j = n; + for (; (j + 3) / 4 >= min_insert; j = (j + 3) / 4) {} + for (size_t i = a; i < b; i += j) + { + BinaryInsertSort(A, i, std::min(b, i + j)); + } + for (size_t i; j < n; j *= 4) + { + for (i = a; i + 2 * j < b; i += 4 * j) + { + pingPongMerge(A, i, i + j, i + 2 * j, std::min(i + 3 * j, b), std::min(i + 4 * j, b), p); + + } + if (i + j < b) { mergeBW(A, i, i + j, b, p); } + } +} + +void smartMergeSort(SortArray& A, size_t a, size_t b, size_t p, size_t pb) +{ + if (b - a <= pb - p) { mergeSort(A, a, b, p); return; } + size_t m = (a + b) >> 1; + mergeSort(A, a, m, p); + mergeSort(A, m, b, p); + mergeFW(A, a, m, b, p); +} + +void peSort(SortArray& A, size_t a, size_t m, size_t b) +{ + size_t n = b - a; + const size_t min_insert = 8; + if (n < 4 * min_insert) { BinaryInsertSort(A, a, b); return; } + if (m - a <= n / 3) + { + size_t t = (n + 2) / 3; + smartMergeSort(A, m, b - t, b - t, b); + smartMerge(A, a, m, b - t, b - t); + m = b - t; + } + size_t m1 = (a + m) >> 1, m2 = partition(A, m, b, m1); + size_t i = m, j = m2; + while (i > m1) { --i; --j; A.swap(i, j); } + m = m2 - (m - m1); + if (m - m1 < b - m2) + { + mergeSort(A, m1, m, m2); + smartMerge(A, a, m1, m, m2); + peSort(A, m + 1, m2, b); + } + else + { + mergeSort(A, m2, b, m1); + smartMerge(A, m + 1, m2, b, m1); + peSort(A, a, m1, m); + } +} + +void ProportionMergeSort(SortArray& A) +{ + peSort(A, 0, 0, A.size()); +} + +// **************************************************************************** +// *** Buffer Partition Merge Sort + +/* + * + MIT License + + Copyright (c) 2021 yuji, implemented by aphitorite + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +* +*/ + +void shiftBW2(SortArray& A, int a, int m, int b) +{ + while (m > a) + { + --b; --m; + A.swap(static_cast(b), static_cast(m)); + } +} + +void inPlaceMerge(SortArray& A, int a, int m, int b) +{ + int i = a, j = m, k = 0; + while (i < j && j < b) + { + if (A[i] > A[j]) + { + k = j; ++k; + while (k < b && A[i] > A[k]) { ++k; } + rotate(A, static_cast(i), static_cast(j), static_cast(k)); + i += k - j; + j = k; + } + else { ++i; } + } +} + +void medianOfThree(SortArray& A, int a, int b) +{ + int m = a + (b - 1 - a) / 2; + if (A[a] > A[m]) { A.swap(static_cast(a), static_cast(m)); } + if (A[m] > A[b - 1]) + { + A.swap(static_cast(m), static_cast(b - 1)); + if (A[a] > A[m]) { return; } + } + A.swap(static_cast(a), static_cast(m)); +} + +void medianofMedians(SortArray& A, int a, int b, int s) +{ + int end = b, start = a, i, j; + bool ad = true; + while (end - start > 1) + { + j = start; + for (i = start; i + 2 * s <= end; i += s) + { + InsertSort(A, static_cast(i), static_cast(i + s)); + A.swap(static_cast(j), static_cast(i + s / 2)); + ++j; + } + if (i < end) + { + InsertSort(A, static_cast(i), static_cast(end)); + int val = 0; + if (ad) { val = 1; } + A.swap(static_cast(j), static_cast(i + (end - val - i) / 2)); + if ((end - i) % 2 == 0) { ad = !ad; } + ++j; + } + end = j; + } +} + +int partition(SortArray& A, int a, int b) +{ + int i = a, j = b; + while (true) + { + do { ++i; } + while (i < j && A[i] > A[a]); + do { --j; } + while (j >= i && A[j] < A[a]); + if (i < j) { A.swap(static_cast(i), static_cast(j)); } + else { return j; } + } +} + +int quickSelect(SortArray& A, int a, int b, int m) +{ + bool badPartition = false, mom = false; + int m1 = (m + b + 1) / 2; + while (true) + { + if (badPartition) + { + medianofMedians(A, a, b, 5); + mom = true; + } + else { medianOfThree(A, a, b); } + int p = partition(A, a, b); + A.swap(static_cast(a), static_cast(p)); + int l = std::max(1, p - a), r = std::max(1, b - (p + 1)); + badPartition = !mom && (l / r >= 16 || r / l >= 16); + if (p >= m && p < m1) { return p; } + else if (p < m) { a = p + 1; } + else { b = p; } + } +} + +void mergeVector(SortArray& A, int a, int m, int b, int p) +{ + int i = a, j = m; + while (i < m && j < b) + { + if (A[i] <= A[j]) + { + A.swap(static_cast(p), static_cast(i)); + ++p; ++i; + } + else + { + A.swap(static_cast(p), static_cast(j)); + ++p; ++j; + } + } + while (i < m) + { + A.swap(static_cast(p), static_cast(i)); + ++p; ++i; + } + while (j < b) + { + A.swap(static_cast(p), static_cast(j)); + ++p; ++j; + } +} + +int mergeFW2(SortArray& A, int p, int a, int m, int b) +{ + int i = a, j = m; + while (i < m && j < b) + { + if (A[i] <= A[j]) + { + A.swap(static_cast(p), static_cast(i)); + ++p; ++i; + } + else + { + A.swap(static_cast(p), static_cast(j)); + ++p; ++j; + } + } + if (i < m) { return i; } + else { return j; } +} + +int getMinLevel(int n) +{ + while (n >= 32) { n = (n + 3) / 4; } + return n; +} + +void mergeSort2(SortArray& A, int a, int b, int p) +{ + int len = b - a; + if (len < 2) { return; } + int i, pos, j = getMinLevel(len); + for (i = a; i + j <= b; i += j) + { + BinaryInsertSort(A, static_cast(i), static_cast(i + j)); + } + BinaryInsertSort(A, static_cast(i), static_cast(b)); + while (j < len) + { + pos = p; + for (i = a; i + 2 * j <= b; i += 2 * j, pos += 2 * j) + { mergeVector(A, i, i + j, i + 2 * j, pos); } + if (i + j < b) { mergeVector(A, i, i + j, b, pos); } + else + { + while (i < b) + { + A.swap(static_cast(i), static_cast(pos)); + ++i; ++pos; + } + } + j *= 2; + pos = a; + for (i = p; i + 2 * j <= p + len; i += 2 * j, pos += 2 * j) + { mergeVector(A, i, i + j, i + 2 * j, pos); } + if (i + j < p + len) { mergeVector(A, i, i + j, p + len, pos); } + else + { + while (i < p + len) + { + A.swap(static_cast(i), static_cast(pos)); + ++i; ++pos; + } + } + j *= 2; + } +} + +void sortArray(SortArray& A, int a, int b) +{ + int minLvl = static_cast(sqrt(b - a)); + int m = (a + b + 1) / 2; + mergeSort2(A, m, b, a); + while (m - a > minLvl) + { + int m1 = (a + m + 1) / 2; + m1 = quickSelect(A, a, m, m1); + mergeSort2(A, m1, m, a); + int bSize = m1 - a; + int m2 = std::min(m1 + bSize, b); + m1 = mergeFW2(A, a, m1, m, m2); + while (m1 < m) + { + shiftBW2(A, m1, m, m2); + m1 = m2 - (m - m1); + a = m1 - bSize; + m = m2; + if (m == b) { break; } + m2 = std::min(m2 + bSize, b); + m1 = mergeFW2(A, a, m1, m, m2); + } + m = m1; + a = m1 - bSize; + } + BinaryInsertSort(A, static_cast(a), static_cast(m)); + inPlaceMerge(A, a, m, b); +} + +void BufferPartitionMergeSort(SortArray& A) +{ + sortArray(A, 0, A.size()); +} \ No newline at end of file From 43588af2b9e5921cd00a313d0d13c0d45657b1f1 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 21:42:21 +0800 Subject: [PATCH 266/289] Delete SortAlgo.cpp Wrong placement --- SortAlgo.cpp | 4478 -------------------------------------------------- 1 file changed, 4478 deletions(-) delete mode 100644 SortAlgo.cpp diff --git a/SortAlgo.cpp b/SortAlgo.cpp deleted file mode 100644 index cb69800fd..000000000 --- a/SortAlgo.cpp +++ /dev/null @@ -1,4478 +0,0 @@ -/****************************************************************************** - * src/SortAlgo.cpp - * - * Implementations is many sorting algorithms. - * - * Note that these implementations may not be as good/fast as possible. Some - * are modified so that the visualization is more instructive. - * - * Futhermore, some algorithms are annotated using the mark() and watch() - * functions from SortArray. These functions add colors to the illustratation - * and thereby makes the algorithm's visualization easier to explain. - * - ****************************************************************************** - * The algorithms in this file are copyrighted by the original authors. All - * code is freely available. - * - * The source code added by myself (Timo Bingmann) and all modifications are - * copyright (C) 2013-2014 Timo Bingmann - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - *****************************************************************************/ - -#include "SortAlgo.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -typedef ArrayItem value_type; - -// inversion count limit for iterator instrumented algorithms -const unsigned int inversion_count_instrumented = 512; - -const struct AlgoEntry g_algolist[] = -{ - { _("Selection Sort"), &SelectionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Double Selection Sort"), &DoubleSelectionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Sandpaper Sort"), &SandpaperSort, UINT_MAX, UINT_MAX, - _("Also known as Exchange Sort.") }, - { _("Double Sandpaper Sort"), &DoubleSandpaperSort, UINT_MAX, UINT_MAX, - _("A variant of Exchange Sort that sorts the array bidirectionally.") }, - { _("Insertion Sort"), &InsertionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Merge Sort"), &MergeSort, UINT_MAX, 512, - _("Merge sort which merges two sorted sequences into a shadow array, and then copies it back to the shown array.") }, - { _("Merge Sort (iterative)"), &MergeSortIterative, UINT_MAX, 512, - _("Merge sort variant which iteratively merges " - "subarrays of sizes of powers of two.") }, - { _("Pairwise Merge Sort (Recursive)"), &PairwiseSort, UINT_MAX, 512, - wxEmptyString }, - { _("Pairwise Merge Sort (Iterative)"), &PairwiseIterativeSort, UINT_MAX, 512, - wxEmptyString }, - { _("Weave Merge Sort"), &WeaveMergeSort, UINT_MAX, 512, - _("An in-place merge sort variant that interleaves 2 halves of the input array, and then uses Insertion Sort to sort the array.")}, - { _("New Shuffle Merge Sort"), &NewShuffleMergeSort, UINT_MAX, 512, - _("An improvement upon Weave Merge Sort, with faster weave time, and inserting now makes comparisons with a worst-case similar to Merge Sort.") }, - { _("Andrey's In-Place Merge Sort"), &AndreyMergeSort, UINT_MAX, 512, - wxEmptyString }, - { _("Proportion Extend Merge Sort"), &ProportionMergeSort, UINT_MAX, 512, - wxEmptyString }, - { _("Buffer Partition Merge Sort"), &BufferPartitionMergeSort, UINT_MAX, 512, - wxEmptyString }, - { _("Strand Sort"), &StrandSort, UINT_MAX, 512, - wxEmptyString }, - { _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX, UINT_MAX, - _("Quick sort variant with left and right pointers.") }, - { _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX, UINT_MAX, - _("Quick sort variant from 3rd edition of CLRS: two pointers on left.") }, - { _("Quick Sort (ternary, LR ptrs)"), &QuickSortTernaryLR, UINT_MAX, UINT_MAX, - _("Ternary-split quick sort variant, adapted from multikey quicksort by " - "Bentley & Sedgewick: partitions \"==\" using two pairs of pointers " - "at left and right, then copied to middle.") }, - { _("Quick Sort (ternary, LL ptrs)"), &QuickSortTernaryLL, UINT_MAX, UINT_MAX, - _("Ternary-split quick sort variant: partitions \"<>?=\" using two " - "pointers at left and one at right. Afterwards copies the \"=\" to middle.") }, - { _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX, UINT_MAX, - _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " - "two at left and one at right.") }, - { _("PDQ Sort"), &PDQSort, UINT_MAX, inversion_count_instrumented, - _("Pattern-defeating Quick Sort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" - " with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, - { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, - _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, - { _("Flan Sort (Quick Library Sort)"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, - _("An in-place Library Sort variant that uses Quick Sort partitioning to make space.") }, - { _("Bubble Sort"), &BubbleSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Optimized Bubble Sort"), &OptimizedBubbleSort, UINT_MAX, UINT_MAX, - _("This variant terminates early if the array is already sorted.") }, - { _("Targeted Bubble Sort"), &TargetedBubbleSort, UINT_MAX, 1024, - _("This variant of Bubble Sort is capable of adjusting the sorting boundaries based on the input array.") }, - { _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Dual Cocktail Shaker Sort"), &DualCocktailShakerSort, UINT_MAX, UINT_MAX, - _("This variant sorts from both directions of the array simultaneously.") }, - { _("Circle Sort"), &CircleSort, UINT_MAX, UINT_MAX, - _("Circle Sort is a recursive sorting algorithm that works by comparing and swapping elements in a circular manner.") }, - { _("Iterative Circle Sort"), &CircleSort2, UINT_MAX, UINT_MAX, - _("A variant of Circle Sort that has less recursion overhead.") }, - { _("Introspective Circle Sort"), &IntroCircleSort, UINT_MAX, UINT_MAX, - _("A variant of Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, - { _("Introspective Iterative Circle Sort"), &IntroIteCircleSort, UINT_MAX, UINT_MAX, - _("A variant of Iterative Circle Sort that switches to Insertion Sort when a certain threshold has been reached.") }, - { _("Gnome Sort"), &GnomeSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Optimized Gnome Sort"), &OptimizedGnomeSort, UINT_MAX, UINT_MAX, - _("This variant avoids scanning through sorted portions of the array after a number has been placed in its correct spot") }, - { _("Comb Sort"), &CombSort, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Shell Sort"), &ShellSort, UINT_MAX, 1024, - wxEmptyString }, - { _("Heap Sort"), &HeapSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("Smooth Sort"), &SmoothSort, UINT_MAX, 1024, - wxEmptyString }, - { _("Odd-Even Sort"), &OddEvenSort, UINT_MAX, 1024, - wxEmptyString }, - // older sequential implementation, which really makes little sense to do - //{ _("Bitonic Sort"), &BitonicSort, UINT_MAX, UINT_MAX, wxEmptyString }, - { _("Batcher's Bitonic Sort"), &BitonicSortNetwork, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Batcher's Odd-Even Merge Sort"), &BatcherSortNetwork, UINT_MAX, UINT_MAX, - wxEmptyString }, - { _("Cycle Sort"), &CycleSort, 512, UINT_MAX, - wxEmptyString }, - { _("Radix Sort (LSD)"), &RadixSortLSD, UINT_MAX, 512, - _("Least significant digit radix sort, which copies item into a shadow " - "array during counting.") }, - { _("In-Place Radix Sort (LSD)"), &InPlaceRadixSortLSD, UINT_MAX, UINT_MAX, - _("Least significant digit radix sort, performed in O(1) space.") }, - { _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX, 512, - _("Most significant digit radix sort, which permutes items in-place by walking cycles.") }, - { _("Rotate Radix Sort (MSD)"), &RotateRadixSortMSD, UINT_MAX, 512, - wxEmptyString }, - { _("Rotate Radix Sort (LSD)"), &RotateRadixSortLSD, UINT_MAX, 512, - wxEmptyString }, - { _("American Flag Sort"), &AmericanFlagSort, UINT_MAX, inversion_count_instrumented, - _("American Flag Sort is an efficient, in-place variant of radix sort that distributes items into hundreds of buckets.") }, - { _("std::sort (gcc)"), &StlSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("std::stable_sort (gcc)"), &StlStableSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("std::sort_heap (gcc)"), &StlHeapSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("Tim Sort"), &TimSort, UINT_MAX, inversion_count_instrumented, - wxEmptyString }, - { _("Block Merge Sort (WikiSort)"), &WikiSort, UINT_MAX, inversion_count_instrumented, - _("An O(1) place O(n log n) time stable merge sort.") }, - { _("Grail Sort (O(1) buffer)"), &GrailSort, UINT_MAX, inversion_count_instrumented, - _("Grail Sort is a stable, in-place sorting algorithm that efficiently organizes an array by using a block-based merging technique.") }, - { _("Grail Sort (external buffer)"), &AuxGrailSort, UINT_MAX, inversion_count_instrumented, - _("A variant of Grail Sort that uses an external buffer for a potential speedup.") }, - { _("Bead Sort"), &BeadSort, UINT_MAX, UINT_MAX, - _("This is a non-comparison based sorting algorithm that uses the concept of stacked beads to sort the elements.") }, - { _("Gravity Sort"), &GravitySort, UINT_MAX, UINT_MAX, - _("A non-comparison based sorting algorithm that uses the concept of gravitational fall to sort the elements.") }, - { _("Pancake Sort"), &PancakeSort, UINT_MAX, UINT_MAX, - _("Sorts the array by performing a series of 'flips' to push the maximum element to the correct spot.") }, - { _("Optimized Pancake Sort"), &OptimizedPancakeSort, UINT_MAX, UINT_MAX, - _("An optimized variant of Pancake Sort that performs 1/2 as many flips.") }, - { _("Adjacency Pancake Sort"), &AdjacencyPancakeSort, UINT_MAX, UINT_MAX, - _("An improvement upon Pancake Sort, which performs only 5/3 N + O(1) flips.") }, - { _("Bogo Sort"), &BogoSort, 10, UINT_MAX, - wxEmptyString }, - { _("Bozo Sort"), &BozoSort, 10, UINT_MAX, - wxEmptyString }, - { _("Stooge Sort"), &StoogeSort, 256, inversion_count_instrumented, - wxEmptyString }, - { _("Slow Sort"), &SlowSort, 128, inversion_count_instrumented, - wxEmptyString }, - { _("Bad Sort"), &BadSort, 128, inversion_count_instrumented, - _("A humorous sorting algorithm with a time complexity of O(n^3).") } -}; - -const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]); - -const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size; - -std::random_device rd1; -std::mt19937 gen1(rd1()); - -// **************************************************************************** -// *** Selection Sort - -void DoubleSelectionSort(SortArray& A) -{ - size_t left = 0; - size_t right = A.size() - 1, n = right; - ssize_t max_idx = 0; - ssize_t low_idx = 0; - std::atomic max_i, low_i; - max_i.store(max_idx); - low_i.store(low_idx); - A.watch(&max_i, 4); - A.watch(&low_i, 5); - while (left < right) - { - max_idx = right; - low_idx = left; - for (size_t i = left; i <= right; ++i) - { - if (A[i] < A[low_idx]) - { - A.mark_swap(i, low_idx); - low_idx = i; - low_i.store(i); - } - else if (A[i] > A[max_idx]) - { - A.mark_swap(i, max_idx); - max_idx = i; - max_i.store(i); - } - } - A.swap(left, low_idx); - ssize_t l = left; // This removes comparison warning - if (max_idx == l) { max_idx = low_idx; } - A.swap(right, max_idx); - if (left > 0) { A.unmark(left - 1); } - if (right < n) { A.unmark(right + 1); } - A.mark(left); - A.mark(right); - ++left; --right; - } - A.unwatch_all(); -} - -void SelectionSort(SortArray& A) -{ - ssize_t jMin = 0; - std::atomic kMin; - kMin.store(jMin); - A.watch(&kMin, 3); - - for (size_t i = 0; i < A.size()-1; ++i) - { - jMin = i; - kMin.store(jMin); - - for (size_t j = i+1; j < A.size(); ++j) - { - if (A[j] < A[jMin]) { - A.mark_swap(j, jMin); - jMin = j; - kMin.store(jMin); - } - } - - A.swap(i, jMin); - - // mark the last good element - if (i > 0) A.unmark(i-1); - A.mark(i); - } - A.unwatch_all(); -} - -// **************************************************************************** -// *** Sandpaper and Double Sandpaper Sort -// Double Sandpaper Sort by Taihennami - -void DoubleSandpaperSort(SortArray& A) -{ - for (size_t left = 0, right = A.size() - 1; left < right; ++left, --right) - { - if (A[left] > A[right]) - { - A.swap(left, right); - } - for (size_t i = left + 1; i < right; ++i) - { - if (A[left] > A[i]) - { - A.swap(i, left); - } - else if (A[i] > A[right]) - { - A.swap(i, right); - } - } - } -} - -void SandpaperSort(SortArray& A) -{ - size_t n = A.size(); - for (size_t i = 0; i < n; ++i) - { - for (size_t j = i + 1; j < n; ++j) - { - if (A[i] > A[j]) - { - A.swap(i, j); - } - } - } -} - -// **************************************************************************** -// *** Insertion Sort - -void InsertSort(SortArray& A, size_t start, size_t end) -{ - int begin = static_cast(start); - for (size_t i = start; i < end; ++i) - { - A.mark(i); - int j = i - 1; - value_type key = A[i]; - while (j >= begin && A[j] > key) - { - A.set(j + 1, A[j]); - --j; - } - int index = j + 1; - A.set(index, key); - - A.unmark(i); - } -} - -// with extra item on stack -void InsertionSort(SortArray& A) -{ - InsertSort(A, 0, A.size()); -} - -// swaps every time (keeps all values visible) -void InsertionSort2(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ++i) - { - value_type key = A[i]; - A.mark(i); - - ssize_t j = i - 1; - while (j >= 0 && A[j] > key) - { - A.swap(j, j + 1); - j--; - } - - A.unmark(i); - } -} - -// swaps every time (keeps all values visible) -void BinaryInsertionSort2(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ++i) - { - value_type key = A[i]; - A.mark(i); - - int lo = 0, hi = i; - while (lo < hi) { - int mid = (lo + hi) / 2; - if (key < A[mid]) - hi = mid; - else - lo = mid + 1; - } - - // item has to go into position lo - - ssize_t j = i - 1; - while (j >= lo) - { - A.swap(j, j + 1); - j--; - } - - A.unmark(i); - } -} - -void BinaryInsertSort(SortArray& A, size_t start, size_t end) -{ - for (size_t i = start; i < end; ++i) - { - value_type key = A[i]; - A.mark(i); - - size_t lo = start, hi = i; - while (lo < hi) { - size_t mid = (lo + hi) / 2; - if (key < A[mid]) - hi = mid; - else - lo = mid + 1; - } - - size_t j = i; - while (j > lo) - { - A.set(j, A[j - 1]); - j--; - } - A.set(lo, key); - A.unmark(i); - } -} - -void BinaryInsertionSort(SortArray& A) -{ - BinaryInsertSort(A, 0, A.size()); -} - -// **************************************************************************** -// *** Merge Sort (out-of-place with sentinels) - -// by myself (Timo Bingmann) - -void Merge(SortArray& A, size_t lo, size_t mid, size_t hi) -{ - // mark merge boundaries - A.mark(lo); - A.mark(mid,3); - A.mark(hi-1); - - // allocate output - std::vector out(hi-lo); - - // merge - size_t i = lo, j = mid, o = 0; // first and second halves - while (i < mid && j < hi) - { - // copy out for fewer time steps - value_type ai = A[i], aj = A[j]; - - out[o++] = (ai < aj ? (++i, ai) : (++j, aj)); - } - - // copy rest - while (i < mid) out[o++] = A[i++]; - while (j < hi) out[o++] = A[j++]; - - ASSERT(o == hi-lo); - - A.unmark(mid); - - // copy back - for (i = 0; i < hi-lo; ++i) - A.set(lo + i, out[i]); - - A.unmark(lo); - A.unmark(hi-1); -} - -void MergeSort(SortArray& A, size_t lo, size_t hi) -{ - if (lo + 1 < hi) - { - size_t mid = (lo + hi) / 2; - - MergeSort(A, lo, mid); - MergeSort(A, mid, hi); - - Merge(A, lo, mid, hi); - } -} - -void MergeSort(SortArray& A) -{ - return MergeSort(A, 0, A.size()); -} - -void MergeSortIterative(SortArray& A) -{ - for (size_t s = 1; s < A.size(); s *= 2) - { - for (size_t i = 0; i + s < A.size(); i += 2 * s) - { - Merge(A, i, i + s, - std::min(i + 2 * s, A.size())); - } - } -} - -/* - MIT License - - Copyright (c) 2020 aphitorite/2021 EmeraldBlock - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -void weaveMerge2(SortArray& A, std::vector& tmp, size_t len, size_t residue, size_t modulus) -{ - if (residue + modulus >= len) { return; } - - size_t low = residue, high = residue + modulus, dmodulus = modulus << 1; - - weaveMerge2(A, tmp, len, low, dmodulus); - weaveMerge2(A, tmp, len, high, dmodulus); - - size_t next = residue; - for (; low < len && high < len; next += modulus) - { - int cmp = 0; - if (A[low] > A[high]) { cmp = 1; } - else if (A[low] < A[high]) { cmp = -1; } - - if (cmp == 1 || (cmp == 0 && low > high)) - { - tmp[next] = A[high]; - high += dmodulus; - } - else - { - tmp[next] = A[low]; - low += dmodulus; - } - } - - if (low >= len) - { - while (high < len) - { - tmp[next] = A[high]; - next += modulus; - high += dmodulus; - - } - } - else - { - while (low < len) - { - tmp[next] = A[low]; - next += modulus; - low += dmodulus; - } - } - - for (size_t i = residue; i < len; i += modulus) - { - A.set(i, tmp[i]); - A[i].get(); - } -} - -void WeaveMergeSort2(SortArray& A) -{ - size_t len = A.size(); - std::vector tmp(len); - weaveMerge2(A, tmp, len, 0, 1); -} - -void insertTo(SortArray& A, size_t a, size_t b) -{ - value_type temp = A[a]; - while (a > b) { A.set(a, A[a - 1]); --a; } - A.set(b, temp); -} - -void shiftValue(SortArray& A, size_t a, size_t b, size_t len) -{ - for (size_t i = 0; i < len; ++i) - { - A[a + i].get(); - A.swap(a + i, b + i); - } -} - -void rotate(SortArray& A, int a, int m, int b) -{ - int l = m - a, r = b - m; - while (l > 0 && r > 0) - { - if (r < l) - { - shiftValue(A, static_cast(m - r), static_cast(m), static_cast(r)); - b -= r; - m -= r; - l -= r; - } - - else - { - shiftValue(A, static_cast(a), static_cast(m), static_cast(l)); - a += l; - m += l; - r -= l; - } - } -} - -void bitReversal(SortArray& A, size_t a, size_t b) -{ - size_t len = b - a, m = 0; - size_t d1 = len >> 1, d2 = d1 + (d1 >> 1); - for (size_t i = 1; i < len - 1; ++i) - { - size_t j = d1; - for (size_t k = i, n = d2; (k & 1) == 0; j -= n, k >>= 1, n >>= 1) {} - m += j; - if (m > i) - { - A.swap(a + i, a + m); - } - } -} - -void weaveInsert(SortArray& A, size_t a, size_t b, bool right) -{ - size_t i = a, j = i + 1; - while (j < b) - { - while (i < j && ((right == true && A[i] <= A[j]) || (right == false && A[i] < A[j]))) { ++i; } - if (i == j) - { - right = !right; - ++j; - } - else - { - insertTo(A, j, i++); - j += 2; - } - } -} - -void weaveMerge(SortArray& A, size_t a, size_t m, size_t b) -{ - if (b - a < 2) { return; } - size_t a1 = a, b1 = b; - bool right = true; - if ((b - a) % 2 == 1) - { - if (m - a < b - m) - { - --a1; - right = false; - } - else { ++b1; } - } - - for (size_t e = b1, f; e - a1 > 2; e = f) - { - m = (a1 + e) / 2; - size_t p = 1 << static_cast(log(m - a1) / log(2)); - rotate(A, static_cast(m - p), static_cast(m), static_cast(e - p)); - - m = e - p; - f = m - p; - - bitReversal(A, f, m); - bitReversal(A, m, e); - bitReversal(A, f, e); - } - weaveInsert(A, a, b, right); -} - -void WeaveMergeSort(SortArray& A) -{ - size_t n = A.size(), d = 1 << static_cast(log(n - 1) / log(2) + 1); - while (d > 1) - { - size_t i = 0, dec = 0; - while (i < n) - { - size_t j = i; - dec += n; - while (dec >= d) - { - dec -= d; - ++j; - } - size_t k = j; - dec += n; - while (dec >= d) - { - dec -= d; - ++k; - } - weaveMerge(A, i, j, k); - i = k; - } - d /= 2; - } -} -// **************************************************************************** -// *** Quick Sort Pivot Selection - -QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST; - -static ssize_t SingleMedianOfThree(SortArray& A, ssize_t lo, ssize_t mid, ssize_t hi) -{ - // cases if two are equal - if (A[lo] == A[mid]) return lo; - if (A[lo] == A[hi - 1] || A[mid] == A[hi - 1]) return hi - 1; - - // cases if three are different - return A[lo] < A[mid] - ? (A[mid] < A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? hi - 1 : lo)) - : (A[mid] > A[hi - 1] ? mid : (A[lo] < A[hi - 1] ? lo : hi - 1)); -} - -template -static void PivotInsertionSort(SortArray& A, std::array& arr) -{ - for (size_t i = 1; i < N; ++i) - { - ssize_t key = arr[i]; - size_t j = i; - while (j > 0 && A[arr[j - 1]] > A[key]) - { - arr[j] = arr[j - 1]; - --j; - } - arr[j] = key; - } -} - -static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) -{ - if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment = (hi - lo) / 5; - std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; - PivotInsertionSort(A, nums); - return nums[2]; -} - -static ssize_t NintherPivot(SortArray& A, ssize_t lo, ssize_t hi) -{ - if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment_size = (hi - lo) / 9; - ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); - ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); - ssize_t g3 = SingleMedianOfThree(A, lo + 6 * segment_size, lo + 7 * segment_size, (lo + 8 * segment_size) + 1); - return SingleMedianOfThree(A, g1, g2, g3 + 1); -} - -// some quicksort variants use hi inclusive and some exclusive, we require it -// to be _exclusive_. hi == array.end()! -ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) -{ - switch (g_quicksort_pivot) - { - case PIVOT_FIRST: - { - return lo; - } - case PIVOT_LAST: - { - return hi - 1; - } - case PIVOT_MID: - { - return (lo + hi) / 2; - } - case PIVOT_RANDOM: - { - return lo + (rand() % (hi - lo)); - } - case PIVOT_MEDIAN3: - { - ssize_t mid = (lo + hi) / 2; - return SingleMedianOfThree(A, lo, mid, hi); - } - case PIVOT_MEDIAN3RANDOM: - { - if (lo > hi) - { - ssize_t temp = lo; - lo = hi; - hi = temp; - } - std::uniform_int_distribution dist(lo, hi - 1); - return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); - } - case PIVOT_MEDIAN5: - { - return MedianOfFive(A, lo, hi); - } - case PIVOT_MEDIAN5RANDOM: - { - if (lo > hi) - { - ssize_t temp = lo; - lo = hi; - hi = temp; - } - std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 5) - { - return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); - } - std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; - PivotInsertionSort(A, samples); - return samples[2]; - } - case PIVOT_MEDIAN7: - { - if (hi - lo < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment = (hi - lo) / 7; - std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; - PivotInsertionSort(A, samples); - return samples[3]; - } - case PIVOT_MEDIAN7RANDOM: - { - if (lo > hi) - { - ssize_t temp = lo; - lo = hi; - hi = temp; - } - std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 7) - { - return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); - } - std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; - PivotInsertionSort(A, samples); - return samples[3]; - } - case PIVOT_NINTHER: - { - return NintherPivot(A, lo, hi); - } - case PIVOT_RANDOMNINTHER: - { - if (lo > hi) - { - ssize_t temp = lo; - lo = hi; - hi = temp; - } - std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 9) - { - return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); - } - ssize_t lo1 = dist(gen1), lo2 = dist(gen1), lo3 = dist(gen1), lo4 = dist(gen1), lo5 = dist(gen1); - ssize_t lo6 = dist(gen1), lo7 = dist(gen1), lo8 = dist(gen1), lo9 = dist(gen1); - ssize_t g1 = SingleMedianOfThree(A, lo1, lo2, lo3 + 1); - ssize_t g2 = SingleMedianOfThree(A, lo4, lo5, lo6 + 1); - ssize_t g3 = SingleMedianOfThree(A, lo7, lo8, lo9 + 1); - return SingleMedianOfThree(A, g1, g2, g3 + 1); - } - case PIVOT_MEDIAN9: - { - if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment = (hi - lo) / 9; - std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8 }; - PivotInsertionSort(A, samples); - return samples[4]; - } - case PIVOT_MEDIAN9RANDOM: - { - if (lo > hi) - { - ssize_t temp = lo; - lo = hi; - hi = temp; - } - std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 9) - { - return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); - } - std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; - PivotInsertionSort(A, samples); - return samples[4]; - } - case PIVOT_MEDIAN15: - { - if (hi - lo < 15) { return MedianOfFive(A, lo, hi); } - ssize_t segment = (hi - lo) / 3; - ssize_t g1 = MedianOfFive(A, lo, lo + segment); - ssize_t g2 = MedianOfFive(A, lo + segment, lo + segment * 2); - ssize_t g3 = MedianOfFive(A, lo + segment * 2, hi); - return SingleMedianOfThree(A, g1, g2, g3 + 1); - } - case PIVOT_THREENINTHER: - { - if (hi - lo < 27) { return NintherPivot(A, lo, hi); } - ssize_t segment = (hi - lo) / 3; - ssize_t g1 = NintherPivot(A, lo, lo + segment); - ssize_t g2 = NintherPivot(A, lo + segment, lo + segment * 2); - ssize_t g3 = NintherPivot(A, lo + segment * 2, hi); - return SingleMedianOfThree(A, g1, g2, g3 + 1); - } - default: - { - return lo; - } - } -} - -wxArrayString QuickSortPivotText() -{ - wxArrayString sl; - - sl.Add(_("First Item")); - sl.Add(_("Last Item")); - sl.Add(_("Middle Item")); - sl.Add(_("Random Item")); - sl.Add(_("Median of Three")); - sl.Add(_("Random Median of Three")); - sl.Add(_("Median of Five")); - sl.Add(_("Random Median of Five")); - sl.Add(_("Median of Seven")); - sl.Add(_("Random Median of Seven")); - sl.Add(_("Ninther")); - sl.Add(_("Random Ninther")); - sl.Add(_("Median of Nine")); - sl.Add(_("Random Median of Nine")); - sl.Add(_("Median of Fifteen")); - sl.Add(_("Median of Three Ninther")); - return sl; -} - -// **************************************************************************** -// *** Quick Sort LR (in-place, pointers at left and right, pivot is middle element) - -// by myself (Timo Bingmann), based on Hoare's original code - -void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) -{ - // pick pivot and watch - ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); - std::atomic p1, i1, j1; - - value_type pivot = A[p]; - p1.store(p); - A.watch(&p1, 2); - - ssize_t i = lo, j = hi; - i1.store(i); - j1.store(j); - A.watch(&i1, 3); - A.watch(&j1, 3); - - while (i <= j) - { - while (A[i] < pivot) - { - i++; - i1.store(i); - } - - - while (A[j] > pivot) - { - j--; - j1.store(j); - } - - if (i <= j) - { - A.swap(i, j); - - // follow pivot if it is swapped - if (p == i) p = j; - else if (p == j) p = i; - p1.store(p); - - i++, j--; - i1.store(i); - j1.store(j); - } - } - - A.unwatch_all(); - - if (lo < j) - QuickSortLR(A, lo, j); - - if (i < hi) - QuickSortLR(A, i, hi); -} - -void QuickSortLR(SortArray& A) -{ - return QuickSortLR(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) - -// by myself (Timo Bingmann), based on CLRS' 3rd edition - -size_t PartitionLL(SortArray& A, size_t lo, size_t hi) -{ - // pick pivot and move to back - size_t p = QuickSortSelectPivot(A, lo, hi); - - value_type pivot = A[p]; - A.swap(p, hi - 1); - A.mark(hi - 1); - - ssize_t i = lo; - std::atomic i1; - i1.store(i); - A.watch(&i1, 3); - - for (size_t j = lo; j < hi - 1; ++j) - { - if (A[j] <= pivot) { - A.swap(i, j); - ++i; - i1.store(i); - } - } - - A.swap(i, hi - 1); - A.unmark(hi - 1); - A.unwatch_all(); - - return i; -} - -void QuickSortLL(SortArray& A, size_t lo, size_t hi) -{ - if (lo + 1 < hi) - { - size_t mid = PartitionLL(A, lo, hi); - - QuickSortLL(A, lo, mid); - QuickSortLL(A, mid+1, hi); - } -} - -void QuickSortLL(SortArray& A) -{ - return QuickSortLL(A, 0, A.size()); -} - -// **************************************************************************** -// *** Quick Sort Ternary (in-place, two pointers at left, pivot is first element and moved to right) - -// by myself (Timo Bingmann), loosely based on multikey quicksort by B&S - -void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) -{ - if (hi <= lo) return; - - int cmp; - - // pick pivot and swap to back - ssize_t piv = QuickSortSelectPivot(A, lo, hi + 1); - A.swap(piv, hi); - A.mark(hi); - - const value_type& pivot = A[hi]; - - // schema: |p === |i <<< | ??? |j >>> |q === |piv - ssize_t i = lo, j = hi - 1; - ssize_t p = lo, q = hi - 1; - std::atomic i1, j1; - i1.store(i); - j1.store(j); - A.watch(&i1, 3); - A.watch(&j1, 3); - - for (;;) - { - // partition on left - while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) - { - if (cmp == 0) { - A.mark(p, 4); - A.swap(i, p++); - } - ++i; - i1.store(i); - } - - // partition on right - while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) - { - if (cmp == 0) { - A.mark(q, 4); - A.swap(j, q--); - } - --j; - j1.store(j); - } - - if (i > j) break; - - // swap item between < > regions - A.swap(i++, j--); - i1.store(i); - j1.store(j); - } - - // swap pivot to right place - A.swap(i, hi); - A.mark_swap(i, hi); - - ssize_t num_less = i - p; - ssize_t num_greater = q - j; - - // swap equal ranges into center, but avoid swapping equal elements - j = i - 1; i = i + 1; - i1.store(i); - j1.store(j); - - ssize_t pe = lo + std::min(p - lo, num_less); - for (ssize_t k = lo; k < pe; k++, j--) { - j1.store(j); - A.swap(k, j); - A.mark_swap(k, j); - } - - ssize_t qe = hi - 1 - std::min(hi - 1 - q, num_greater - 1); // one already greater at end - for (ssize_t k = hi - 1; k > qe; k--, i++) { - i1.store(i); - A.swap(i, k); - A.mark_swap(i, k); - } - - A.unwatch_all(); - A.unmark_all(); - - QuickSortTernaryLR(A, lo, lo + num_less - 1); - QuickSortTernaryLR(A, hi - num_greater + 1, hi); -} - -void QuickSortTernaryLR(SortArray& A) -{ - return QuickSortTernaryLR(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Quick Sort LL (in-place, two pointers at left, pivot is first element and moved to right) - -// by myself (Timo Bingmann) - -std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) -{ - // pick pivot and swap to back - ssize_t p = QuickSortSelectPivot(A, lo, hi); - - value_type pivot = A[p]; - A.swap(p, hi - 1); - A.mark(hi - 1); - - ssize_t i = lo, k = hi - 1; - std::atomic i1; - i1.store(i); - A.watch(&i1, 3); - - for (ssize_t j = lo; j < k; ++j) - { - int cmp = A[j].cmp(pivot); // ternary comparison - if (cmp == 0) { - A.swap(--k, j); - --j; // reclassify A[j] - A.mark(k, 4); - } - else if (cmp < 0) { - A.swap(i++, j); - i1.store(i); - } - } - - // unwatch i, because the pivot is swapped there - // in the first step of the following swap loop. - A.unwatch_all(); - - ssize_t j = i + (hi - k); - - for (ssize_t s = 0; s < hi - k; ++s) { - A.swap(i + s, hi - 1 - s); - A.mark_swap(i + s, hi - 1 - s); - } - A.unmark_all(); - - return std::make_pair((ssize_t)i, j); -} - -void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) -{ - if (lo + 1 < hi) - { - std::pair mid = PartitionTernaryLL(A, lo, hi); - - QuickSortTernaryLL(A, lo, mid.first); - QuickSortTernaryLL(A, mid.second, hi); - } -} - -void QuickSortTernaryLL(SortArray& A) -{ - return QuickSortTernaryLL(A, 0, A.size()); -} - -// **************************************************************************** -// *** Dual-Pivot Quick Sort - -// by Sebastian Wild - -void dualPivotYaroslavskiy(class SortArray& a, int left, int right) -{ - if (right > left) - { - if (a[left] > a[right]) { - a.swap(left, right); - } - - const value_type p = a[left]; - const value_type q = a[right]; - - a.mark(left); - a.mark(right); - - ssize_t l = left + 1; - ssize_t g = right - 1; - ssize_t k = l; - std::atomic l1, g1, k1; - l1.store(l); - g1.store(g); - k1.store(k); - - a.watch(&l1, 3); - a.watch(&g1, 3); - a.watch(&k1, 3); - - while (k <= g) - { - if (a[k] < p) { - a.swap(k, l); - ++l; - l1.store(l); - } - else if (a[k] >= q) { - while (a[g] > q && k < g) - { - --g; - g1.store(g); - } - a.swap(k, g); - --g; - g1.store(g); - if (a[k] < p) { - a.swap(k, l); - ++l; - l1.store(l); - } - } - ++k; - k1.store(k); - } - --l; - ++g; - l1.store(l); - g1.store(g); - a.swap(left, l); - a.swap(right, g); - - a.unmark_all(); - a.unwatch_all(); - - dualPivotYaroslavskiy(a, left, l - 1); - dualPivotYaroslavskiy(a, l + 1, g - 1); - dualPivotYaroslavskiy(a, g + 1, right); - } -} - -void QuickSortDualPivot(class SortArray& a) -{ - return dualPivotYaroslavskiy(a, 0, a.size()-1); -} - -// **************************************************************************** -// *** Bubble Sort - -void BubbleSort(SortArray& A) -{ - for (size_t i = 0; i < A.size()-1; ++i) - { - for (size_t j = 0; j < A.size()-1 - i; ++j) - { - if (A[j] > A[j + 1]) - { - A.swap(j, j+1); - } - } - } -} - -void OptimizedBubbleSort(SortArray& A) -{ - for (size_t i = 0; i < A.size() - 1; ++i) - { - bool sorted = true; - for (size_t j = 0; j < A.size() - 1 - i; ++j) - { - if (A[j] > A[j + 1]) - { - A.swap(j, j + 1); - sorted = false; - } - } - if (sorted == true) { break; } - } -} - -void TargetedBubbleSort(SortArray& A) -{ - bool sorted = false; - size_t target = A.size() - 1, lastSwapped = 0; - while (!sorted) - { - sorted = true; - for (size_t i = 0; i < target; ++i) - { - if (A[i] > A[i + 1]) - { - A.swap(i, i + 1); - lastSwapped = i; - sorted = false; - } - } - target = lastSwapped; - } -} - -// **************************************************************************** -// *** Cocktail Shaker Sort - -// from http://de.wikibooks.org/wiki/Algorithmen_und_Datenstrukturen_in_C/_Shakersort - -void CocktailShakerSort(SortArray& A) -{ - size_t lo = 0, hi = A.size()-1, mov = lo; - - while (lo < hi) - { - for (size_t i = hi; i > lo; --i) - { - if (A[i-1] > A[i]) - { - A.swap(i-1, i); - mov = i; - } - } - - lo = mov; - - for (size_t i = lo; i < hi; ++i) - { - if (A[i] > A[i+1]) - { - A.swap(i, i+1); - mov = i; - } - } - - hi = mov; - } -} - -void DualCocktailShakerSort(SortArray& A) -{ - size_t lo = 0, hi = A.size() - 1; - while (lo < hi) - { - size_t lo_mov = 0, hi_mov = 0; - for (size_t i = lo + 1, j = hi - 1; i <= hi; ++i, --j) - { - if (A[i - 1] > A[i]) - { - A.swap(i - 1, i); - lo_mov = i; - } - if (A[j + 1] < A[j]) - { - A.swap(j + 1, j); - hi_mov = j; - } - } - lo = hi_mov; - hi = lo_mov; - } -} - -// **************************************************************************** -// *** Circle Sort - -bool CircleSortRec(SortArray& A, size_t low, size_t high, size_t len) -{ - bool swapped = false; - if (low == high) { return false; } - size_t lo = low, hi = high; - while (lo < hi) - { - if (hi < len && A[lo] > A[hi]) - { - A.swap(lo, hi); - swapped = true; - } - ++lo; --hi; - } - size_t mid = (high - low) / 2; - bool firstHalf = CircleSortRec(A, low, low + mid, len); - bool secondHalf = false; - if (low + mid + 1 < len) - { - secondHalf = CircleSortRec(A, low + mid + 1, high, len); - } - return swapped || firstHalf || secondHalf; -} - -void CircleSort(SortArray& A) -{ - size_t len = A.size(), n = 1; - for (; n < len; n *= 2) {} - while (CircleSortRec(A, 0, n - 1, len)) {} -} - -bool CircleSortIte(SortArray& A, size_t length, size_t arr_len) -{ - bool swapped = false; - for (size_t gap = length / 2; gap > 0; gap /= 2) - { - for (size_t start = 0; start + gap < arr_len; start += 2 * gap) - { - size_t high = start + 2 * gap - 1, low = start; - while (low < high) - { - if (high < arr_len && A[low] > A[high]) - { - A.swap(low, high); - swapped = true; - } - ++low; --high; - } - } - } - return swapped; -} - -void CircleSort2(SortArray& A) -{ - size_t len = A.size(), n = 1; - for (; n < len; n *= 2) {} - while (CircleSortIte(A, n, len)) {} -} - -void IntroCircleSort(SortArray& A) -{ - size_t len = A.size(), threshold = 0, n = 1, iterations = 0; - for (; n < len; n *= 2, ++threshold) {} - threshold /= 2; - do - { - ++iterations; - if (iterations >= threshold) - { - InsertSort(A, 0, len); - break; - } - } - while (CircleSortRec(A, 0, n - 1, len)); -} - -void IntroIteCircleSort(SortArray& A) -{ - size_t len = A.size(), threshold = 0, n = 1, iterations = 0; - for (; n < len; n *= 2, ++threshold) {} - threshold /= 2; - do - { - ++iterations; - if (iterations >= threshold) - { - InsertSort(A, 0, len); - break; - } - } while (CircleSortIte(A, n, len)); -} - -// **************************************************************************** -// *** Gnome Sort - -// from http://en.wikipediA.org/wiki/Gnome_sort - -void GnomeSort(SortArray& A) -{ - for (size_t i = 1; i < A.size(); ) - { - if (A[i] >= A[i-1]) - { - ++i; - } - else - { - A.swap(i, i-1); - if (i > 1) --i; - } - } -} - -void OptimizedGnomeSort(SortArray& A) -{ - size_t prev = 0; - for (size_t i = 1; i < A.size(); ) - { - if (i == 0 || A[i] >= A[i - 1]) - { - if (prev != 0) { i += prev; prev = 0; } - ++i; - } - else - { - A.swap(i, i - 1); - --i; ++prev; - } - } -} - -// **************************************************************************** -// *** Comb Sort - -// from http://en.wikipediA.org/wiki/Comb_sort - -void CombSort(SortArray& A) -{ - const double shrink = 1.3; - - bool swapped = false; - size_t gap = A.size(); - - while ((gap > 1) || swapped) - { - if (gap > 1) { - gap = (size_t)((float)gap / shrink); - } - - swapped = false; - - for (size_t i = 0; gap + i < A.size(); ++i) - { - if (A[i] > A[i + gap]) - { - A.swap(i, i+gap); - swapped = true; - } - } - } -} - -// **************************************************************************** -// *** Odd-Even Sort - -// from http://en.wikipediA.org/wiki/Odd%E2%80%93even_sort - -void OddEvenSort(SortArray& A) -{ - bool sorted = false; - - while (!sorted) - { - sorted = true; - - for (size_t i = 1; i < A.size()-1; i += 2) - { - if(A[i] > A[i+1]) - { - A.swap(i, i+1); - sorted = false; - } - } - - for (size_t i = 0; i < A.size()-1; i += 2) - { - if(A[i] > A[i+1]) - { - A.swap(i, i+1); - sorted = false; - } - } - } -} - -// **************************************************************************** -// *** Shell Sort - -// with gaps by Robert Sedgewick from http://www.cs.princeton.edu/~rs/shell/shell.c - -void ShellSort(SortArray& A) -{ - size_t incs[16] = { 1391376, 463792, 198768, 86961, 33936, - 13776, 4592, 1968, 861, 336, - 112, 48, 21, 7, 3, 1 }; - - for (size_t k = 0; k < 16; k++) - { - for (size_t h = incs[k], i = h; i < A.size(); i++) - { - value_type v = A[i]; - size_t j = i; - - while (j >= h && A[j-h] > v) - { - A.set(j, A[j-h]); - j -= h; - } - - A.set(j, v); - } - } -} - -// **************************************************************************** -// *** Heap Sort - -// heavily adapted from http://www.codecodex.com/wiki/Heapsort - -bool isPowerOfTwo(size_t x) -{ - return ((x != 0) && !(x & (x - 1))); -} - -uint32_t prevPowerOfTwo(uint32_t x) -{ - x |= x >> 1; x |= x >> 2; x |= x >> 4; - x |= x >> 8; x |= x >> 16; - return x - (x >> 1); -} - -int largestPowerOfTwoLessThan(int n) -{ - int k = 1; - while (k < n) k = k << 1; - return k >> 1; -} - -void HeapSort(SortArray& A) -{ - size_t n = A.size(), i = n / 2; - - // mark heap levels with different colors - for (size_t j = i; j < n; ++j) - A.mark(j, log(prevPowerOfTwo(j+1)) / log(2) + 4); - - while (1) - { - if (i > 0) { - // build heap, sift A[i] down the heap - i--; - } - else { - // pop largest element from heap: swap front to back, and sift - // front A[0] down the heap - n--; - if (n == 0) return; - A.swap(0,n); - - A.mark(n); - if (n+1 < A.size()) A.unmark(n+1); - } - - size_t parent = i; - size_t child = i*2 + 1; - - // sift operation - push the value of A[i] down the heap - while (child < n) - { - if (child + 1 < n && A[child + 1] > A[child]) { - child++; - } - if (A[child] > A[parent]) { - A.swap(parent, child); - parent = child; - child = parent*2+1; - } - else { - break; - } - } - - // mark heap levels with different colors - A.mark(i, log(prevPowerOfTwo(i+1)) / log(2) + 4); - } - -} - -// **************************************************************************** -// *** Radix Sort (counting sort, most significant digit (MSD) first, in-place redistribute) - -// by myself (Timo Bingmann) - -void RadixSortMSD2(SortArray& A, size_t lo, size_t hi, size_t depth) -{ - A.mark(lo); A.mark(hi-1); - - // radix and base calculations - const unsigned int RADIX = 4; - - unsigned int pmax = floor( log(A.array_max()+1) / log(RADIX) ); - ASSERT(depth <= pmax); - - size_t base = pow(RADIX, pmax - depth); - - // count digits - std::vector count(RADIX, 0); - - for (size_t i = lo; i < hi; ++i) - { - size_t r = A[i].get() / base % RADIX; - ASSERT(r < RADIX); - count[r]++; - } - - // inclusive prefix sum - std::vector bkt(RADIX, 0); - std::partial_sum(count.begin(), count.end(), bkt.begin()); - - // mark bucket boundaries - for (size_t i = 0; i < bkt.size(); ++i) { - if (bkt[i] == 0) continue; - A.mark(lo + bkt[i]-1, 3); - } - - // reorder items in-place by walking cycles - for (size_t i=0, j; i < (hi-lo); ) - { - while ( (j = --bkt[ (A[lo+i].get() / base % RADIX) ]) > i ) - { - A.swap(lo + i, lo + j); - } - i += count[ (A[lo+i].get() / base % RADIX) ]; - } - - A.unmark_all(); - - // no more depth to sort? - if (depth+1 > pmax) return; - - // recurse on buckets - size_t sum = lo; - for (size_t i = 0; i < RADIX; ++i) - { - if (count[i] > 1) - RadixSortMSD2(A, sum, sum+count[i], depth+1); - sum += count[i]; - } -} - -void RadixSortMSD2(SortArray& A) -{ - return RadixSortMSD2(A, 0, A.size(), 0); -} - -/* - MIT License - - Copyright (c) 2019 w0rthy - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -size_t maxLog(SortArray& A, size_t n, size_t base) -{ - int max = A[0]; - for (size_t i = 1, j = n - 1; i <= j; ++i, --j) - { - int ele1 = A[i].get(), ele2 = A[j]; - if (ele1 > max) { max = ele1; } - if (ele2 > max) { max = ele2; } - } - size_t digit = static_cast(log(max) / log(base)); - return digit; -} - -int getDigit2(int a, double power, int radix) -{ - double digit = (a / static_cast(pow(radix, power)) % radix); - return static_cast(digit); -} - -void transcribeMSD(SortArray& A, std::vector>& registers, size_t start, size_t min) -{ - size_t total = start, temp = 0; - for (const std::vector& arr : registers) - { - total += arr.size(); - } - - for (int i = registers.size() - 1; i >= 0; --i) - { - for (int j = registers[i].size() - 1; j >= 0; --j) - { - size_t loc = total + min - temp - 1; - A.set(loc, registers[i].at(j)); - A[loc].get(); - ++temp; - } - } -} - -void radixMSD(SortArray& A, size_t len, size_t min, size_t max, size_t radix, double pow) -{ - if (min >= max || pow < 0) { return; } - A.mark(min); A.mark(max - 1); - - std::vector> registers(radix, std::vector()); - - for (size_t i = min; i < max; ++i) - { - int ele = A[i].get(); - int digit = getDigit2(ele, pow, radix); - registers[digit].push_back(A[i]); - } - - transcribeMSD(A, registers, 0, min); - A.unmark_all(); - - size_t sum = 0; - for (size_t i = 0; i < registers.size(); ++i) - { - radixMSD(A, len, sum + min, sum + min + registers[i].size(), radix, pow - 1); - sum += registers[i].size(); - registers[i].clear(); - } -} - -void RadixSortMSD(SortArray& A) -{ - size_t n = A.size(), maxPow = maxLog(A, n, 4); - radixMSD(A, n, 0, n, 4, (double)maxPow); -} - -// **************************************************************************** -// *** Radix Sort (counting sort, least significant digit (LSD) first, out-of-place redistribute) - -// by myself (Timo Bingmann) - -void RadixSortLSD(SortArray& A) -{ - // radix and base calculations - const unsigned int RADIX = 4; - - unsigned int pmax = ceil( log(A.array_max()+1) / log(RADIX) ); - - for (unsigned int p = 0; p < pmax; ++p) - { - size_t base = pow(RADIX, p); - - // count digits and copy data - std::vector count(RADIX, 0); - std::vector copy(A.size()); - - for (size_t i = 0; i < A.size(); ++i) - { - size_t r = (copy[i] = A[i]).get() / base % RADIX; - ASSERT(r < RADIX); - count[r]++; - } - - // exclusive prefix sum - std::vector bkt(RADIX+1, 0); - std::partial_sum(count.begin(), count.end(), bkt.begin()+1); - - // mark bucket boundaries - for (size_t i = 0; i < bkt.size()-1; ++i) { - if (bkt[i] >= A.size()) continue; - A.mark(bkt[i], 3); - } - - // redistribute items back into array (stable) - for (size_t i=0; i < A.size(); ++i) - { - size_t r = copy[i].get() / base % RADIX; - A.set( bkt[r]++, copy[i] ); - } - - A.unmark_all(); - } -} - -// **************************************************************************** -// *** In-Place Radix Sort LSD -/* - Copyright (c) 2019 w0rthy - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -void shiftElement(SortArray& A, size_t start, size_t end) -{ - if (start < end) - { - while (start < end) - { - A[start].get(); - A.swap(start, start + 1); - ++start; - } - } - else - { - while (start > end) - { - A[start].get(); - A.swap(start, start - 1); - --start; - } - } -} - -void InPlaceRadixSortLSD(SortArray& A) -{ - size_t pos = 0, n = A.size(); - int bucket = 20; - std::vector buckets(bucket - 1, 0); - size_t maxPow = maxLog(A, n, bucket); - for (size_t p = 0; p <= maxPow; ++p) - { - for (size_t i = 0; i < buckets.size(); ++i) { buckets[i] = n - 1; } - pos = 0; - for (size_t i = 0; i < n; ++i) - { - int ele = A[pos].get(); - int digit = getDigit2(ele, (double)p, bucket); - if (digit == 0) { ++pos; } - else - { - shiftElement(A, pos, buckets[digit - 1]); - for (size_t j = digit - 1; j > 0; --j) - { - buckets[j - 1] = buckets[j - 1] - 1; - } - } - } - } -} - -// **************************************************************************** -// *** Rotate Radix MSD/LSD Sort - -/* - Copyright (c) 2020-2021 aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -static const int base = 4; - -int shift(int n, int q) -{ - while (q > 0) - { - n /= base; - --q; - } - return n; -} - -int binSearch(SortArray& A, int a, int b, int d, int p) -{ - while (a < b) - { - int m = (a + b) / 2; - int ele = A[m].get(); - int result = static_cast(getDigit2(static_cast(ele), static_cast(p), static_cast(base))); - if (result >= d) { b = m; } - else { a = m + 1; } - } - return a; -} - -void rotateMerge(SortArray& A, int a, int m, int b, int da, int db, int p) -{ - if (b - a < 2 || db - da < 2) { return; } - int dm = (da + db) / 2; - int m1 = binSearch(A, a, m, dm, p); - int m2 = binSearch(A, m, b, dm, p); - rotate(A, m1, m, m2); - m = m1 + (m2 - m); - rotateMerge(A, m, m2, b, dm, db, p); - rotateMerge(A, a, m1, m, da, dm, p); -} - -void rotateMergeSort(SortArray& A, int a, int b, int p) -{ - if (b - a < 2) { return; } - int m = (a + b) / 2; - rotateMergeSort(A, a, m, p); - rotateMergeSort(A, m, b, p); - rotateMerge(A, a, m, b, 0, base, p); -} - -int dist(SortArray& A, int a, int b, int p) -{ - rotateMergeSort(A, a, b, p); - return binSearch(A, a, b, 1, p); -} - -void RotateRadixSortMSD(SortArray& A) -{ - int len = static_cast(A.size()); - int q = static_cast(maxLog(A, static_cast(len), static_cast(base))); - int m = 0, i = 0, b = len; - while (i < len) - { - int p = 0; - if (b - i < 1) { p = i; } - else { p = dist(A, i, b, q); } - if (q == 0) - { - m += base; - int t = m / base; - while (t % base == 0) - { - t /= base; - ++q; - } - i = b; - while (b < len) - { - int ele = A[b].get(); - if (shift(ele, q + 1) == shift(m, q + 1)) { ++b; } - else { break; } - } - } - else - { - b = p; - --q; - } - } -} - -void RotateRadixSortLSD(SortArray& A) -{ - int len = static_cast(A.size()); - int max = static_cast(maxLog(A, static_cast(len), static_cast(base))); - for (int i = 0; i <= max; ++i) - { - rotateMergeSort(A, 0, len, i); - } -} - -// **************************************************************************** -// *** Use STL Sorts via Iterator Adapters - -void siftDown(SortArray& A, size_t root, size_t dist, size_t start, bool isMax) -{ - int compareVal = 0; - if (isMax) { compareVal = -1; } - else { compareVal = 1; } - while (root <= dist / 2) - { - size_t leaf = 2 * root; - int compVal = 0; - - if (leaf < dist) - { - if (A[start + leaf - 1] < A[start + leaf]) { compVal = -1; } - else if (A[start + leaf - 1] > A[start + leaf]) { compVal = 1; } - if (compVal == compareVal) { ++leaf; } - } - - if (A[start + root - 1] < A[start + leaf - 1]) { compVal = -1; } - else if (A[start + root - 1] > A[start + leaf - 1]) { compVal = 1; } - else { compVal = 0; } - - if (compVal == compareVal) - { - A.swap(start + root - 1, start + leaf - 1); - root = leaf; - } - else { break; } - } -} - -void heapifyArr(SortArray& A, size_t low, size_t high, bool isMax) -{ - size_t len = high - low; - for (size_t i = len / 2; i >= 1; --i) - { - siftDown(A, i, len, low, isMax); - } -} - -void reverseArr(SortArray& A, size_t start, size_t len) -{ - for (size_t i = start; i < start + ((len - start + 1) / 2); ++i) - { - A.swap(i, start + len - 1); - } -} - -void HeapSort2(SortArray& A, size_t start, size_t len, bool isMax) -{ - heapifyArr(A, start, len, isMax); - for (size_t i = len - start; i > 1; --i) - { - A.swap(start, start + i - 1); - siftDown(A, 1, i - 1, start, isMax); - } - - if (!isMax) - { - reverseArr(A, start, start + len - 1); - } -} - -size_t floorLogBaseTwo(size_t a) -{ - return static_cast(floor(log(a) / log(2))); -} - -value_type gccmedianof3(SortArray& A, size_t left, size_t mid, size_t right) -{ - if (A[left] < A[mid]) - { - if (A[mid] < A[right]) - { - A.swap(left, mid); - } - else if (A[left] < A[right]) - { - A.swap(left, right); - } - } - else if (A[left] < A[right]) { return A[left]; } - else if (A[mid] < A[right]) - { - A.swap(left, right); - } - else - { - A.swap(mid, right); - } - return A[left]; -} - -value_type medianof3(SortArray& A, size_t left, size_t mid, size_t right) -{ - if (A[right] < A[left]) { A.swap(left, right); } - if (A[mid] < A[left]) { A.swap(mid, left); } - if (A[right] < A[mid]) { A.swap(right, mid); } - return A[mid]; -} - -size_t partitionArr(SortArray& A, size_t lo, size_t hi, value_type x) -{ - size_t i = lo, j = hi; - while (true) - { - while (A[i] < x) { ++i; } - --j; - while (x < A[j]) { --j; } - - if (!(i < j)) { return i; } - A.swap(i, j); - ++i; - } -} - -void introsortLoop(SortArray& A, size_t lo, size_t hi, size_t depth) -{ - size_t threshold = 16; - while (hi - lo > threshold) - { - if (depth == 0) - { - HeapSort2(A, lo, hi, true); - return; - } - --depth; - size_t p = partitionArr(A, lo, hi, medianof3(A, lo, lo + ((hi - lo) / 2), hi - 1)); - introsortLoop(A, p, hi, depth); - hi = p; - } - return; -} - -void StlSort(SortArray& A) -{ - size_t n = A.size(); - introsortLoop(A, 0, n, 2 * floorLogBaseTwo(n)); - InsertionSort(A); -} - -void StlSort2(SortArray& A) -{ - std::sort(MyIterator(&A, 0), MyIterator(&A, A.size())); -} - -void StlStableSort(SortArray& A) -{ - std::stable_sort(MyIterator(&A, 0), MyIterator(&A, A.size())); -} - -void StlHeapSort2(SortArray& A) -{ - std::make_heap(MyIterator(&A, 0), MyIterator(&A, A.size())); - std::sort_heap(MyIterator(&A, 0), MyIterator(&A, A.size())); -} - -void StlHeapSort(SortArray& A) -{ - HeapSort2(A, 0, A.size(), true); -} - -// **************************************************************************** -// *** BogoSort and more slow sorts - -// by myself (Timo Bingmann) - -bool BogoCheckSorted(SortArray& A) -{ - size_t i; - A.mark(0); - for (i = 1; i < A.size(); ++i) - { - if (A[i - 1] > A[i]) break; - A.mark(i); - } - - if (i == A.size()) { - // this is amazing. - return true; - } - - // unmark - while (i > 0) A.unmark(i--); - A.unmark(0); - - return false; -} - -void BogoSort(SortArray& A) -{ - // keep a permutation of [0,size) - std::vector perm(A.size()); - - for (size_t i = 0; i < A.size(); ++i) - perm[i] = i; - - while (1) - { - // check if array is sorted - if (BogoCheckSorted(A)) break; - - // pick a random permutation of indexes - std::shuffle(perm.begin(), perm.end(), gen1); - - // permute array in-place - std::vector pmark(A.size(), 0); - - for (size_t i = 0; i < A.size(); ++i) - { - if (pmark[i]) continue; - - // walk a cycle - size_t j = i; - - //std::cout << "cycle start " << j << " -> " << perm[j] << "\n"; - - while ( perm[j] != i ) - { - ASSERT(!pmark[j]); - A.swap(j, perm[j]); - pmark[j] = 1; - - j = perm[j]; - //std::cout << "cycle step " << j << " -> " << perm[j] << "\n"; - } - //std::cout << "cycle end\n"; - - ASSERT(!pmark[j]); - pmark[j] = 1; - } - - //std::cout << "permute end\n"; - - for (size_t i = 0; i < A.size(); ++i) - ASSERT(pmark[i]); - } -} - -void BozoSort(SortArray& A) -{ - srand(time(nullptr)); - - while (1) - { - // check if array is sorted - if (BogoCheckSorted(A)) break; - - // swap two random items - A.swap(rand() % A.size(), rand() % A.size()); - } -} - -void flip(SortArray& A, size_t high) -{ - size_t low = 0; - while (low < high) - { - A[low].get(); - A.swap(low, high); - ++low; --high; - } -} - -size_t find_max(SortArray& A, size_t n) // Optimized find_max method, searching the max element in n/2 time -{ - size_t max = 0; - for (size_t low = 1, hi = n; low <= hi; ++low, --hi) - { - if (A[low] > A[max]) - { - max = low; - } - if (A[hi] > A[max]) - { - max = hi; - } - } - return max; -} - -void PancakeSort(SortArray& A) -{ - size_t n = A.size() - 1; - for (size_t cur_size = n; cur_size >= 1; --cur_size) - { - size_t max_idx = find_max(A, cur_size); - if (max_idx != cur_size) - { - if (max_idx > 0) { flip(A, max_idx); } - flip(A, cur_size); - } - } -} - - -// **************************************************************************** -// *** Optimized Pancake Sort -/* - The MIT License (MIT) - - Copyright (c) 2021-2023 aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -void flip2(SortArray& A, size_t high) -{ - if (high > 0) { --high; } - size_t low = 0; - while (low < high) - { - A[low].get(); - A.swap(low, high); - ++low; --high; - } -} - - -bool mergeFlip(SortArray& A, size_t h1, size_t h2) -{ - if (h1 == 1 && h2 == 1) - { - if (A[0] > A[1]) { flip2(A, 2); } - return true; - } - size_t n = h1 + h2, m = n / 2; - if (h2 < h1) - { - if (h2 < 1) { return true; } - size_t i = 0, j = h2; - while (i < j) - { - size_t k = (i + j) / 2, loc = n - 1 - k; - A[loc].get(); - if (A[n - 1 - k - m] > A[loc]) { i = k + 1; } - else { j = k; } - } - flip2(A, n - m - i); - flip2(A, n - i); - if (mergeFlip(A, h2 - i, i + m - h2)) { flip2(A, m); } - flip2(A, n); - if (!mergeFlip(A, i, n - m - i)) { flip2(A, n - m); } - } - else - { - if (h1 < 1) { return false; } - size_t i = 0, j = h1; - while (i < j) - { - size_t k = (i + j) / 2; - A[k].get(); - if (A[k] < A[k + m]) { i = k + 1; } - else { j = k; } - } - flip2(A, i); - flip2(A, i + m); - if (mergeFlip(A, i + m - h1, h1 - i)) { flip2(A, m); } - flip2(A, n); - if (!mergeFlip(A, n - m - i, i)) { flip2(A, n - m); } - } - return true; -} - -void sortFlip(SortArray& A, size_t n) -{ - if (n < 2) { return; } - size_t h = n / 2; - sortFlip(A, h); - flip2(A, n); - sortFlip(A, n - h); - mergeFlip(A, n - h, h); -} - -void OptimizedPancakeSort(SortArray& A) -{ - sortFlip(A, A.size()); -} - -void BeadSort(SortArray& A) -{ - int max = A[0]; - int len = A.size(); - for (int n = 1; n < len; ++n) - { - int m = A[n].get(); - if (m > max) - { max = m; } - } - - std::vector> beads(len, std::vector(max, 0)); - - for (int i = 0; i < len; ++i) - { - int n = A[i].get(); - for (int j = 0; j < n; ++j) - { beads[i][j] = 1; } - } - - for (int j = 0; j < max; ++j) - { - int sum = 0; - for (int i = 0; i < len; ++i) - { - sum += beads[i][j]; - beads[i][j] = 0; - } - for (int i = len - 1; i >= len - sum; --i) - { - size_t k = static_cast(i); - A.set(k, ArrayItem(j + 1)); - A[k].get(); - } - } -} - -/* - MIT License - - Copyright (c) 2020 aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -void GravitySort(SortArray& A) -{ - int n = A.size(); - int min = A[0], max = A[0]; - for (int i = 1; i < n; ++i) - { - int ele = A[i].get(); - if (ele < min) { min = ele; } - if (ele > max) { max = ele; } - } - std::vector x(n, 0); - std::vector y(max - min + 1, 0); - for (int i = 0; i < n; ++i) - { - int ele = A[i].get(); - x[i] = ele - min; - y[ele - min] = y[ele - min] + 1; - } - - int y_size = static_cast(y.size() - 1); - for (int i = y_size; i > 0; --i) - { - y[i - 1] = y[i - 1] += y[i]; - } - - for (int j = y_size; j >= 0; --j) - { - for (int i = 0; i < n; ++i) - { - int val = 0, val2 = 0; - if (i >= n - y[j]) { val = 1; } - if (x[i] >= j) { val2 = 1; } - int inc = val - val2, ele = A[i].get(); - A.set(i, ArrayItem(ele + inc)); - } - } -} - -/* - MIT License - - Copyright (c) 2024 aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - -*/ - -void dualSwap(SortArray& A, std::vector& keys, int a, int b) -{ - size_t z = static_cast(a); - A[z].get(); - A.swap(z, static_cast(b)); - value_type temp = keys[a]; - keys[a] = keys[b]; - keys[b] = temp; -} - -void reversal(SortArray& A, std::vector& keys, int a, int b) -{ - while (b - a > 1) { --b; dualSwap(A, keys, a, b); ++a; } -} - -bool isAdjacent(std::vector& keys, int a, int b, int N) -{ - return (keys[a] + 1) % N == keys[b] || (keys[b] + 1) % N == keys[a]; -} - -int findAdjacent(std::vector& keys, int e, int a, int N) -{ - while (!isAdjacent(keys, a, e, N)) { ++a; } - return a; -} - -void AdjacencyPancakeSort(SortArray& A) -{ - int a = 0, N = static_cast(A.size()), b = N; - if (N == 2) - { - reverseArr(A, a, a + 1); - return; - } - std::vector keys(N); - - for (int j = a; j < b; ++j) - { - int c = 0; - for (int i = a; i < b; ++i) - { - if (i == j) { continue; } - if (A[i] < A[j] || (A[i] == A[j] && i < j)) { ++c; } - } - keys[j - a] = ArrayItem(c); - } - - while (true) - { - int i = a; - while (i < b - 1 && isAdjacent(keys, i, i + 1, N)) { ++i; } - if (i == b - 1) { break; } - if (i == a) - { - int j = findAdjacent(keys, a, a + 2, N); - if (!isAdjacent(keys, j - 1, j, N)) - { reversal(A, keys, a, j); } - else - { - int k = findAdjacent(keys, a, j + 1, N); - if (!isAdjacent(keys, k - 1, k, N)) - { reversal(A, keys, a, k); } - else - { - reversal(A, keys, a, j + 1); - reversal(A, keys, a, j); - reversal(A, keys, a, k + 1); - reversal(A, keys, a, a + k - j); - } - } - } - else - { - int j = findAdjacent(keys, a, i + 1, N); - if (!isAdjacent(keys, j - 1, j, N)) - { reversal(A, keys, a, j); } - else - { - int k = findAdjacent(keys, i, i + 2, N); - if (k + 1 < b && isAdjacent(keys, k + 1, k, N)) - { - reversal(A, keys, a, i + 1); - reversal(A, keys, a, k + 1); - } - else - { - reversal(A, keys, a, k + 1); - reversal(A, keys, a, a + k - i); - if (!isAdjacent(keys, k - 1, k, N)) - { - if (j < k) - { - reversal(A, keys, a, k + 1); - reversal(A, keys, a, i + k - j + 1); - } - else - { - reversal(A, keys, a, j + 1); - reversal(A, keys, a, a + j - k); - } - } - } - } - } - } - - int i = a; - while (keys[i] != 0 && keys[i] != N - 1) { ++i; } - if (keys[i] == 0) - { - if (i == a) { return; } - reversal(A, keys, a, b); - i = b - 2 - (i - a); - } - else if (i == a) - { - reversal(A, keys, a, b); - return; - } - ++i; - reversal(A, keys, a, i); - reversal(A, keys, a, b); - reversal(A, keys, a, b - (i - a)); -} - -// **************************************************************************** -// *** Bitonic Sort - -// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm - -namespace BitonicSortNS { - -static const bool ASCENDING = true; // sorting direction - -static void compare(SortArray& A, int i, int j, bool dir) -{ - if (dir == (A[i] > A[j])) - A.swap(i, j); -} - -static void bitonicMerge(SortArray& A, int lo, int n, bool dir) -{ - if (n > 1) - { - int m = largestPowerOfTwoLessThan(n); - - for (int i = lo; i < lo + n - m; i++) - compare(A, i, i+m, dir); - - bitonicMerge(A, lo, m, dir); - bitonicMerge(A, lo + m, n - m, dir); - } -} - -static void bitonicSort(SortArray& A, int lo, int n, bool dir) -{ - if (n > 1) - { - int m = n / 2; - bitonicSort(A, lo, m, !dir); - bitonicSort(A, lo + m, n - m, dir); - bitonicMerge(A, lo, n, dir); - } -} - -} // namespace BitonicSortNS - -void BitonicSort(SortArray& A) -{ - BitonicSortNS::bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING); -} - -// **************************************************************************** -// *** Bitonic Sort as "Parallel" Sorting Network - -// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/oddn.htm - -// modified to first record the recursively generated swap sequence, and then -// sort it back into the order a parallel sorting network would perform the -// swaps in - -namespace BitonicSortNetworkNS { - -struct swappair_type -{ - // swapped positions - unsigned int i,j; - - // depth of recursions: sort / merge - unsigned int sort_depth, merge_depth; - - swappair_type(unsigned int _i, unsigned int _j, - unsigned int _sort_depth, unsigned int _merge_depth) - : i(_i), j(_j), - sort_depth(_sort_depth), merge_depth(_merge_depth) - { } - - // order relation for sorting swaps - bool operator < (const swappair_type& b) const - { - if (sort_depth != b.sort_depth) - return sort_depth > b.sort_depth; - - if (merge_depth != b.merge_depth) - return merge_depth < b.merge_depth; - - return i < b.i; - } -}; - -typedef std::vector sequence_type; -std::vector sequence; - -void replay(SortArray& A) -{ - for (sequence_type::const_iterator si = sequence.begin(); - si != sequence.end(); ++si) - { - if (A[si->i] > A[si->j]) - A.swap(si->i, si->j); - } -} - -static const bool ASCENDING = true; // sorting direction - -static void compare(SortArray& /* A */, unsigned int i, unsigned int j, bool dir, - unsigned int sort_depth, unsigned int merge_depth) -{ - // if (dir == (A[i] > A[j])) A.swap(i, j); - - if (dir) - sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); - else - sequence.push_back( swappair_type(j,i, sort_depth, merge_depth) ); -} - -static void bitonicMerge(SortArray& A, unsigned int lo, unsigned int n, bool dir, - unsigned int sort_depth, unsigned int merge_depth) -{ - if (n > 1) - { - unsigned int m = largestPowerOfTwoLessThan(n); - - for (unsigned int i = lo; i < lo + n - m; i++) - compare(A, i, i + m, dir, sort_depth, merge_depth); - - bitonicMerge(A, lo, m, dir, sort_depth, merge_depth+1); - bitonicMerge(A, lo + m, n - m, dir, sort_depth, merge_depth+1); - } -} - -static void bitonicSort(SortArray& A, unsigned int lo, unsigned int n, bool dir, - unsigned int sort_depth) -{ - if (n > 1) - { - unsigned int m = n / 2; - bitonicSort(A, lo, m, !dir, sort_depth+1); - bitonicSort(A, lo + m, n - m, dir, sort_depth+1); - bitonicMerge(A, lo, n, dir, sort_depth, 0); - } -} - -void sort(SortArray& A) -{ - sequence.clear(); - bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING, 0); - std::sort(sequence.begin(), sequence.end()); - replay(A); - sequence.clear(); -} - -} // namespace BitonicSortNS - -void BitonicSortNetwork(SortArray& A) -{ - BitonicSortNetworkNS::sort(A); -} - -// **************************************************************************** -// *** Batcher's Odd-Even Merge Sort as "Parallel" Sorting Network - -// from http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/oemen.htm - -// modified to first record the recursively generated swap sequence, and then -// sort it back into the order a parallel sorting network would perform the -// swaps in - -namespace BatcherSortNetworkNS { - -struct swappair_type -{ - // swapped positions - unsigned int i,j; - - // depth of recursions: sort / merge - unsigned int sort_depth, merge_depth; - - swappair_type(unsigned int _i, unsigned int _j, - unsigned int _sort_depth, unsigned int _merge_depth) - : i(_i), j(_j), - sort_depth(_sort_depth), merge_depth(_merge_depth) - { } - - // order relation for sorting swaps - bool operator < (const swappair_type& b) const - { - if (sort_depth != b.sort_depth) - return sort_depth > b.sort_depth; - - if (merge_depth != b.merge_depth) - return merge_depth > b.merge_depth; - - return i < b.i; - } -}; - -typedef std::vector sequence_type; -std::vector sequence; - -void replay(SortArray& A) -{ - for (sequence_type::const_iterator si = sequence.begin(); - si != sequence.end(); ++si) - { - if (A[si->i] > A[si->j]) - A.swap(si->i, si->j); - } -} - -static void compare(SortArray& A, unsigned int i, unsigned int j, - unsigned int sort_depth, unsigned int merge_depth) -{ - // skip all swaps beyond end of array - ASSERT(i < j); - if (j >= A.size()) return; - - sequence.push_back( swappair_type(i,j, sort_depth, merge_depth) ); - - //if (A[i] > A[j]) A.swap(i, j); -} - -// lo is the starting position and n is the length of the piece to be merged, r -// is the distance of the elements to be compared -static void oddEvenMerge(SortArray& A, unsigned int lo, unsigned int n, unsigned int r, - unsigned int sort_depth, unsigned int merge_depth) -{ - unsigned int m = r * 2; - if (m < n) - { - // even subsequence - oddEvenMerge(A, lo, n, m, sort_depth, merge_depth+1); - // odd subsequence - oddEvenMerge(A, lo + r, n, m, sort_depth, merge_depth+1); - - for (unsigned int i = lo + r; i + r < lo + n; i += m) - compare(A, i, i + r, sort_depth, merge_depth); - } - else { - compare(A, lo, lo + r, sort_depth, merge_depth); - } -} - -// sorts a piece of length n of the array starting at position lo -static void oddEvenMergeSort(SortArray& A, unsigned int lo, unsigned int n, - unsigned int sort_depth) -{ - if (n > 1) - { - unsigned int m = n / 2; - oddEvenMergeSort(A, lo, m, sort_depth+1); - oddEvenMergeSort(A, lo + m, m, sort_depth+1); - oddEvenMerge(A, lo, n, 1, sort_depth, 0); - } -} - -void sort(SortArray& A) -{ - sequence.clear(); - - unsigned int n = largestPowerOfTwoLessThan(A.size()); - if (n != A.size()) n *= 2; - - oddEvenMergeSort(A, 0, n, 0); - std::sort(sequence.begin(), sequence.end()); - replay(A); - sequence.clear(); -} - -} // namespace BatcherSortNetworkNS - -void BatcherSortNetwork(SortArray& A) -{ - BatcherSortNetworkNS::sort(A); -} - -// **************************************************************************** -// *** Smooth Sort - -// from http://en.wikipediA.org/wiki/Smoothsort - -namespace SmoothSortNS { - -static const int LP[] = { - 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, - 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, - 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, - 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, - 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, - 866988873 // the next number is > 31 bits. -}; - -static void sift(SortArray& A, int pshift, int head) -{ - // we do not use Floyd's improvements to the heapsort sift, because we - // are not doing what heapsort does - always moving nodes from near - // the bottom of the tree to the root. - - value_type val = A[head]; - - while (pshift > 1) - { - int rt = head - 1; - int lf = head - 1 - LP[pshift - 2]; - - if (val.cmp(A[lf]) >= 0 && val.cmp(A[rt]) >= 0) - break; - - if (A[lf].cmp(A[rt]) >= 0) { - A.set(head, A[lf]); - head = lf; - pshift -= 1; - } - else { - A.set(head, A[rt]); - head = rt; - pshift -= 2; - } - } - - A.set(head, val); -} - -static void trinkle(SortArray& A, int p, int pshift, int head, bool isTrusty) -{ - value_type val = A[head]; - - while (p != 1) - { - int stepson = head - LP[pshift]; - - if (A[stepson].cmp(val) <= 0) - break; // current node is greater than head. sift. - - // no need to check this if we know the current node is trusty, - // because we just checked the head (which is val, in the first - // iteration) - if (!isTrusty && pshift > 1) { - int rt = head - 1; - int lf = head - 1 - LP[pshift - 2]; - if (A[rt].cmp(A[stepson]) >= 0 || - A[lf].cmp(A[stepson]) >= 0) - break; - } - - A.set(head, A[stepson]); - - head = stepson; - //int trail = Integer.numberOfTrailingZeros(p & ~1); - int trail = __builtin_ctz(p & ~1); - p >>= trail; - pshift += trail; - isTrusty = false; - } - - if (!isTrusty) { - A.set(head, val); - sift(A, pshift, head); - } -} - -void sort(SortArray& A, int lo, int hi) -{ - int head = lo; // the offset of the first element of the prefix into m - - // These variables need a little explaining. If our string of heaps - // is of length 38, then the heaps will be of size 25+9+3+1, which are - // Leonardo numbers 6, 4, 2, 1. - // Turning this into a binary number, we get b01010110 = 0x56. We represent - // this number as a pair of numbers by right-shifting all the zeros and - // storing the mantissa and exponent as "p" and "pshift". - // This is handy, because the exponent is the index into L[] giving the - // size of the rightmost heap, and because we can instantly find out if - // the rightmost two heaps are consecutive Leonardo numbers by checking - // (p&3)==3 - - int p = 1; // the bitmap of the current standard concatenation >> pshift - int pshift = 1; - - while (head < hi) - { - if ((p & 3) == 3) { - // Add 1 by merging the first two blocks into a larger one. - // The next Leonardo number is one bigger. - sift(A, pshift, head); - p >>= 2; - pshift += 2; - } - else { - // adding a new block of length 1 - if (LP[pshift - 1] >= hi - head) { - // this block is its final size. - trinkle(A, p, pshift, head, false); - } else { - // this block will get merged. Just make it trusty. - sift(A, pshift, head); - } - - if (pshift == 1) { - // LP[1] is being used, so we add use LP[0] - p <<= 1; - pshift--; - } else { - // shift out to position 1, add LP[1] - p <<= (pshift - 1); - pshift = 1; - } - } - p |= 1; - head++; - } - - trinkle(A, p, pshift, head, false); - - while (pshift != 1 || p != 1) - { - if (pshift <= 1) { - // block of length 1. No fiddling needed - //int trail = Integer.numberOfTrailingZeros(p & ~1); - int trail = __builtin_ctz(p & ~1); - p >>= trail; - pshift += trail; - } - else { - p <<= 2; - p ^= 7; - pshift -= 2; - - // This block gets broken into three bits. The rightmost bit is a - // block of length 1. The left hand part is split into two, a block - // of length LP[pshift+1] and one of LP[pshift]. Both these two - // are appropriately heapified, but the root nodes are not - // necessarily in order. We therefore semitrinkle both of them - - trinkle(A, p >> 1, pshift + 1, head - LP[pshift] - 1, true); - trinkle(A, p, pshift, head - 1, true); - } - - head--; - } -} - -} // namespace SmoothSortNS - -void SmoothSort(SortArray& A) -{ - return SmoothSortNS::sort(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Stooge Sort - -void StoogeSort(SortArray& A, int i, int j) -{ - if (A[i] > A[j]) - { - A.swap(i, j); - } - - if (j - i + 1 >= 3) - { - int t = (j - i + 1) / 3; - - A.mark(i, 3); - A.mark(j, 3); - - StoogeSort(A, i, j-t); - StoogeSort(A, i+t, j); - StoogeSort(A, i, j-t); - - A.unmark(i); - A.unmark(j); - } -} - -void StoogeSort(SortArray& A) -{ - StoogeSort(A, 0, A.size()-1); -} - -void BadSort(SortArray& A) -{ - for (size_t i = 0; i < A.size(); i++) - { - size_t shortest = i; - for (size_t j = i; j < A.size(); j++) - { - bool isShortest = true; - for (size_t k = j + 1; k < A.size(); k++) - { - if (A[j] > A[k]) - { - isShortest = false; - break; - } - } - if (isShortest) - { - shortest = j; - break; - } - } - A.swap(i, shortest); - } -} - -// **************************************************************************** -// *** Slow Sort - -void SlowSort(SortArray& A, int i, int j) -{ - if (i >= j) return; - - int m = (i + j) / 2; - - SlowSort(A, i, m); - SlowSort(A, m+1, j); - - if (A[m] > A[j]) - A.swap(m, j); - - A.mark(j, 2); - - SlowSort(A, i, j-1); - - A.unmark(j); -} - -void SlowSort(SortArray& A) -{ - SlowSort(A, 0, A.size()-1); -} - -// **************************************************************************** -// *** Cycle Sort - -// Adapted from http://en.wikipedia.org/wiki/Cycle_sort - -void CycleSort(SortArray& vec_arr, ssize_t n) -{ - std::atomic cStart, cRank; - ssize_t cycleStart = 0; - cStart.store(cycleStart); - vec_arr.watch(&cStart, 16); - - ssize_t rank = 0; - cRank.store(rank); - vec_arr.watch(&cRank, 5); - - // Loop through the array to find cycles to rotate. - for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) - { - value_type& item = vec_arr.get_mutable(cycleStart); - cStart.store(cycleStart); - do { - // Find where to put the item. - rank = cycleStart; - for (ssize_t i = cycleStart + 1; i < n; ++i) - { - if (vec_arr[i] < item) - { - rank++; - cRank.store(rank); - } - } - - // If the item is already there, this is a 1-cycle. - if (rank == cycleStart) { - vec_arr.mark(rank, 2); - break; - } - - // Otherwise, put the item after any duplicates. - while (item == vec_arr[rank]) - { - rank++; - cRank.store(rank); - } - - // Put item into right place and colorize - counted_swap(vec_arr.get_mutable(rank), item); - vec_arr.mark(rank, 2); - - // Continue for rest of the cycle. - } while (rank != cycleStart); - } - - vec_arr.unwatch_all(); -} - -void CycleSort(SortArray& A) -{ - CycleSort(A, A.size()); -} - - -// **************************************************************************** -// *** Pairwise Sorting Network (Recursive and Iterative) -/* - Copyright (c) 2021 aphitorite - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -void compSwap(SortArray& A, size_t a, size_t b) -{ - size_t n = A.size(); - if (b < n && A[a] > A[b]) { A.swap(a, b); } -} -void PairwiseMerge(SortArray& A, size_t a, size_t b) -{ - size_t m = (a + b) / 2, m1 = (a + m) / 2, g = m - m1; - for (size_t i = 0; m1 + i < m; ++i) - { - for (size_t j = m1, k = g; k > 0; k >>= 1, j -= k - (i & k)) - { - compSwap(A, j + i, j + i + k); - } - } - if (b - a > 4) { PairwiseMerge(A, m, b); } -} - -void PairwiseMergeSort(SortArray& A, size_t a, size_t b) -{ - size_t m = (a + b) / 2; - for (size_t i = a, j = m; i < m; ++i, ++j) - { - compSwap(A, i, j); - } - if (b - a > 2) - { - PairwiseMergeSort(A, a, m); - PairwiseMergeSort(A, m, b); - PairwiseMerge(A, a, b); - } -} - -void PairwiseSort(SortArray& A) -{ - size_t end = A.size(); - size_t n = 1; - for (; n < end; n <<= 1) {} - PairwiseMergeSort(A, 0, n); -} - -void PairwiseIterativeSort(SortArray& A) -{ - size_t end = A.size(), n = 1; - for (; n < end; n <<= 1) {} - for (size_t k = n >> 1; k > 0; k >>= 1) - { - for (size_t j = 0; j < end; j += k << 1) - { - for (size_t i = 0; i < k; ++i) - { - compSwap(A, j + i, j + i + k); - } - } - } - for (size_t k = 2; k < n; k <<= 1) - { - for (size_t j = k >> 1; j > 0; j >>= 1) - { - for (size_t i = 0; i < end; i += k << 1) - { - for (size_t m = j; m < ((k - j) << 1); m += j << 1) - { - for (size_t o = 0; o < j; ++o) - { - compSwap(A, i + m + o, i + m + j + o); - } - } - } - } - } -} - -// **************************************************************************** -// *** American Flag Sort -// Adapted from https://en.wikipedia.org/wiki/American_flag_sort -/* - Copyright 2017 Justin Wetherell - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -size_t getDigit(size_t num, size_t divisor, size_t buckets) { return (num / divisor) % buckets; } - -int getMaxNumberOfDigits(SortArray& A, size_t len, int buckets) -{ - int max = std::numeric_limits::min(); - int temp = 0; - for (size_t i = 0; i < len; ++i) - { - int ele = A[i].get(); - temp = static_cast(log(ele) / log(buckets)) + 1; - if (temp > max) { max = temp; } - } - return max; -} - -void sort(SortArray& A, size_t start, size_t len, size_t divisor) -{ - size_t buckets = 128; - std::vector count(buckets, 0); - std::vector offset(buckets, 0); - size_t digit = 0; - - for (size_t i = start; i < len; ++i) - { - int d = A[i].get(); - size_t l = d; - digit = getDigit(l, divisor, buckets); - count[digit] = count[digit] + 1; - } - int s = start; - offset[0] = s; - - for (size_t i = 1; i < buckets; ++i) - { - offset[i] = count[i - 1] + offset[i - 1]; - } - - for (size_t b = 0; b < buckets; ++b) - { - while (count[b] > 0) - { - size_t origin = offset[b], from = origin; - int num = A[from]; - do - { - size_t m = num; - digit = getDigit(m, divisor, buckets); - size_t to = offset[digit]; - - offset[digit] = offset[digit] + 1; - count[digit] = count[digit] - 1; - - int temp = A[to].get(); - A.set(to, ArrayItem(num)); - - num = temp; - from = to; - } - while (from != origin); - } - } - if (divisor > 1) - { - for (size_t i = 0; i < buckets; ++i) - { - size_t begin = 0; - if (i > 0) { begin = offset[i - 1]; } - else { begin = start; } - size_t last = offset[i]; - - if (last - begin > 1) - { - sort(A, begin, last, divisor / buckets); - } - } - } -} - -void AmericanFlagSort(SortArray& A) -{ - size_t len = A.size(); - int buckets = 128, max = 1; - int numberOfDigits = getMaxNumberOfDigits(A, len, buckets); // Max number of digits - - for (int i = 0; i < numberOfDigits - 1; ++i) { max *= buckets; } - - size_t m = max; - sort(A, 0, len, m); -} - - -// **************************************************************************** -// *** Strand Sort - -/* - MIT License - - Copyright (c) 2020-2021 aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -void mergeTo(SortArray& A, std::vector& subList, size_t a, size_t m, size_t b) -{ - size_t i = 0, s = m - a; - while (i < s && m < b) - { - if (subList[i] < A[m]) - { - A.set(a++, subList[i++]); - } - else - { - A.set(a++, A[m++]); - } - } - while (i < s) - { - A.set(a++, subList[i++]); - } -} - -void StrandSort(SortArray& A) -{ - size_t n = A.size(), j = n, k = j; - std::vector subList(n); - while (j > 0) - { - subList[0] = A[0]; - --k; - for (size_t i = 0, p = 0, m = 1; m < j; ++m) - { - if (A[m] >= subList[i]) - { - subList[++i] = A[m]; - --k; - } - else - { - A.set(p++, A[m]); - } - } - mergeTo(A, subList, k, j, n); - j = k; - } -} - - -// **************************************************************************** -// *** New Shuffle Merge Sort -/* - MIT License - - Copyright (c) 2021 EmeraldBlock - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -/* - * Implements https://www.sciencedirect.com/science/article/pii/S1877050910005478. - * - * The shuffle algorithm is at https://arxiv.org/abs/0805.1598. - * Note that the unshuffle algorithm is not the shuffle algorithm in reverse, - * but rather, it is a variation of the shuffle algorithm. - * - * See also a proof of the time complexity at https://arxiv.org/abs/1508.00292. - * The implementation is based on the pseudocode found in this. -*/ - -void rotateEqual(SortArray& A, size_t a, size_t b, size_t size) -{ - for (size_t i = 0; i < size; ++i) - { - A.swap(a + i, b + i); - } -} - -void rotateArray(SortArray& A, size_t mid, size_t a, size_t b) -{ - while (a > 0 && b > 0) - { - if (a > b) - { - rotateEqual(A, mid - b, mid, b); - mid -= b; - a -= b; - } - else - { - rotateEqual(A, mid - a, mid, a); - mid += a; - b -= a; - } - } -} - -void shuffleEasy(SortArray& A, size_t start, size_t size) -{ - for (size_t i = 1; i < size; i *= 3) - { - value_type val = A[start + i - 1]; - for (size_t j = i * 2 % size; j != i; j = j * 2 % size) - { - value_type nval = A[start + j - 1]; - A.set(start + j - 1, val); - val = nval; - } - A.set(start + i - 1, val); - } -} - -void shuffleArray(SortArray& A, size_t start, size_t end) -{ - while (end - start > 1) - { - size_t n = (end - start) / 2, l = 1; - while (l * 3 - 1 <= 2 * n) { l *= 3; } - size_t m = (l - 1) / 2; - rotateArray(A, start + n, n - m, m); - shuffleEasy(A, start, l); - start += l - 1; - } -} - -void rotateShuffledEqual(SortArray& A, size_t a, size_t b, size_t size) -{ - for (size_t i = 0; i < size; i += 2) - { - A.swap(a + i, b + i); - } -} - -void rotateShuffled(SortArray& A, size_t mid, size_t a, size_t b) -{ - while (a > 0 && b > 0) - { - if (a > b) - { - rotateShuffledEqual(A, mid - b, mid, b); - mid -= b; - a -= b; - } - else - { - rotateShuffledEqual(A, mid - a, mid, a); - mid += a; - b -= a; - } - } -} - -void rotateShuffledOuter(SortArray& A, size_t mid, size_t a, size_t b) -{ - if (a > b) - { - rotateShuffledEqual(A, mid - b, mid + 1, b); - mid -= b; - a -= b; - rotateShuffled(A, mid, a, b); - } - else - { - rotateShuffledEqual(A, mid - a, mid + 1, a); - mid += a + 1; - b -= a; - rotateShuffled(A, mid, a, b); - } -} - -void unshuffleEasy(SortArray& A, size_t start, size_t size) -{ - for (size_t i = 1; i < size; i *= 3) - { - size_t prev = i; - value_type val = A[start + i - 1]; - for (size_t j = i * 2 % size; j != i; j = j * 2 % size) { - A.set(start + prev - 1, A[start + j - 1]); - prev = j; - } - A.set(start + prev - 1, val); - } -} - -void unshuffle(SortArray& A, size_t start, size_t end) -{ - while (end - start > 1) - { - size_t n = (end - start) / 2, l = 1; - while (l * 3 - 1 <= 2 * n) { l *= 3; } - size_t m = (l - 1) / 2; - - rotateShuffledOuter(A, start + 2 * m, 2 * m, 2 * n - 2 * m); - unshuffleEasy(A, start, l); - start += l - 1; - } -} - -void mergeUp(SortArray& A, size_t start, size_t end, bool type) -{ - size_t i = start, j = i + 1; - while (j < end) - { - if (A[i] < A[j] || (!type && A[i] == A[j])) - { - ++i; - if (i == j) - { - ++j; - type = !type; - } - } - else if (end - j == 1) - { - rotateArray(A, j, j - i, 1); - break; - } - else - { - size_t r = 0; - if (type) - { - while (j + 2 * r < end && A[j + 2 * r] <= A[i]) { ++r; } - } - else - { - while (j + 2 * r < end && A[j + 2 * r] < A[i]) { ++r; } - } - --j; - unshuffle(A, j, j + 2 * r); - rotateArray(A, j, j - i, r); - i += r + 1; - j += 2 * r + 1; - } - } -} - -void mergeArray(SortArray& A, size_t start, size_t mid, size_t end) -{ - if (mid - start <= end - mid) - { - shuffleArray(A, start, end); - mergeUp(A, start, end, true); - } - else - { - shuffleArray(A, start + 1, end); - mergeUp(A, start, end, false); - } -} - -size_t ceilPowerOfTwo(size_t x) -{ - --x; - for (size_t i = 16; i > 0; i >>= 1) { x |= x >> i; } - return ++x; -} - -void sortLarge(SortArray& A, size_t len) -{ - for (size_t subarrayCount = ceilPowerOfTwo(len), wholeI = len / subarrayCount, fracI = len % subarrayCount; subarrayCount > 1; ) - { - for (size_t whole = 0, frac = 0; whole < len; ) - { - size_t start = whole; - whole += wholeI; - frac += fracI; - if (frac >= subarrayCount) - { - ++whole; - frac -= subarrayCount; - } - size_t mid = whole; - whole += wholeI; - frac += fracI; - if (frac >= subarrayCount) - { - ++whole; - frac -= subarrayCount; - } - mergeArray(A, start, mid, whole); - } - subarrayCount >>= 1; - wholeI <<= 1; - if (fracI >= subarrayCount) - { - ++wholeI; - fracI -= subarrayCount; - } - } -} - -void mergeSortArray(SortArray& A, size_t len) -{ - if (len < 1 << 15) - { - for (size_t subarrayCount = ceilPowerOfTwo(len); subarrayCount > 1; subarrayCount >>= 1) - { - for (size_t i = 0; i < subarrayCount; i += 2) - { - mergeArray(A, len * i / subarrayCount, len * (i + 1) / subarrayCount, len * (i + 2) / subarrayCount); - } - } - } - else - { - sortLarge(A, len); - } -} - -void NewShuffleMergeSort(SortArray& A) -{ - size_t len = A.size(); - mergeSortArray(A, len); -} - -// **************************************************************************** -// *** Andrey Astrelin's In-Place Merge Sort - -void sortVector(SortArray& A, size_t a, size_t b) -{ - while (b > 1) - { - size_t k = 0; - for (size_t i = 1; i < b; ++i) - { - if (A[a + k] > A[a + i]) { k = i; } - } - A.swap(a, a + k); - ++a; --b; - } -} - -void aswap(SortArray& A, size_t arr1, size_t arr2, size_t l) -{ - while (l-- > 0) - { - A.swap(arr1, arr2); - ++arr1; ++arr2; - } -} - -int backMerge(SortArray& A, size_t arr1, size_t l1, size_t arr2, size_t l2) -{ - size_t arr0 = arr2 + l1; - for (;;) - { - if (A[arr1] > A[arr2]) - { - A.swap(arr1, arr0); - --arr1; --arr0; - if (--l1 == 0) { return 0; } - } - else - { - A.swap(arr2, arr0); - --arr2; --arr0; - if (--l2 == 0) { break; } - } - } - size_t res = l1; - do - { - A.swap(arr1, arr0); - --arr1; --arr0; - } - while (--l1 != 0); - return res; -} - -void rMerge(SortArray& A, size_t a, size_t l, size_t r) -{ - for (size_t i = 0; i < l; i += r) - { - size_t q = i; - for (size_t j = i + r; j < l; j += r) - { - if (A[a + q] > A[a + j]) { q = j; } - } - if (q != i) { aswap(A, a + i, a + q, r); } - if (i != 0) - { - aswap(A, a + l, a + i, r); - backMerge(A, a + (l + r - 1), r, a + (i - 1), r); - } - } -} - -size_t rbnd(size_t len) -{ - len = len / 2; - size_t k = 0; - for (size_t i = 1; i < len; i *= 2) { ++k; } - len /= k; - for (k = 1; k <= len; k *= 2) {} - return k; -} - -void msort(SortArray& A, size_t a, size_t len) -{ - if (len < 12) { sortVector(A, a, len); return; } - size_t r = rbnd(len), lr = (len / r - 1) * r; - for (size_t p = 2; p <= lr; p += 2) - { - if (A[a + (p - 2)] > A[a + (p - 1)]) - { A.swap(a + (p - 2), a + (p - 1)); } - if ((p & 2) != 0) { continue; } - aswap(A, a + (p - 2), a + p, 2); - size_t m = len - p, q = 2; - for (;;) - { - size_t q0 = 2 * q; - if (q0 > m || (p & q0) != 0) { break; } - backMerge(A, a + (p - q - 1), q, a + (p + q - 1), q); - q = q0; - } - backMerge(A, a + (p + q - 1), q, a + (p - q - 1), q); - size_t q1 = q; - q *= 2; - while ((q & p) == 0) - { - q *= 2; - rMerge(A, a + (p - q), q, q1); - } - } - - size_t q1 = 0; - for (size_t q = r; q < lr; q *= 2) - { - if ((lr & q) != 0) - { - q1 += q; - if (q1 != q) - { - rMerge(A, a + (lr - q1), q1, r); - } - } - } - - size_t s = len - lr; - msort(A, a + lr, s); - aswap(A, a, a + lr, s); - s += backMerge(A, a + (s - 1), s, a + (lr - 1), lr - s); - msort(A, a, s); -} - -void AndreyMergeSort(SortArray& A) -{ - msort(A, 0, A.size()); -} - - -// **************************************************************************** -// *** Proportion Extend Merge Sort - -/* - MIT License - - Copyright (c) 2023 aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -void blockSwap(SortArray& A, size_t a, size_t b, size_t s) -{ - while (s-- > 0) - { - A.swap(a, b); - ++a; ++b; - } -} - -size_t partition(SortArray& A, size_t a, size_t b, size_t p) -{ - size_t i = a - 1, j = b; - while (true) - { - do { ++i; } while (i < j && A[i] < A[p]); - do { --j; } while (j >= i && A[j] > A[p]); - if (i < j) { A.swap(i, j); } - else { return i; } - } -} - -void mergeFW(SortArray& A, size_t a, size_t m, size_t b, size_t p) -{ - size_t pLen = m - a, i = 0, j = m, k = a; - blockSwap(A, a, p, pLen); - while (i < pLen && j < b) - { - if (A[p + i] <= A[j]) { A.swap(k, p + i); ++k; ++i; } - else { A.swap(k, j); ++k; ++j; } - } - while (i < pLen) { A.swap(k, p + i); ++k; ++i; } -} - -void mergeBW(SortArray& A, size_t a, size_t m, size_t b, size_t p) -{ - size_t pLen = b - m; - int i = static_cast(pLen - 1), - j = static_cast(m - 1), - k = static_cast(b - 1), - z = static_cast(a); - blockSwap(A, m, p, pLen); - while (i >= 0 && j >= z) - { - if (A[p + i] >= A[j]) { A.swap(k, p + i); --k; --i; } - else { A.swap(k, j); --k; --j; } - } - while (i >= 0) { A.swap(k, p + i); --k; --i; } -} - -void smartMerge(SortArray& A, size_t a, size_t m, size_t b, size_t p) -{ - if (m - a < b - m) { mergeFW(A, a, m, b, p); } - else { mergeBW(A, a, m, b, p); } -} - -void mergeTo(SortArray& A, size_t a, size_t m, size_t b, size_t p) -{ - size_t i = a, j = m; - while (i < m && j < b) - { - if (A[i] <= A[j]) { A.swap(p, i); ++p; ++i; } - else { A.swap(p, j); ++p; ++j; } - } - while (i < m) { A.swap(p, i); ++p; ++i; } - while (j < b) { A.swap(p, j); ++p; ++j; } -} - -void pingPongMerge(SortArray& A, size_t a, size_t m1, size_t m, size_t m2, size_t b, size_t p) -{ - size_t p1 = p + m - a, pEnd = p + b - a; - mergeTo(A, a, m1, m, p); - mergeTo(A, m, m2, b, p1); - mergeTo(A, p, p1, pEnd, a); -} - -void mergeSort(SortArray& A, size_t a, size_t b, size_t p) -{ - const size_t min_insert = 8; - size_t n = b - a, j = n; - for (; (j + 3) / 4 >= min_insert; j = (j + 3) / 4) {} - for (size_t i = a; i < b; i += j) - { - BinaryInsertSort(A, i, std::min(b, i + j)); - } - for (size_t i; j < n; j *= 4) - { - for (i = a; i + 2 * j < b; i += 4 * j) - { - pingPongMerge(A, i, i + j, i + 2 * j, std::min(i + 3 * j, b), std::min(i + 4 * j, b), p); - - } - if (i + j < b) { mergeBW(A, i, i + j, b, p); } - } -} - -void smartMergeSort(SortArray& A, size_t a, size_t b, size_t p, size_t pb) -{ - if (b - a <= pb - p) { mergeSort(A, a, b, p); return; } - size_t m = (a + b) >> 1; - mergeSort(A, a, m, p); - mergeSort(A, m, b, p); - mergeFW(A, a, m, b, p); -} - -void peSort(SortArray& A, size_t a, size_t m, size_t b) -{ - size_t n = b - a; - const size_t min_insert = 8; - if (n < 4 * min_insert) { BinaryInsertSort(A, a, b); return; } - if (m - a <= n / 3) - { - size_t t = (n + 2) / 3; - smartMergeSort(A, m, b - t, b - t, b); - smartMerge(A, a, m, b - t, b - t); - m = b - t; - } - size_t m1 = (a + m) >> 1, m2 = partition(A, m, b, m1); - size_t i = m, j = m2; - while (i > m1) { --i; --j; A.swap(i, j); } - m = m2 - (m - m1); - if (m - m1 < b - m2) - { - mergeSort(A, m1, m, m2); - smartMerge(A, a, m1, m, m2); - peSort(A, m + 1, m2, b); - } - else - { - mergeSort(A, m2, b, m1); - smartMerge(A, m + 1, m2, b, m1); - peSort(A, a, m1, m); - } -} - -void ProportionMergeSort(SortArray& A) -{ - peSort(A, 0, 0, A.size()); -} - -// **************************************************************************** -// *** Buffer Partition Merge Sort - -/* - * - MIT License - - Copyright (c) 2021 yuji, implemented by aphitorite - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -* -*/ - -void shiftBW2(SortArray& A, int a, int m, int b) -{ - while (m > a) - { - --b; --m; - A.swap(static_cast(b), static_cast(m)); - } -} - -void inPlaceMerge(SortArray& A, int a, int m, int b) -{ - int i = a, j = m, k = 0; - while (i < j && j < b) - { - if (A[i] > A[j]) - { - k = j; ++k; - while (k < b && A[i] > A[k]) { ++k; } - rotate(A, static_cast(i), static_cast(j), static_cast(k)); - i += k - j; - j = k; - } - else { ++i; } - } -} - -void medianOfThree(SortArray& A, int a, int b) -{ - int m = a + (b - 1 - a) / 2; - if (A[a] > A[m]) { A.swap(static_cast(a), static_cast(m)); } - if (A[m] > A[b - 1]) - { - A.swap(static_cast(m), static_cast(b - 1)); - if (A[a] > A[m]) { return; } - } - A.swap(static_cast(a), static_cast(m)); -} - -void medianofMedians(SortArray& A, int a, int b, int s) -{ - int end = b, start = a, i, j; - bool ad = true; - while (end - start > 1) - { - j = start; - for (i = start; i + 2 * s <= end; i += s) - { - InsertSort(A, static_cast(i), static_cast(i + s)); - A.swap(static_cast(j), static_cast(i + s / 2)); - ++j; - } - if (i < end) - { - InsertSort(A, static_cast(i), static_cast(end)); - int val = 0; - if (ad) { val = 1; } - A.swap(static_cast(j), static_cast(i + (end - val - i) / 2)); - if ((end - i) % 2 == 0) { ad = !ad; } - ++j; - } - end = j; - } -} - -int partition(SortArray& A, int a, int b) -{ - int i = a, j = b; - while (true) - { - do { ++i; } - while (i < j && A[i] > A[a]); - do { --j; } - while (j >= i && A[j] < A[a]); - if (i < j) { A.swap(static_cast(i), static_cast(j)); } - else { return j; } - } -} - -int quickSelect(SortArray& A, int a, int b, int m) -{ - bool badPartition = false, mom = false; - int m1 = (m + b + 1) / 2; - while (true) - { - if (badPartition) - { - medianofMedians(A, a, b, 5); - mom = true; - } - else { medianOfThree(A, a, b); } - int p = partition(A, a, b); - A.swap(static_cast(a), static_cast(p)); - int l = std::max(1, p - a), r = std::max(1, b - (p + 1)); - badPartition = !mom && (l / r >= 16 || r / l >= 16); - if (p >= m && p < m1) { return p; } - else if (p < m) { a = p + 1; } - else { b = p; } - } -} - -void mergeVector(SortArray& A, int a, int m, int b, int p) -{ - int i = a, j = m; - while (i < m && j < b) - { - if (A[i] <= A[j]) - { - A.swap(static_cast(p), static_cast(i)); - ++p; ++i; - } - else - { - A.swap(static_cast(p), static_cast(j)); - ++p; ++j; - } - } - while (i < m) - { - A.swap(static_cast(p), static_cast(i)); - ++p; ++i; - } - while (j < b) - { - A.swap(static_cast(p), static_cast(j)); - ++p; ++j; - } -} - -int mergeFW2(SortArray& A, int p, int a, int m, int b) -{ - int i = a, j = m; - while (i < m && j < b) - { - if (A[i] <= A[j]) - { - A.swap(static_cast(p), static_cast(i)); - ++p; ++i; - } - else - { - A.swap(static_cast(p), static_cast(j)); - ++p; ++j; - } - } - if (i < m) { return i; } - else { return j; } -} - -int getMinLevel(int n) -{ - while (n >= 32) { n = (n + 3) / 4; } - return n; -} - -void mergeSort2(SortArray& A, int a, int b, int p) -{ - int len = b - a; - if (len < 2) { return; } - int i, pos, j = getMinLevel(len); - for (i = a; i + j <= b; i += j) - { - BinaryInsertSort(A, static_cast(i), static_cast(i + j)); - } - BinaryInsertSort(A, static_cast(i), static_cast(b)); - while (j < len) - { - pos = p; - for (i = a; i + 2 * j <= b; i += 2 * j, pos += 2 * j) - { mergeVector(A, i, i + j, i + 2 * j, pos); } - if (i + j < b) { mergeVector(A, i, i + j, b, pos); } - else - { - while (i < b) - { - A.swap(static_cast(i), static_cast(pos)); - ++i; ++pos; - } - } - j *= 2; - pos = a; - for (i = p; i + 2 * j <= p + len; i += 2 * j, pos += 2 * j) - { mergeVector(A, i, i + j, i + 2 * j, pos); } - if (i + j < p + len) { mergeVector(A, i, i + j, p + len, pos); } - else - { - while (i < p + len) - { - A.swap(static_cast(i), static_cast(pos)); - ++i; ++pos; - } - } - j *= 2; - } -} - -void sortArray(SortArray& A, int a, int b) -{ - int minLvl = static_cast(sqrt(b - a)); - int m = (a + b + 1) / 2; - mergeSort2(A, m, b, a); - while (m - a > minLvl) - { - int m1 = (a + m + 1) / 2; - m1 = quickSelect(A, a, m, m1); - mergeSort2(A, m1, m, a); - int bSize = m1 - a; - int m2 = std::min(m1 + bSize, b); - m1 = mergeFW2(A, a, m1, m, m2); - while (m1 < m) - { - shiftBW2(A, m1, m, m2); - m1 = m2 - (m - m1); - a = m1 - bSize; - m = m2; - if (m == b) { break; } - m2 = std::min(m2 + bSize, b); - m1 = mergeFW2(A, a, m1, m, m2); - } - m = m1; - a = m1 - bSize; - } - BinaryInsertSort(A, static_cast(a), static_cast(m)); - inPlaceMerge(A, a, m, b); -} - -void BufferPartitionMergeSort(SortArray& A) -{ - sortArray(A, 0, A.size()); -} \ No newline at end of file From b1c61e35fdcfb7a4eeafa45466c9427da6c98320 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 21:42:42 +0800 Subject: [PATCH 267/289] Minor text correction --- src/SortAlgo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index b6a13d515..cb69800fd 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -97,8 +97,8 @@ const struct AlgoEntry g_algolist[] = _("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, " "two at left and one at right.") }, { _("PDQ Sort"), &PDQSort, UINT_MAX, inversion_count_instrumented, - _("Pattern-defeating quicksort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" - "with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, + _("Pattern-defeating Quick Sort (pdqsort) is a novel sorting algorithm that combines the fast average case of randomized quicksort" + " with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns.") }, { _("Branchless PDQ Sort"), &PDQSortBranchless, UINT_MAX, inversion_count_instrumented, _("Provides potential speedup over default Pattern-Defeating Quick Sort for arithmetic data.") }, { _("Flan Sort (Quick Library Sort)"), &QuickLibrarySort, UINT_MAX, inversion_count_instrumented, From a58ae22bd623f2e0f4a5c55687ad83ed02dd3049 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 23:00:02 +0800 Subject: [PATCH 268/289] Allowed additional algorithms to work under C++11 --- src/algorithms/grailsort.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/grailsort.cpp b/src/algorithms/grailsort.cpp index 21093b862..4fd98a059 100644 --- a/src/algorithms/grailsort.cpp +++ b/src/algorithms/grailsort.cpp @@ -1297,7 +1297,7 @@ namespace grailsort_detail template< typename RandomAccessIterator, - typename Compare = std::less<> + typename Compare = std::less::value_type> > void grailsort(RandomAccessIterator first, RandomAccessIterator last, Compare comp = {}) { @@ -1312,7 +1312,7 @@ void grailsort(RandomAccessIterator first, RandomAccessIterator last, Compare co template< typename RandomAccessIterator1, typename RandomAccessIterator2, - typename Compare = std::less<> + typename Compare = std::less::value_type> > void grailsort(RandomAccessIterator1 first, RandomAccessIterator1 last, RandomAccessIterator2 buff_first, RandomAccessIterator2 buff_last, From 5608cc01a7668745f7ff09a8b2e15ecd6901fafd Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 23:01:36 +0800 Subject: [PATCH 269/289] Allowed the visualizer to properly compile under C++11 This should allow the visualizer to be more compatible now. With this change, the project should now compile under at least C++11 --- src/SortArray.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SortArray.h b/src/SortArray.h index 7c5327fcb..8d2a007fc 100644 --- a/src/SortArray.h +++ b/src/SortArray.h @@ -24,7 +24,7 @@ #ifndef SORT_ARRAY_HEADER #define SORT_ARRAY_HEADER -#include +#include #include #include #include @@ -106,7 +106,7 @@ constexpr void counted_reverse(BidirIt first, BidirIt last) { using iter_cat = typename std::iterator_traits::iterator_category; - if constexpr (std::is_base_of_v) + if (std::is_base_of::value) { if (first == last) { return; } for (--last; first < last; (void)++first, --last) @@ -119,7 +119,7 @@ void counted_reverse(BidirIt first, BidirIt last) } } -template > +template > void counted_make_heap(RandomIt first, RandomIt last, Compare comp = Compare()) { if (last - first < 2) return; @@ -155,7 +155,7 @@ void sift_down(RandomIt first, RandomIt last, std::size_t index, Compare comp) } } -template > +template > void counted_sort_heap(RandomIt first, RandomIt last, Compare comp = Compare()) { while (last - first > 1) From dd70178c38b7d7e6cc019983a43972695c191b17 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Thu, 7 Nov 2024 23:16:46 +0800 Subject: [PATCH 270/289] Ensure that no changes are missed out From 0c87005f56c0f091508a221638fb1994b06aded9 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 8 Nov 2024 00:27:20 +0800 Subject: [PATCH 271/289] Added Median of Eleven, increased minimum high-low threshold This should allow all higher Median of N implementations to perform at least a little better due to higher threshold (previous * 2), since clustering has even lesser chances of happening, especially the randomized variants. --- src/SortAlgo.cpp | 69 +++++++++++++++++++++++++++++++++++++++++------- src/SortAlgo.h | 2 +- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index cb69800fd..9434dc976 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -749,9 +749,29 @@ static void PivotInsertionSort(SortArray& A, std::array& arr) } } +std::array gaps = { 8, 3, 1 }; +template +static void PivotShellSort(SortArray& A, std::array& arr) +{ + for (size_t k = 0; k < 3; ++k) + { + for (size_t h = gaps[k], i = h; i < N; ++i) + { + ssize_t key = arr[i]; + size_t j = i; + while (j >= h && A[arr[j - h]] > A[key]) + { + arr[j] = arr[j - h]; + j -= h; + } + arr[j] = key; + } + } +} + static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) { - if (hi - lo < 5) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 10) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 5; std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; PivotInsertionSort(A, nums); @@ -760,7 +780,7 @@ static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) static ssize_t NintherPivot(SortArray& A, ssize_t lo, ssize_t hi) { - if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 18) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment_size = (hi - lo) / 9; ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); @@ -819,7 +839,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 5) + if (hi - lo < 10) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -829,7 +849,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN7: { - if (hi - lo < 7) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 14) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 7; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; PivotInsertionSort(A, samples); @@ -844,7 +864,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 7) + if (hi - lo < 14) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -865,7 +885,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 9) + if (hi - lo < 18) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -878,7 +898,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN9: { - if (hi - lo < 9) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 18) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 9; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8 }; PivotInsertionSort(A, samples); @@ -893,7 +913,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 9) + if (hi - lo < 18) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -901,9 +921,36 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) PivotInsertionSort(A, samples); return samples[4]; } + case PIVOT_MEDIAN11: + { + if (hi - lo < 22) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 11; + std::array samples = {lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8, lo + segment * 9, lo + segment * 10 }; + PivotShellSort(A, samples); + return samples[5]; + break; + } + case PIVOT_MEDIAN11RANDOM: + { + if (lo > hi) + { + ssize_t temp = lo; + lo = hi; + hi = temp; + } + std::uniform_int_distribution dist(lo, hi - 1); + if (hi - lo < 22) + { + return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); + } + std::array samples = { dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1), dist(gen1) }; + PivotShellSort(A, samples); + return samples[5]; + break; + } case PIVOT_MEDIAN15: { - if (hi - lo < 15) { return MedianOfFive(A, lo, hi); } + if (hi - lo < 30) { return MedianOfFive(A, lo, hi); } ssize_t segment = (hi - lo) / 3; ssize_t g1 = MedianOfFive(A, lo, lo + segment); ssize_t g2 = MedianOfFive(A, lo + segment, lo + segment * 2); @@ -912,7 +959,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_THREENINTHER: { - if (hi - lo < 27) { return NintherPivot(A, lo, hi); } + if (hi - lo < 54) { return NintherPivot(A, lo, hi); } ssize_t segment = (hi - lo) / 3; ssize_t g1 = NintherPivot(A, lo, lo + segment); ssize_t g2 = NintherPivot(A, lo + segment, lo + segment * 2); @@ -944,6 +991,8 @@ wxArrayString QuickSortPivotText() sl.Add(_("Random Ninther")); sl.Add(_("Median of Nine")); sl.Add(_("Random Median of Nine")); + sl.Add(_("Median of Eleven")); + sl.Add(_("Random Median of Eleven")); sl.Add(_("Median of Fifteen")); sl.Add(_("Median of Three Ninther")); return sl; diff --git a/src/SortAlgo.h b/src/SortAlgo.h index f2d1311ee..632f58f05 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM, PIVOT_MEDIAN15, PIVOT_THREENINTHER }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM, PIVOT_MEDIAN11, PIVOT_MEDIAN11RANDOM, PIVOT_MEDIAN15, PIVOT_THREENINTHER }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From d1cedd10db0e7ac83c1210c380cf68da98fea232 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 8 Nov 2024 02:39:52 +0800 Subject: [PATCH 272/289] Drastically increased minimum threshold for Median of N Credits to @Taihennami on "The Studio" Discord for introducing me to this great minimum threshold formula, as well as introducing me to using Shell Sort for sorting n = 11. The minimum threshold for all higher Median of N is now (n * n), such as 5 * 5 = 25, or n^2, this should allow all higher Median of N pivot rules to perform faster on small array sizes due to having less overhead, as well as providing better pivot selection when the boundary is high enough. --- src/SortAlgo.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 9434dc976..f97ed2fe7 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -771,7 +771,7 @@ static void PivotShellSort(SortArray& A, std::array& arr) static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) { - if (hi - lo < 10) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 25) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 5; std::array nums = { lo, lo + segment, lo + 2 * segment, lo + 3 * segment, lo + 4 * segment }; PivotInsertionSort(A, nums); @@ -780,7 +780,7 @@ static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) static ssize_t NintherPivot(SortArray& A, ssize_t lo, ssize_t hi) { - if (hi - lo < 18) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 81) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment_size = (hi - lo) / 9; ssize_t g1 = SingleMedianOfThree(A, lo, lo + segment_size, (lo + segment_size * 2) + 1); ssize_t g2 = SingleMedianOfThree(A, lo + 3 * segment_size, lo + 4 * segment_size, (lo + 5 * segment_size) + 1); @@ -839,7 +839,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 10) + if (hi - lo < 25) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -849,7 +849,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN7: { - if (hi - lo < 14) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 49) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 7; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; PivotInsertionSort(A, samples); @@ -864,7 +864,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 14) + if (hi - lo < 49) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -885,7 +885,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 18) + if (hi - lo < 81) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -898,7 +898,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN9: { - if (hi - lo < 18) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 81) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 9; std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8 }; PivotInsertionSort(A, samples); @@ -913,7 +913,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 18) + if (hi - lo < 81) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -923,7 +923,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN11: { - if (hi - lo < 22) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + if (hi - lo < 121) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } ssize_t segment = (hi - lo) / 11; std::array samples = {lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6, lo + segment * 7, lo + segment * 8, lo + segment * 9, lo + segment * 10 }; PivotShellSort(A, samples); @@ -939,7 +939,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) hi = temp; } std::uniform_int_distribution dist(lo, hi - 1); - if (hi - lo < 22) + if (hi - lo < 121) { return SingleMedianOfThree(A, dist(gen1), dist(gen1), dist(gen1) + 1); } @@ -950,7 +950,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN15: { - if (hi - lo < 30) { return MedianOfFive(A, lo, hi); } + if (hi - lo < 75) { return MedianOfFive(A, lo, hi); } ssize_t segment = (hi - lo) / 3; ssize_t g1 = MedianOfFive(A, lo, lo + segment); ssize_t g2 = MedianOfFive(A, lo + segment, lo + segment * 2); @@ -959,7 +959,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_THREENINTHER: { - if (hi - lo < 54) { return NintherPivot(A, lo, hi); } + if (hi - lo < 243) { return NintherPivot(A, lo, hi); } ssize_t segment = (hi - lo) / 3; ssize_t g1 = NintherPivot(A, lo, lo + segment); ssize_t g2 = NintherPivot(A, lo + segment, lo + segment * 2); From 6e18602bf7d1226db8197e4f8568f536cfa70186 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 8 Nov 2024 02:50:13 +0800 Subject: [PATCH 273/289] Made gaps array static --- src/SortAlgo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index f97ed2fe7..1abdf1205 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -749,7 +749,7 @@ static void PivotInsertionSort(SortArray& A, std::array& arr) } } -std::array gaps = { 8, 3, 1 }; +static std::array gaps = { 8, 3, 1 }; template static void PivotShellSort(SortArray& A, std::array& arr) { From b9e70b5293dd97504c06ad3694c461926ba272de Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Fri, 8 Nov 2024 03:35:21 +0800 Subject: [PATCH 274/289] Added Median of Twenty-One This should be the last pivot rule I will ever implement. Assuming that I will implement Median of Medians properly, then I will add it too, but this is not going to be my main focus now. I suppose I will now aim towards adding more sorting algorithms. --- src/SortAlgo.cpp | 25 ++++++++++++++++++++----- src/SortAlgo.h | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 1abdf1205..00ca58377 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -778,6 +778,15 @@ static ssize_t MedianOfFive(SortArray& A, ssize_t lo, ssize_t hi) return nums[2]; } +static ssize_t MedianOfSeven(SortArray& A, ssize_t lo, ssize_t hi) +{ + if (hi - lo < 49) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } + ssize_t segment = (hi - lo) / 7; + std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; + PivotInsertionSort(A, samples); + return samples[3]; +} + static ssize_t NintherPivot(SortArray& A, ssize_t lo, ssize_t hi) { if (hi - lo < 81) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } @@ -849,11 +858,7 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) } case PIVOT_MEDIAN7: { - if (hi - lo < 49) { return SingleMedianOfThree(A, lo, (lo + hi) / 2, hi); } - ssize_t segment = (hi - lo) / 7; - std::array samples = { lo, lo + segment, lo + segment * 2, lo + segment * 3, lo + segment * 4, lo + segment * 5, lo + segment * 6 }; - PivotInsertionSort(A, samples); - return samples[3]; + return MedianOfSeven(A, lo, hi); } case PIVOT_MEDIAN7RANDOM: { @@ -957,6 +962,15 @@ ssize_t QuickSortSelectPivot(SortArray& A, ssize_t lo, ssize_t hi) ssize_t g3 = MedianOfFive(A, lo + segment * 2, hi); return SingleMedianOfThree(A, g1, g2, g3 + 1); } + case PIVOT_MEDIAN21: + { + if (hi - lo < 143) { return MedianOfSeven(A, lo, hi); } + ssize_t segment = (hi - lo) / 3; + ssize_t g1 = MedianOfSeven(A, lo, lo + segment); + ssize_t g2 = MedianOfSeven(A, lo + segment, lo + segment * 2); + ssize_t g3 = MedianOfSeven(A, lo + segment * 2, hi); + return SingleMedianOfThree(A, g1, g2, g3 + 1); + } case PIVOT_THREENINTHER: { if (hi - lo < 243) { return NintherPivot(A, lo, hi); } @@ -994,6 +1008,7 @@ wxArrayString QuickSortPivotText() sl.Add(_("Median of Eleven")); sl.Add(_("Random Median of Eleven")); sl.Add(_("Median of Fifteen")); + sl.Add(_("Median of Twenty-One")); sl.Add(_("Median of Three Ninther")); return sl; } diff --git a/src/SortAlgo.h b/src/SortAlgo.h index 632f58f05..dcc9bdd06 100644 --- a/src/SortAlgo.h +++ b/src/SortAlgo.h @@ -73,7 +73,7 @@ void BufferPartitionMergeSort(class SortArray& a); wxArrayString QuickSortPivotText(); -enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM, PIVOT_MEDIAN11, PIVOT_MEDIAN11RANDOM, PIVOT_MEDIAN15, PIVOT_THREENINTHER }; +enum QuickSortPivotType { PIVOT_FIRST, PIVOT_LAST, PIVOT_MID, PIVOT_RANDOM, PIVOT_MEDIAN3, PIVOT_MEDIAN3RANDOM, PIVOT_MEDIAN5, PIVOT_MEDIAN5RANDOM, PIVOT_MEDIAN7, PIVOT_MEDIAN7RANDOM, PIVOT_NINTHER, PIVOT_RANDOMNINTHER, PIVOT_MEDIAN9, PIVOT_MEDIAN9RANDOM, PIVOT_MEDIAN11, PIVOT_MEDIAN11RANDOM, PIVOT_MEDIAN15, PIVOT_MEDIAN21, PIVOT_THREENINTHER }; extern QuickSortPivotType g_quicksort_pivot; void QuickSortLR(class SortArray& a); From 209b1fce979a3e4e5b3bd986fce1efc8384be445 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Sat, 9 Nov 2024 21:36:08 +0800 Subject: [PATCH 275/289] Removed unnecessary filter-out --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index ff88b4425..bc65be036 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,7 +28,7 @@ sorting_test_SOURCES = \ SortTest.cpp \ $(COMMON) -AM_CXXFLAGS = -W -Wall $(filter-out -g, @WX_CXXFLAGS@) $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) +AM_CXXFLAGS = -W -Wall @WX_CXXFLAGS@ $(filter-out -Dmain=SDL_main, @SDL_CFLAGS@) LDADD = if GOT_RESCOMP From f6e93df687379259803832f50ef46a2b10599557 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 00:43:20 +0800 Subject: [PATCH 276/289] Removed typecasting fix Since watch() in this fork never expects a volatile variable anymore, and all Quick Sorts here use a separate watched std::atomic variable, the typecasting fix provided earlier is of no use now. --- src/SortAlgo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 00ca58377..ac0118764 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1042,7 +1042,6 @@ void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) i1.store(i); } - while (A[j] > pivot) { j--; @@ -1271,7 +1270,7 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t } A.unmark_all(); - return std::make_pair((ssize_t)i, j); + return std::make_pair(i, j); } void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) From dd9cf436d8b49ae50ee140a7b44429781c22d952 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 10:35:45 +0800 Subject: [PATCH 277/289] Fully integrated std::atomic for Selection and Double Selection Sort --- src/SortAlgo.cpp | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index ac0118764..a08a12e0d 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -206,36 +206,32 @@ void DoubleSelectionSort(SortArray& A) { size_t left = 0; size_t right = A.size() - 1, n = right; - ssize_t max_idx = 0; - ssize_t low_idx = 0; std::atomic max_i, low_i; - max_i.store(max_idx); - low_i.store(low_idx); + max_i.store(0); + low_i.store(0); A.watch(&max_i, 4); A.watch(&low_i, 5); while (left < right) { - max_idx = right; - low_idx = left; + max_i.store(right); + low_i.store(left); for (size_t i = left; i <= right; ++i) { - if (A[i] < A[low_idx]) + if (A[i] < A[low_i.load()]) { - A.mark_swap(i, low_idx); - low_idx = i; + A.mark_swap(i, low_i.load()); low_i.store(i); } - else if (A[i] > A[max_idx]) + else if (A[i] > A[max_i.load()]) { - A.mark_swap(i, max_idx); - max_idx = i; + A.mark_swap(i, max_i.load()); max_i.store(i); } } - A.swap(left, low_idx); + A.swap(left, low_i.load()); ssize_t l = left; // This removes comparison warning - if (max_idx == l) { max_idx = low_idx; } - A.swap(right, max_idx); + if (max_i.load() == l) { max_i.store(low_i.load()); } + A.swap(right, max_i.load()); if (left > 0) { A.unmark(left - 1); } if (right < n) { A.unmark(right + 1); } A.mark(left); @@ -247,26 +243,23 @@ void DoubleSelectionSort(SortArray& A) void SelectionSort(SortArray& A) { - ssize_t jMin = 0; std::atomic kMin; - kMin.store(jMin); + kMin.store(0); A.watch(&kMin, 3); for (size_t i = 0; i < A.size()-1; ++i) { - jMin = i; - kMin.store(jMin); + kMin.store(i); for (size_t j = i+1; j < A.size(); ++j) { - if (A[j] < A[jMin]) { - A.mark_swap(j, jMin); - jMin = j; - kMin.store(jMin); + if (A[j] < A[kMin.load()]) { + A.mark_swap(j, kMin.load()); + kMin.store(j); } } - A.swap(i, jMin); + A.swap(i, kMin.load()); // mark the last good element if (i > 0) A.unmark(i-1); From da4d0854c74f1bf493bf6c2d9139ba2f959e360e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 10:41:36 +0800 Subject: [PATCH 278/289] Fully integrated std::atomic for Cycle Sort --- src/SortAlgo.cpp | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index a08a12e0d..9b09e3ea1 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -3356,51 +3356,40 @@ void SlowSort(SortArray& A) void CycleSort(SortArray& vec_arr, ssize_t n) { - std::atomic cStart, cRank; - ssize_t cycleStart = 0; - cStart.store(cycleStart); - vec_arr.watch(&cStart, 16); + std::atomic cycleStart, rank; + cycleStart.store(0); + vec_arr.watch(&cycleStart, 16); - ssize_t rank = 0; - cRank.store(rank); - vec_arr.watch(&cRank, 5); + rank.store(0); + vec_arr.watch(&rank, 5); // Loop through the array to find cycles to rotate. - for (cycleStart = 0; cycleStart < n - 1; ++cycleStart) + for (; cycleStart.load() < n - 1; ++cycleStart) { - value_type& item = vec_arr.get_mutable(cycleStart); - cStart.store(cycleStart); + value_type& item = vec_arr.get_mutable(cycleStart.load()); do { // Find where to put the item. - rank = cycleStart; - for (ssize_t i = cycleStart + 1; i < n; ++i) + rank.store(cycleStart.load()); + for (ssize_t i = cycleStart.load() + 1; i < n; ++i) { - if (vec_arr[i] < item) - { - rank++; - cRank.store(rank); - } + if (vec_arr[i] < item) { rank++; } } // If the item is already there, this is a 1-cycle. - if (rank == cycleStart) { - vec_arr.mark(rank, 2); + if (rank.load() == cycleStart.load()) { + vec_arr.mark(rank.load(), 2); break; } // Otherwise, put the item after any duplicates. - while (item == vec_arr[rank]) - { - rank++; - cRank.store(rank); - } + while (item == vec_arr[rank.load()]) { rank++; } // Put item into right place and colorize - counted_swap(vec_arr.get_mutable(rank), item); - vec_arr.mark(rank, 2); + counted_swap(vec_arr.get_mutable(rank.load()), item); + vec_arr.mark(rank.load(), 2); // Continue for rest of the cycle. - } while (rank != cycleStart); + } while (rank.load() != cycleStart.load()); } vec_arr.unwatch_all(); From 485bc87af25d48598db437aba8a2519b8a557c7e Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 11:05:06 +0800 Subject: [PATCH 279/289] Fully integrated std::atomic usage for all Quick Sort variants --- src/SortAlgo.cpp | 140 ++++++++++++++++++----------------------------- 1 file changed, 53 insertions(+), 87 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index 9b09e3ea1..c0a7d65f1 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -206,9 +206,7 @@ void DoubleSelectionSort(SortArray& A) { size_t left = 0; size_t right = A.size() - 1, n = right; - std::atomic max_i, low_i; - max_i.store(0); - low_i.store(0); + std::atomic max_i{ 0 }, low_i{ 0 }; A.watch(&max_i, 4); A.watch(&low_i, 5); while (left < right) @@ -243,8 +241,7 @@ void DoubleSelectionSort(SortArray& A) void SelectionSort(SortArray& A) { - std::atomic kMin; - kMin.store(0); + std::atomic kMin{ 0 }; A.watch(&kMin, 3); for (size_t i = 0; i < A.size()-1; ++i) @@ -1084,25 +1081,22 @@ size_t PartitionLL(SortArray& A, size_t lo, size_t hi) A.swap(p, hi - 1); A.mark(hi - 1); - ssize_t i = lo; - std::atomic i1; - i1.store(i); - A.watch(&i1, 3); + std::atomic i{static_cast(lo)}; + A.watch(&i, 3); for (size_t j = lo; j < hi - 1; ++j) { if (A[j] <= pivot) { - A.swap(i, j); + A.swap(i.load(), j); ++i; - i1.store(i); } } - A.swap(i, hi - 1); + A.swap(i.load(), hi - 1); A.unmark(hi - 1); A.unwatch_all(); - return i; + return i.load(); } void QuickSortLL(SortArray& A, size_t lo, size_t hi) @@ -1140,70 +1134,60 @@ void QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) const value_type& pivot = A[hi]; // schema: |p === |i <<< | ??? |j >>> |q === |piv - ssize_t i = lo, j = hi - 1; + std::atomic i{ lo }, j{hi - 1}; ssize_t p = lo, q = hi - 1; - std::atomic i1, j1; - i1.store(i); - j1.store(j); - A.watch(&i1, 3); - A.watch(&j1, 3); + + A.watch(&i, 3); + A.watch(&j, 3); for (;;) { // partition on left - while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) + while (i.load() <= j.load() && (cmp = A[i.load()].cmp(pivot)) <= 0) { if (cmp == 0) { A.mark(p, 4); - A.swap(i, p++); + A.swap(i.load(), p++); } ++i; - i1.store(i); } // partition on right - while (i <= j && (cmp = A[j].cmp(pivot)) >= 0) + while (i.load() <= j.load() && (cmp = A[j.load()].cmp(pivot)) >= 0) { if (cmp == 0) { A.mark(q, 4); - A.swap(j, q--); + A.swap(j.load(), q--); } --j; - j1.store(j); } - if (i > j) break; + if (i.load() > j.load()) break; // swap item between < > regions A.swap(i++, j--); - i1.store(i); - j1.store(j); } // swap pivot to right place - A.swap(i, hi); - A.mark_swap(i, hi); + A.swap(i.load(), hi); + A.mark_swap(i.load(), hi); - ssize_t num_less = i - p; - ssize_t num_greater = q - j; + ssize_t num_less = i.load() - p; + ssize_t num_greater = q - j.load(); // swap equal ranges into center, but avoid swapping equal elements - j = i - 1; i = i + 1; - i1.store(i); - j1.store(j); + j.store(i.load() - 1); i.store(i.load() + 1); ssize_t pe = lo + std::min(p - lo, num_less); for (ssize_t k = lo; k < pe; k++, j--) { - j1.store(j); - A.swap(k, j); - A.mark_swap(k, j); + A.swap(k, j.load()); + A.mark_swap(k, j.load()); } ssize_t qe = hi - 1 - std::min(hi - 1 - q, num_greater - 1); // one already greater at end for (ssize_t k = hi - 1; k > qe; k--, i++) { - i1.store(i); - A.swap(i, k); - A.mark_swap(i, k); + A.swap(i.load(), k); + A.mark_swap(i.load(), k); } A.unwatch_all(); @@ -1232,10 +1216,10 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t A.swap(p, hi - 1); A.mark(hi - 1); - ssize_t i = lo, k = hi - 1; - std::atomic i1; - i1.store(i); - A.watch(&i1, 3); + std::atomic i{lo}; + ssize_t k = hi - 1; + + A.watch(&i, 3); for (ssize_t j = lo; j < k; ++j) { @@ -1247,7 +1231,6 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t } else if (cmp < 0) { A.swap(i++, j); - i1.store(i); } } @@ -1255,15 +1238,15 @@ std::pair PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t // in the first step of the following swap loop. A.unwatch_all(); - ssize_t j = i + (hi - k); + ssize_t j = i.load() + (hi - k); for (ssize_t s = 0; s < hi - k; ++s) { - A.swap(i + s, hi - 1 - s); - A.mark_swap(i + s, hi - 1 - s); + A.swap(i.load() + s, hi - 1 - s); + A.mark_swap(i.load() + s, hi - 1 - s); } A.unmark_all(); - return std::make_pair(i, j); + return std::make_pair(i.load(), j); } void QuickSortTernaryLL(SortArray& A, size_t lo, size_t hi) @@ -1301,56 +1284,41 @@ void dualPivotYaroslavskiy(class SortArray& a, int left, int right) a.mark(left); a.mark(right); - ssize_t l = left + 1; - ssize_t g = right - 1; - ssize_t k = l; - std::atomic l1, g1, k1; - l1.store(l); - g1.store(g); - k1.store(k); - - a.watch(&l1, 3); - a.watch(&g1, 3); - a.watch(&k1, 3); + std::atomic l{ left + 1 }, g{ right - 1 }, k{ l.load() }; + + a.watch(&l, 3); + a.watch(&g, 3); + a.watch(&k, 3); - while (k <= g) + while (k.load() <= g) { - if (a[k] < p) { - a.swap(k, l); + if (a[k.load()] < p) { + a.swap(k.load(), l.load()); ++l; - l1.store(l); } - else if (a[k] >= q) { - while (a[g] > q && k < g) - { - --g; - g1.store(g); - } - a.swap(k, g); + else if (a[k.load()] >= q) { + while (a[g.load()] > q && k.load() < g) { --g; } + a.swap(k.load(), g.load()); --g; - g1.store(g); - if (a[k] < p) { - a.swap(k, l); + if (a[k.load()] < p) { + a.swap(k.load(), l.load()); ++l; - l1.store(l); } } ++k; - k1.store(k); } --l; ++g; - l1.store(l); - g1.store(g); - a.swap(left, l); - a.swap(right, g); + + a.swap(left, l.load()); + a.swap(right, g.load()); a.unmark_all(); a.unwatch_all(); - dualPivotYaroslavskiy(a, left, l - 1); - dualPivotYaroslavskiy(a, l + 1, g - 1); - dualPivotYaroslavskiy(a, g + 1, right); + dualPivotYaroslavskiy(a, left, l.load() - 1); + dualPivotYaroslavskiy(a, l.load() + 1, g.load() - 1); + dualPivotYaroslavskiy(a, g.load() + 1, right); } } @@ -3356,11 +3324,9 @@ void SlowSort(SortArray& A) void CycleSort(SortArray& vec_arr, ssize_t n) { - std::atomic cycleStart, rank; - cycleStart.store(0); + std::atomic cycleStart{ 0 }, rank{ 0 }; vec_arr.watch(&cycleStart, 16); - rank.store(0); vec_arr.watch(&rank, 5); // Loop through the array to find cycles to rotate. From 3525e39bac797227058cf53316addfdde66c2f85 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 11:23:23 +0800 Subject: [PATCH 280/289] Fully integrated std::atomic usage for Quick Sort LR I almost forgot to convert this sorting algorithm, my bad. --- src/SortAlgo.cpp | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/SortAlgo.cpp b/src/SortAlgo.cpp index c0a7d65f1..ed5f6588b 100644 --- a/src/SortAlgo.cpp +++ b/src/SortAlgo.cpp @@ -1011,55 +1011,39 @@ wxArrayString QuickSortPivotText() void QuickSortLR(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and watch - ssize_t p = QuickSortSelectPivot(A, lo, hi + 1); - std::atomic p1, i1, j1; + std::atomic p{ QuickSortSelectPivot(A, lo, hi + 1) }; + value_type pivot = A[p.load()]; + A.watch(&p, 2); - value_type pivot = A[p]; - p1.store(p); - A.watch(&p1, 2); - - ssize_t i = lo, j = hi; - i1.store(i); - j1.store(j); - A.watch(&i1, 3); - A.watch(&j1, 3); + std::atomic i{ lo }, j{ hi }; + A.watch(&i, 3); + A.watch(&j, 3); - while (i <= j) + while (i.load() <= j.load()) { - while (A[i] < pivot) - { - i++; - i1.store(i); - } + while (A[i.load()] < pivot) { i++; } - while (A[j] > pivot) - { - j--; - j1.store(j); - } + while (A[j.load()] > pivot) { j--; } - if (i <= j) + if (i.load() <= j.load()) { - A.swap(i, j); + A.swap(i.load(), j.load()); // follow pivot if it is swapped - if (p == i) p = j; - else if (p == j) p = i; - p1.store(p); + if (p.load() == i.load()) p.store(j.load()); + else if (p.load() == j.load()) p.store(i.load()); i++, j--; - i1.store(i); - j1.store(j); } } A.unwatch_all(); if (lo < j) - QuickSortLR(A, lo, j); + QuickSortLR(A, lo, j.load()); if (i < hi) - QuickSortLR(A, i, hi); + QuickSortLR(A, i.load(), hi); } void QuickSortLR(SortArray& A) From 2c9038a3d7f166f557b82eb69d17a06f1ed88756 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 13:15:43 +0800 Subject: [PATCH 281/289] Fixed secs/delay comparison This should allow for more predictable behavior. --- src/WSortView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index e08233886..c9de27c30 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -98,7 +98,7 @@ void WSortView::DoDelay(double delay) double secs = 0; #if __WXGTK__ // wxMicroSleep(delay * 1000.0); - if (delay < 1) + if (delay < 1.0) { double microDelay = delay * 1000.0; while (secs <= microDelay) @@ -127,7 +127,7 @@ void WSortView::DoDelay(double delay) } #elif MSW_PERFORMANCECOUNTER // mswMicroSleep(delay * 1000.0); - if (delay < 1) + if (delay < 1.0) { double microDelay = delay * 1000.0; while (secs <= microDelay) From 0666a7fc6b76da5ff7dfa24f571322f44e84e7db Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 13:41:07 +0800 Subject: [PATCH 282/289] Removed millisecond loop interval in DoDelay() After some research, I am able to conclude that delay * 1000 isn't going to cause any overflow here in most cases, especially considering that a double can hold an even larger value than an int. But, in case microDelay somehow holds an infinite value, then the additional condition will ensure that microDelay will be set to the max value that a double can hold to ensure that proper comparison and functionality is still there. --- src/WMain.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/WMain.cpp b/src/WMain.cpp index db815a41e..81f831318 100644 --- a/src/WMain.cpp +++ b/src/WMain.cpp @@ -342,8 +342,10 @@ void WMain::SetDelay(size_t pos) #endif if (pos == 0) g_delay = 0.1; - if (g_delay >= 1) + if (g_delay > 10) labelDelayValue->SetLabel(wxString::Format(_("%.0f ms"), g_delay)); + else if (g_delay > 1) + labelDelayValue->SetLabel(wxString::Format(_("%.2f ms"), g_delay)); else labelDelayValue->SetLabel(wxString::Format(_("%.3f ms"), g_delay)); } From 1015f8132d31cfb7541bd8f5cd9da319c181a977 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 13:42:00 +0800 Subject: [PATCH 283/289] Removed millisecond loop interval in DoDelay() After some research, I am able to conclude that delay * 1000 isn't going to cause any overflow here in most cases, especially considering that a double can hold an even larger value than an int. But, in case microDelay somehow holds an infinite value, then the additional condition will ensure that microDelay will be set to the max value that a double can hold to ensure that proper comparison and functionality is still there. --- src/WSortView.cpp | 62 ++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index c9de27c30..56978e599 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -95,63 +95,31 @@ void WSortView::DoDelay(double delay) // else timeout, recheck m_stepwise and loop wxMilliSleep(1); } - double secs = 0; + double secs = 0.0, microDelay = delay * 1000.0; + if (microDelay == std::numeric_limits::infinity() || microDelay == -std::numeric_limits::infinity()) + { microDelay = std::numeric_limits::max(); } #if __WXGTK__ // wxMicroSleep(delay * 1000.0); - if (delay < 1.0) + while (secs <= microDelay) { - double microDelay = delay * 1000.0; - while (secs <= microDelay) - { - wxMicroSleep(1); - secs += 1.0; - if (wmain->m_thread_terminate) - { - wmain->m_thread->Exit(); - return; - } - } - } - else - { - while (secs <= delay) + wxMicroSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) { - wxMilliSleep(1); - secs += 1.0; - if (wmain->m_thread_terminate) - { - wmain->m_thread->Exit(); - return; - } + wmain->m_thread->Exit(); + return; } } #elif MSW_PERFORMANCECOUNTER // mswMicroSleep(delay * 1000.0); - if (delay < 1.0) + while (secs <= microDelay) { - double microDelay = delay * 1000.0; - while (secs <= microDelay) - { - mswMicroSleep(1); - secs += 1.0; - if (wmain->m_thread_terminate) - { - wmain->m_thread->Exit(); - return; - } - } - } - else - { - while (secs <= delay) + mswMicroSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) { - mswMicroSleep(1000); - secs += 1.0; - if (wmain->m_thread_terminate) - { - wmain->m_thread->Exit(); - return; - } + wmain->m_thread->Exit(); + return; } } #else From c050026a7709a823400dfc63ab362b3cbc0c2844 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 23:38:58 +0800 Subject: [PATCH 284/289] Hybrid millisecond/microsecond delay interval I am very much bothered with just the microsecond loop interval only. The reason why it's bothering me so much is that, say, someone allowed 60000 ms in the visualizer, 60000 * 1000 = 60000000, which means the microsecond loop would have to perform a total of 60 million evaluation and incrementation which isn't really good. A previous solution I had was to simply ignore the decimal part and use millisecond interval, so instead of 60 million, only 60000 checks would be performed, but this isn't very good as well since the visualizer fully interprets the decimal part of the ms value. This struggle finally ends today, finally! The DoDelay() method now has 2 loops, one for the whole number value, and the other one for the fractional value. If the delay for example is set to 1.89 ms, if only the microsecond loop is used, this would result in 1890 iterations in total, with this hybrid approach, only 891 iterations (1 for millisecond, .89 * 1000 = 890 for microsecond) are done which is a good improvement! This slash in iterations becomes more noticeable the larger the ms value is. For example, with 14.89 ms, the resulting iterations with microsecond loop only would be 14890 iterations, with this hybrid approach, it only becomes 904 iterations (.89 * 1000 = 890 + 14) only! Now I can finally rest easy. --- src/WSortView.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 56978e599..f56c19edd 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -74,6 +74,8 @@ void mswMicroSleep(int microseconds) #endif // MSW_PERFORMANCECOUNTER +static double returnFrac(double n) { return n - static_cast(n); } + void WSortView::DoDelay(double delay) { // must be called by the algorithm thread @@ -95,12 +97,24 @@ void WSortView::DoDelay(double delay) // else timeout, recheck m_stepwise and loop wxMilliSleep(1); } - double secs = 0.0, microDelay = delay * 1000.0; + double secs = 0.0, microDelay = returnFrac(delay) * 1000.0; + delay = std::trunc(delay); if (microDelay == std::numeric_limits::infinity() || microDelay == -std::numeric_limits::infinity()) { microDelay = std::numeric_limits::max(); } #if __WXGTK__ // wxMicroSleep(delay * 1000.0); - while (secs <= microDelay) + while (secs < delay) + { + wxMilliSleep(1); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + secs = 0; + while (secs < microDelay) { wxMicroSleep(1); secs += 1.0; @@ -112,6 +126,17 @@ void WSortView::DoDelay(double delay) } #elif MSW_PERFORMANCECOUNTER // mswMicroSleep(delay * 1000.0); + while (secs < delay) + { + mswMicroSleep(1000); + secs += 1.0; + if (wmain->m_thread_terminate) + { + wmain->m_thread->Exit(); + return; + } + } + secs = 0; while (secs <= microDelay) { mswMicroSleep(1); From 13552e48bd32f6f1f846e7aec6905ec94fac5aa6 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Mon, 11 Nov 2024 23:45:05 +0800 Subject: [PATCH 285/289] Minor correction on msw delay --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index f56c19edd..356f819ab 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -137,7 +137,7 @@ void WSortView::DoDelay(double delay) } } secs = 0; - while (secs <= microDelay) + while (secs < microDelay) { mswMicroSleep(1); secs += 1.0; From 9a43c9b0d6390c95eadf6c8d15eafd5bc55913d6 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 12 Nov 2024 01:09:43 +0800 Subject: [PATCH 286/289] Minor correction on DoDelay() method The wxMilliSleep() converts a decimal value such as 0.1 to just 0, so in the else block, since wxMilliSleep receives a truncated delay, it effectively does the same thing. --- src/WSortView.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 356f819ab..8569c203c 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -113,7 +113,7 @@ void WSortView::DoDelay(double delay) return; } } - secs = 0; + secs = 0.0; while (secs < microDelay) { wxMicroSleep(1); @@ -136,7 +136,7 @@ void WSortView::DoDelay(double delay) return; } } - secs = 0; + secs = 0.0; while (secs < microDelay) { mswMicroSleep(1); @@ -150,7 +150,7 @@ void WSortView::DoDelay(double delay) #else // wxMSW does not have a high resolution timer, maybe others do? // wxMilliSleep(delay); - while (secs <= delay) + while (secs < delay) { wxMilliSleep(1); secs += 1.0; From 1495309cf7e7f9f5104f84507008530712913b9b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 12 Nov 2024 01:21:12 +0800 Subject: [PATCH 287/289] Removed infinity check condition Since the fractional ms value will never go past 1.0, the check condition is not needed now, --- src/WSortView.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 8569c203c..c7c9acd6c 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -99,8 +99,6 @@ void WSortView::DoDelay(double delay) } double secs = 0.0, microDelay = returnFrac(delay) * 1000.0; delay = std::trunc(delay); - if (microDelay == std::numeric_limits::infinity() || microDelay == -std::numeric_limits::infinity()) - { microDelay = std::numeric_limits::max(); } #if __WXGTK__ // wxMicroSleep(delay * 1000.0); while (secs < delay) From 78e62985e68abd5e058209455c3b9747a1b4f59b Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 12 Nov 2024 08:10:28 +0800 Subject: [PATCH 288/289] Added 0 -> 1 ms condition on else block --- src/WSortView.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index c7c9acd6c..6f11341b5 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -148,6 +148,7 @@ void WSortView::DoDelay(double delay) #else // wxMSW does not have a high resolution timer, maybe others do? // wxMilliSleep(delay); + if (delay < 1.0) { delay = 1; } while (secs < delay) { wxMilliSleep(1); From 98ce7bb2c68fa0219ec6fa2a4cc330e9a6167336 Mon Sep 17 00:00:00 2001 From: Unbreakable-Syntax Date: Tue, 12 Nov 2024 08:14:28 +0800 Subject: [PATCH 289/289] Minor correction --- src/WSortView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WSortView.cpp b/src/WSortView.cpp index 6f11341b5..0a7277414 100644 --- a/src/WSortView.cpp +++ b/src/WSortView.cpp @@ -148,7 +148,7 @@ void WSortView::DoDelay(double delay) #else // wxMSW does not have a high resolution timer, maybe others do? // wxMilliSleep(delay); - if (delay < 1.0) { delay = 1; } + if (delay < 1.0) { delay = 1.0; } while (secs < delay) { wxMilliSleep(1);