From 6cf07fc33c5a246a651b19144b1d207e314539e0 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 21 Aug 2021 15:04:40 -0700 Subject: [PATCH 01/17] MemoryBenchmark: Generate baseline before adding 3-argument sorting functions --- examples/MemoryBenchmark/README.md | 60 +++++++++++++-------------- examples/MemoryBenchmark/samd.txt | 30 +++++++------- examples/MemoryBenchmark/teensy32.txt | 30 +++++++------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 5a24b63..75d4b10 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -117,26 +117,26 @@ ASCII table. +---------------------------------------------------------------------+ | Functionality | flash/ ram | delta | |----------------------------------------+--------------+-------------| -| Baseline | 10664/ 0 | 0/ 0 | +| Baseline | 10520/ 0 | 0/ 0 | |----------------------------------------+--------------+-------------| -| bubbleSort() | 10696/ 0 | 32/ 0 | -| insertionSort() | 10712/ 0 | 48/ 0 | -| selectionSort() | 10740/ 0 | 76/ 0 | +| bubbleSort() | 10568/ 0 | 48/ 0 | +| insertionSort() | 10568/ 0 | 48/ 0 | +| selectionSort() | 10584/ 0 | 64/ 0 | |----------------------------------------+--------------+-------------| -| shellSortClassic() | 10720/ 0 | 56/ 0 | -| shellSortKnuth() | 10736/ 0 | 72/ 0 | -| shellSortTokuda() | 10836/ 0 | 172/ 0 | +| shellSortClassic() | 10584/ 0 | 64/ 0 | +| shellSortKnuth() | 10576/ 0 | 56/ 0 | +| shellSortTokuda() | 10648/ 0 | 128/ 0 | |----------------------------------------+--------------+-------------| -| combSort13() | 10724/ 0 | 60/ 0 | -| combSort13m() | 10740/ 0 | 76/ 0 | -| combSort133() | 10716/ 0 | 52/ 0 | -| combSort133m() | 10740/ 0 | 76/ 0 | +| combSort13() | 10584/ 0 | 64/ 0 | +| combSort13m() | 10600/ 0 | 80/ 0 | +| combSort133() | 10576/ 0 | 56/ 0 | +| combSort133m() | 10592/ 0 | 72/ 0 | |----------------------------------------+--------------+-------------| -| quickSortMiddle() | 10764/ 0 | 100/ 0 | -| quickSortMedian() | 10796/ 0 | 132/ 0 | -| quickSortMedianSwapped() | 10808/ 0 | 144/ 0 | +| quickSortMiddle() | 10616/ 0 | 96/ 0 | +| quickSortMedian() | 10648/ 0 | 128/ 0 | +| quickSortMedianSwapped() | 10664/ 0 | 144/ 0 | |----------------------------------------+--------------+-------------| -| qsort() | 11448/ 0 | 784/ 0 | +| qsort() | 11320/ 0 | 800/ 0 | +---------------------------------------------------------------------+ ``` @@ -259,26 +259,26 @@ usage by objects. +---------------------------------------------------------------------+ | Functionality | flash/ ram | delta | |----------------------------------------+--------------+-------------| -| Baseline | 7788/ 3256 | 0/ 0 | +| Baseline | 7116/ 3256 | 0/ 0 | |----------------------------------------+--------------+-------------| -| bubbleSort() | 7816/ 3256 | 28/ 0 | -| insertionSort() | 7844/ 3256 | 56/ 0 | -| selectionSort() | 7852/ 3256 | 64/ 0 | +| bubbleSort() | 7144/ 3256 | 28/ 0 | +| insertionSort() | 7172/ 3256 | 56/ 0 | +| selectionSort() | 7180/ 3256 | 64/ 0 | |----------------------------------------+--------------+-------------| -| shellSortClassic() | 7868/ 3256 | 80/ 0 | -| shellSortKnuth() | 7880/ 3256 | 92/ 0 | -| shellSortTokuda() | 7976/ 3256 | 188/ 0 | +| shellSortClassic() | 7196/ 3256 | 80/ 0 | +| shellSortKnuth() | 7208/ 3256 | 92/ 0 | +| shellSortTokuda() | 7304/ 3256 | 188/ 0 | |----------------------------------------+--------------+-------------| -| combSort13() | 7864/ 3256 | 76/ 0 | -| combSort13m() | 7876/ 3256 | 88/ 0 | -| combSort133() | 7844/ 3256 | 56/ 0 | -| combSort133m() | 7860/ 3256 | 72/ 0 | +| combSort13() | 7192/ 3256 | 76/ 0 | +| combSort13m() | 7204/ 3256 | 88/ 0 | +| combSort133() | 7172/ 3256 | 56/ 0 | +| combSort133m() | 7188/ 3256 | 72/ 0 | |----------------------------------------+--------------+-------------| -| quickSortMiddle() | 7896/ 3256 | 108/ 0 | -| quickSortMedian() | 7932/ 3256 | 144/ 0 | -| quickSortMedianSwapped() | 7960/ 3256 | 172/ 0 | +| quickSortMiddle() | 7224/ 3256 | 108/ 0 | +| quickSortMedian() | 7260/ 3256 | 144/ 0 | +| quickSortMedianSwapped() | 7288/ 3256 | 172/ 0 | |----------------------------------------+--------------+-------------| -| qsort() | 9248/ 3256 | 1460/ 0 | +| qsort() | 8576/ 3256 | 1460/ 0 | +---------------------------------------------------------------------+ ``` diff --git a/examples/MemoryBenchmark/samd.txt b/examples/MemoryBenchmark/samd.txt index 3677945..277d53a 100644 --- a/examples/MemoryBenchmark/samd.txt +++ b/examples/MemoryBenchmark/samd.txt @@ -1,15 +1,15 @@ -0 10664 262144 -1 10696 262144 -2 10712 262144 -3 10740 262144 -4 10720 262144 -5 10736 262144 -6 10836 262144 -7 10724 262144 -8 10740 262144 -9 10716 262144 -10 10740 262144 -11 10764 262144 -12 10796 262144 -13 10808 262144 -14 11448 262144 +0 10520 262144 +1 10568 262144 +2 10568 262144 +3 10584 262144 +4 10584 262144 +5 10576 262144 +6 10648 262144 +7 10584 262144 +8 10600 262144 +9 10576 262144 +10 10592 262144 +11 10616 262144 +12 10648 262144 +13 10664 262144 +14 11320 262144 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 3141051..54fba26 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -1,15 +1,15 @@ -0 7788 262144 3256 65536 -1 7816 262144 3256 65536 -2 7844 262144 3256 65536 -3 7852 262144 3256 65536 -4 7868 262144 3256 65536 -5 7880 262144 3256 65536 -6 7976 262144 3256 65536 -7 7864 262144 3256 65536 -8 7876 262144 3256 65536 -9 7844 262144 3256 65536 -10 7860 262144 3256 65536 -11 7896 262144 3256 65536 -12 7932 262144 3256 65536 -13 7960 262144 3256 65536 -14 9248 262144 3256 65536 +0 7116 262144 3256 65536 +1 7144 262144 3256 65536 +2 7172 262144 3256 65536 +3 7180 262144 3256 65536 +4 7196 262144 3256 65536 +5 7208 262144 3256 65536 +6 7304 262144 3256 65536 +7 7192 262144 3256 65536 +8 7204 262144 3256 65536 +9 7172 262144 3256 65536 +10 7188 262144 3256 65536 +11 7224 262144 3256 65536 +12 7260 262144 3256 65536 +13 7288 262144 3256 65536 +14 8576 262144 3256 65536 From 8abbd2b08da8b5470220af4c62aefabba8b9a632 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 21 Aug 2021 14:12:14 -0700 Subject: [PATCH 02/17] src: Add 3-argument versions of all sort functions that accept a comparison predicate (function or lambda expression) --- examples/HelloSort/HelloSort.ino | 45 ++++- src/ace_sorting/bubbleSort.h | 31 +++- src/ace_sorting/combSort.h | 281 ++++++++++++++++++++++++------ src/ace_sorting/insertionSort.h | 42 ++++- src/ace_sorting/quickSort.h | 230 ++++++++++++++++++++---- src/ace_sorting/selectionSort.h | 50 ++++++ src/ace_sorting/shellSort.h | 194 +++++++++++++++++++-- tests/SortingTest/SortingTest.ino | 120 +++++++++++++ 8 files changed, 868 insertions(+), 125 deletions(-) diff --git a/examples/HelloSort/HelloSort.ino b/examples/HelloSort/HelloSort.ino index da54e6e..48faf93 100644 --- a/examples/HelloSort/HelloSort.ino +++ b/examples/HelloSort/HelloSort.ino @@ -1,9 +1,11 @@ /* - * Quick demo of one of the sorting functions: create an array of integers with - * random numbers, and sort the array. Print out the unsorted and sorted arrays. - * Other sorting functions follow the same pattern. The compiler is able to - * infer the type of the data, so you don't normally need to specify the - * template type to the shellSortKnuth() function. + * Quick demo of one of the sorting functions, in this example, + * shellSortKnuth(). All the other sorting algorithms have the exact same + * function signature. First, create an array of integers with random numbers. + * Then sort the array in different ways, including reverse sorting. Print out + * the unsorted and sorted arrays. The compiler is able to infer the type of the + * data, so you don't normally need to specify the template type to the + * shellSortKnuth() function. */ #include @@ -18,6 +20,7 @@ using ace_sorting::shellSortKnuth; const uint16_t ARRAY_SIZE = 50; int array[ARRAY_SIZE]; +// Print given array. void printArray(int* array, uint16_t arraySize) { for (uint16_t i = 0; i < arraySize; i++) { SERIAL_PORT_MONITOR.print(array[i]); @@ -26,12 +29,17 @@ void printArray(int* array, uint16_t arraySize) { SERIAL_PORT_MONITOR.println(); } +// Fill array with random numbers. void fillArray(int* array, uint16_t arraySize) { for (uint16_t i = 0; i < arraySize; i++) { array[i] = random(256); } } +bool lessThan(int a, int b) { + return a < b; +} + //----------------------------------------------------------------------------- void setup() { @@ -49,15 +57,34 @@ void setup() { randomSeed(analogRead(A0)); #endif + SERIAL_PORT_MONITOR.print("Unsorted: "); fillArray(array, ARRAY_SIZE); - SERIAL_PORT_MONITOR.println("Unsorted:"); printArray(array, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); - // The compiler automatically generates the correct version of - // shellSortKnuth() based on the type of `array`. + // Use default ascending sort order. + SERIAL_PORT_MONITOR.print("Sorted using implicit ascending: "); shellSortKnuth(array, ARRAY_SIZE); - SERIAL_PORT_MONITOR.println("Sorted:"); printArray(array, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); + + // Use function pointer. + SERIAL_PORT_MONITOR.print("Sorted using function pointer: "); + shellSortKnuth(array, ARRAY_SIZE, lessThan); + printArray(array, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); + + // Use lambda expression + SERIAL_PORT_MONITOR.print("Sorted using lambda expression: "); + shellSortKnuth(array, ARRAY_SIZE, [](int a, int b) { return a < b; }); + printArray(array, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); + + // Reverse sort using lambda expression + SERIAL_PORT_MONITOR.print("Reverse sorted using lambda expression: "); + shellSortKnuth(array, ARRAY_SIZE, [](int a, int b) { return a > b; }); + printArray(array, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); #if defined(EPOXY_DUINO) exit(0); diff --git a/src/ace_sorting/bubbleSort.h b/src/ace_sorting/bubbleSort.h index e0e8faf..5caf41a 100644 --- a/src/ace_sorting/bubbleSort.h +++ b/src/ace_sorting/bubbleSort.h @@ -41,13 +41,42 @@ namespace ace_sorting { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void bubbleSort(T data[], uint16_t n) { bool swapped; do { swapped = false; for (uint16_t i = 1; i < n; i++) { - if (data[i - 1] > data[i]) { + if (data[i] < data[i - 1]) { + swap(data[i - 1], data[i]); + swapped = true; + } + } + } while (swapped); +} +#else +template +void bubbleSort(T data[], uint16_t n) { + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + bubbleSort(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument bubbleSort() with the addition of a `lessThan` + * lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void bubbleSort(T data[], uint16_t n, F&& lessThan) { + bool swapped; + do { + swapped = false; + for (uint16_t i = 1; i < n; i++) { + if (lessThan(data[i], data[i - 1])) { swap(data[i - 1], data[i]); swapped = true; } diff --git a/src/ace_sorting/combSort.h b/src/ace_sorting/combSort.h index ac3c28a..85c883b 100644 --- a/src/ace_sorting/combSort.h +++ b/src/ace_sorting/combSort.h @@ -46,27 +46,67 @@ namespace ace_sorting { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void combSort13(T data[], uint16_t n) { - bool swapped = true; + bool swapped = true; - uint16_t gap = n; - while (swapped || gap > 1) { - gap = gap * 10 / 13; - if (gap == 0) gap = 1; - swapped = false; + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 10 / 13; + if (gap == 0) gap = 1; + swapped = false; - uint16_t i; + uint16_t i; uint16_t j; - for (i = 0, j = gap; j < n; i++, j++) { - if (data[i] > data[j]) { + for (i = 0, j = gap; j < n; i++, j++) { + if (data[j] < data[i]) { swap(data[i], data[j]); - swapped = true; - } - } - } + swapped = true; + } + } + } +} +#else +template +void combSort13(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + combSort13(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument combSort13() with the addition of a `lessThan` lambda + * expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void combSort13(T data[], uint16_t n, F&& lessThan) { + bool swapped = true; + + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 10 / 13; + if (gap == 0) gap = 1; + swapped = false; + + uint16_t i; + uint16_t j; + for (i = 0, j = gap; j < n; i++, j++) { + if (lessThan(data[j], data[i])) { + swap(data[i], data[j]); + swapped = true; + } + } + } } +//----------------------------------------------------------------------------- + /** * Same as combSort13() with the modification that if the gap is 9 or 10, it is * set to 11, so that the gap sequence becomes (11, 8, 6, 4, 3, 2, 1). For @@ -79,30 +119,74 @@ void combSort13(T data[], uint16_t n) { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void combSort13m(T data[], uint16_t n) { - bool swapped = true; + bool swapped = true; - uint16_t gap = n; - while (swapped || gap > 1) { - gap = gap * 10 / 13; + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 10 / 13; if (gap == 9 || gap == 10) { gap = 11; } else if (gap == 0) { gap = 1; } - swapped = false; + swapped = false; - uint16_t i; + uint16_t i; uint16_t j; - for (i = 0, j = gap; j < n; i++, j++) { - if (data[i] > data[j]) { + for (i = 0, j = gap; j < n; i++, j++) { + if (data[j] < data[i]) { swap(data[i], data[j]); - swapped = true; - } - } - } + swapped = true; + } + } + } } +#else +template +void combSort13m(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + combSort13m(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument combSort13m() with the addition of a `lessThan` lambda + * expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void combSort13m(T data[], uint16_t n, F&& lessThan) { + bool swapped = true; + + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 10 / 13; + if (gap == 9 || gap == 10) { + gap = 11; + } else if (gap == 0) { + gap = 1; + } + swapped = false; + + uint16_t i; + uint16_t j; + for (i = 0, j = gap; j < n; i++, j++) { + if (lessThan(data[j], data[i])) { + swap(data[i], data[j]); + swapped = true; + } + } + } +} + +//----------------------------------------------------------------------------- /** * Comb sort using a gap factor of 4/3=1.33 (successive gap is multiplied by 3 @@ -111,41 +195,82 @@ void combSort13m(T data[], uint16_t n) { * 21845. * * This gap ratio seemed appealing because the division by 4 will be optimized - * by the compiler into a left shift by 2 bits, so this algorithm does not + * by the compiler into a right shift of 2 bits, so this algorithm does not * perform any integer division. Experimentation on 8-bit processors without - * hardware dvision this algorithm is slightly faster than combSort13() on - * average. + * hardware dvision shows that this algorithm is slightly faster than + * combSort13() on average. * - * On 32-bit or 64-bit processors with hardware division, experimentation shows - * that this algorithm is actually slightly slower on average than combSort13(). - * And it seems to have a slightly higher variance, with some input data causing - * large spikes in runtime compared to the average. + * On 32-bit or 64-bit processors with hardware division, on larger input + * `data`, experimentation shows that this algorithm is actually slightly slower + * on average than combSort13(). And it seems to have a slightly higher + * variance, with some input data causing large spikes in runtime compared to + * the average. * * Average complexity: O(n^2 / 2^p). * See https://en.wikipedia.org/wiki/Comb_sort * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void combSort133(T data[], uint16_t n) { - bool swapped = true; + bool swapped = true; - uint16_t gap = n; - while (swapped || gap > 1) { - gap = gap * 3 / 4; - if (gap == 0) gap = 1; - swapped = false; + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 3 / 4; + if (gap == 0) gap = 1; + swapped = false; - uint16_t i; + uint16_t i; uint16_t j; - for (i = 0, j = gap; j < n; i++, j++) { - if (data[i] > data[j]) { + for (i = 0, j = gap; j < n; i++, j++) { + if (data[j] < data[i]) { swap(data[i], data[j]); - swapped = true; - } - } - } + swapped = true; + } + } + } } +#else +template +void combSort133(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + combSort133(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument combSort133() with the addition of a `lessThan` lambda + * expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void combSort133(T data[], uint16_t n, F&& lessThan) { + bool swapped = true; + + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 3 / 4; + if (gap == 0) gap = 1; + swapped = false; + + uint16_t i; + uint16_t j; + for (i = 0, j = gap; j < n; i++, j++) { + if (lessThan(data[j], data[i])) { + swap(data[i], data[j]); + swapped = true; + } + } + } +} + +//----------------------------------------------------------------------------- /** * Same as combSort133() but modified so that a gap of 9 or 10 becomes gap=11 so @@ -158,29 +283,71 @@ void combSort133(T data[], uint16_t n) { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) +template +void combSort133m(T data[], uint16_t n) { + bool swapped = true; + + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 3 / 4; + if (gap == 9 || gap == 10) { + gap = 11; + } else if (gap == 0) { + gap = 1; + } + swapped = false; + + uint16_t i; + uint16_t j; + for (i = 0, j = gap; j < n; i++, j++) { + if (data[j] < data[i]) { + swap(data[i], data[j]); + swapped = true; + } + } + } +} +#else template void combSort133m(T data[], uint16_t n) { - bool swapped = true; + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + combSort133m(data, n, lessThan); +} +#endif - uint16_t gap = n; - while (swapped || gap > 1) { - gap = gap * 3 / 4; +/** + * Same as the 2-argument combSort133m() with the addition of a `lessThan` + * lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void combSort133m(T data[], uint16_t n, F&& lessThan) { + bool swapped = true; + + uint16_t gap = n; + while (swapped || gap > 1) { + gap = gap * 3 / 4; if (gap == 9 || gap == 10) { gap = 11; } else if (gap == 0) { gap = 1; } - swapped = false; + swapped = false; - uint16_t i; + uint16_t i; uint16_t j; - for (i = 0, j = gap; j < n; i++, j++) { - if (data[i] > data[j]) { + for (i = 0, j = gap; j < n; i++, j++) { + if (lessThan(data[j], data[i])) { swap(data[i], data[j]); - swapped = true; - } - } - } + swapped = true; + } + } + } } } diff --git a/src/ace_sorting/insertionSort.h b/src/ace_sorting/insertionSort.h index 03cd9f7..944be48 100644 --- a/src/ace_sorting/insertionSort.h +++ b/src/ace_sorting/insertionSort.h @@ -26,21 +26,22 @@ SOFTWARE. * @file insertionSort.h * * Insertion sort. + * See https://en.wikipedia.org/wiki/Insertion_sort */ #ifndef ACE_SORTING_INSERTION_SORT_H #define ACE_SORTING_INSERTION_SORT_H -#include "swap.h" - namespace ace_sorting { /** * Insertion sort. * Average complexity: O(n^2) + * See https://en.wikipedia.org/wiki/Insertion_sort * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void insertionSort(T data[], uint16_t n) { for (uint16_t i = 1; i < n; i++) { @@ -60,6 +61,43 @@ void insertionSort(T data[], uint16_t n) { data[j] = temp; } } +#else +template +void insertionSort(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + insertionSort(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument insertionSort() with the addition of a `lessThan` + * lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void insertionSort(T data[], uint16_t n, F&& lessThan) { + for (uint16_t i = 1; i < n; i++) { + T temp = data[i]; + + // Shift one slot to the right. + uint16_t j; + for (j = i; j > 0; j--) { + // The following is equivalent to: (data[j - 1] <= temp) + if (! lessThan(temp, data[j - 1])) break; + data[j] = data[j - 1]; + } + + // This can assign 'temp' back into the original slot if no shifting was + // done. That's ok because T is assumed to be relatively cheap to copy, and + // checking for (i != j) is more expensive than just doing the extra + // assignment. + data[j] = temp; + } +} } diff --git a/src/ace_sorting/quickSort.h b/src/ace_sorting/quickSort.h index 6d30e9b..6993f49 100644 --- a/src/ace_sorting/quickSort.h +++ b/src/ace_sorting/quickSort.h @@ -26,6 +26,7 @@ SOFTWARE. * @file quickSort.h * * Quick sort algorithms. + * See https://en.wikipedia.org/wiki/Quicksort */ #ifndef ACE_SORTING_QUICK_SORT_H @@ -44,29 +45,72 @@ namespace ace_sorting { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void quickSortMiddle(T data[], uint16_t n) { if (n <= 1) return; - + T pivot = data[n / 2]; T* left = data; T* right = data + n - 1; - + while (left <= right) { - if (*left < pivot) { + if (*left < pivot) { left++; - } else if (*right > pivot) { + } else if (pivot < *right) { right--; - } else { + } else { swap(*left, *right); - left++; - right--; - } + left++; + right--; + } } - quickSortMiddle(data, right - data + 1); - quickSortMiddle(left, data + n - left); + quickSortMiddle(data, right - data + 1); + quickSortMiddle(left, data + n - left); +} +#else +template +void quickSortMiddle(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + quickSortMiddle(data, n, lessThan); } +#endif + +/** + * Same as the 2-argument quickSortMiddle() with the addition of a `lessThan` + * lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void quickSortMiddle(T data[], uint16_t n, F&& lessThan) { + if (n <= 1) return; + + T pivot = data[n / 2]; + T* left = data; + T* right = data + n - 1; + + while (left <= right) { + if (lessThan(*left, pivot)) { + left++; + } else if (lessThan(pivot, *right)) { + right--; + } else { + swap(*left, *right); + left++; + right--; + } + } + + quickSortMiddle(data, right - data + 1, lessThan); + quickSortMiddle(left, data + n - left, lessThan); +} + +//----------------------------------------------------------------------------- /** * Quick sort using Sedgewick's recommendation of using the median of low, @@ -77,67 +121,179 @@ void quickSortMiddle(T data[], uint16_t n) { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void quickSortMedian(T data[], uint16_t n) { if (n <= 1) return; - + // Select the median of data[low], data[mid], and data[high] as the estimate // of the ideal pivot. Don't swap (low, mid) or (mid, high) (compare that // quickSortMedianSwapped()) to save flash memory. They will get swapped in // the partitioning while-loop below. uint16_t mid = n / 2; T pivot = data[mid]; - if (data[0] > data[n - 1]) { + if (data[n - 1] < data[0]) { swap(data[0], data[n - 1]); } - if (data[0] > pivot) { + if (pivot < data[0]) { pivot = data[0]; - } else if (pivot > data[n - 1]) { + } else if (data[n - 1] < pivot) { pivot = data[n - 1]; } T* left = data; T* right = data + n - 1; - + while (left <= right) { - if (*left < pivot) { + if (*left < pivot) { left++; - } else if (*right > pivot) { + } else if (pivot < *right) { right--; - } else { + } else { swap(*left, *right); - left++; - right--; - } + left++; + right--; + } } - quickSortMedian(data, right - data + 1); - quickSortMedian(left, data + n - left); + quickSortMedian(data, right - data + 1); + quickSortMedian(left, data + n - left); +} +#else +template +void quickSortMedian(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + quickSortMedian(data, n, lessThan); } +#endif + +/** + * Same as the 2-argument quickSortMedian() with the addition of a `lessThan` + * lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void quickSortMedian(T data[], uint16_t n, F&& lessThan) { + if (n <= 1) return; + + // Select the median of data[low], data[mid], and data[high] as the estimate + // of the ideal pivot. Don't swap (low, mid) or (mid, high) (compare that + // quickSortMedianSwapped()) to save flash memory. They will get swapped in + // the partitioning while-loop below. + uint16_t mid = n / 2; + T pivot = data[mid]; + if (lessThan(data[n - 1], data[0])) { + swap(data[0], data[n - 1]); + } + if (lessThan(pivot, data[0])) { + pivot = data[0]; + } else if (lessThan(data[n - 1], pivot)) { + pivot = data[n - 1]; + } + + T* left = data; + T* right = data + n - 1; + + while (left <= right) { + if (lessThan(*left, pivot)) { + left++; + } else if (lessThan(pivot, *right)) { + right--; + } else { + swap(*left, *right); + left++; + right--; + } + } + + quickSortMedian(data, right - data + 1, lessThan); + quickSortMedian(left, data + n - left, lessThan); +} + +//----------------------------------------------------------------------------- /** * Same as quickSortMedian(), but swap the low and high so that low, mid, and * high elements become sorted. This means that the low and high are already * partitioned, so we can omit those 2 points from the partitioning while-loop. * This code consumes a lot more flash memory due to the additional swap() - * calls. + * calls, but runs slightly faster. * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) +template +void quickSortMedianSwapped(T data[], uint16_t n) { + if (n <= 1) return; + + // Select the median of data[low], data[mid], and data[high] as the estimate + // of the ideal pivot. In the process, the (low, mid, high) become sorted. + uint16_t mid = n / 2; + T pivot = data[mid]; + if (data[n - 1] < data[0]) { + swap(data[0], data[n - 1]); + } + if (pivot < data[0]) { + swap(data[0], data[mid]); + } else if (data[n - 1] < pivot) { + swap(data[mid], data[n - 1]); + } + pivot = data[mid]; + + // We can skip the low and high because they are already sorted. + T* left = data + 1; + T* right = data + n - 2; + + while (left <= right) { + if (*left < pivot) { + left++; + } else if (pivot < *right) { + right--; + } else { + swap(*left, *right); + left++; + right--; + } + } + + quickSortMedianSwapped(data, right - data + 1); + quickSortMedianSwapped(left, data + n - left); +} +#else template void quickSortMedianSwapped(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + quickSortMedianSwapped(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument quickSortMedianSwapped() with the addition of a + * `lessThan` lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void quickSortMedianSwapped(T data[], uint16_t n, F&& lessThan) { if (n <= 1) return; - + // Select the median of data[low], data[mid], and data[high] as the estimate // of the ideal pivot. In the process, the (low, mid, high) become sorted. uint16_t mid = n / 2; T pivot = data[mid]; - if (data[0] > data[n - 1]) { + if (lessThan(data[n - 1], data[0])) { swap(data[0], data[n - 1]); } - if (data[0] > pivot) { + if (lessThan(pivot, data[0])) { swap(data[0], data[mid]); - } else if (pivot > data[n - 1]) { + } else if (lessThan(data[n - 1], pivot)) { swap(data[mid], data[n - 1]); } pivot = data[mid]; @@ -145,21 +301,21 @@ void quickSortMedianSwapped(T data[], uint16_t n) { // We can skip the low and high because they are already sorted. T* left = data + 1; T* right = data + n - 2; - + while (left <= right) { - if (*left < pivot) { + if (lessThan(*left, pivot)) { left++; - } else if (*right > pivot) { + } else if (lessThan(pivot, *right)) { right--; - } else { + } else { swap(*left, *right); - left++; - right--; - } + left++; + right--; + } } - quickSortMedianSwapped(data, right - data + 1); - quickSortMedianSwapped(left, data + n - left); + quickSortMedianSwapped(data, right - data + 1, lessThan); + quickSortMedianSwapped(left, data + n - left, lessThan); } } diff --git a/src/ace_sorting/selectionSort.h b/src/ace_sorting/selectionSort.h index 7d47ce2..0f79113 100644 --- a/src/ace_sorting/selectionSort.h +++ b/src/ace_sorting/selectionSort.h @@ -26,6 +26,7 @@ SOFTWARE. * @file selectionSort.h * * Selection sort. + * See https://en.wikipedia.org/wiki/Selection_sort */ #ifndef ACE_SORTING_SELECTION_SORT_H @@ -38,9 +39,11 @@ namespace ace_sorting { /** * Selection sort. * Average complexity: O(n^2) + * See https://en.wikipedia.org/wiki/Selection_sort * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void selectionSort(T data[], uint16_t n) { for (uint16_t i = 0; i < n; i++) { @@ -71,6 +74,53 @@ void selectionSort(T data[], uint16_t n) { } } } +#else +template +void selectionSort(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + selectionSort(data, n, lessThan); +} +#endif + +/** + * Same as the 2-argument selectionSort() with the addition of a `lessThan` + * lambda expression or function. + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void selectionSort(T data[], uint16_t n, F&& lessThan) { + for (uint16_t i = 0; i < n; i++) { + + // Loop to find the smallest element. + uint16_t iSmallest = i; + T smallest = data[i]; + + // Starting the loop with 'j = i + 1' increases flash usage on AVR by 12 + // bytes. But it does not reduce the execution time signficantly, because + // the (i + 1) will be done anyway by the j++ in the loop. So the only thing + // we save is a single redundant 'smallest < smallest' comparison. + for (uint16_t j = i; j < n; j++) { + if (lessThan(data[j], smallest)) { + iSmallest = j; + smallest = data[j]; + } + } + + // This extra check (i != iSmallest) is not really necessary, because if the + // first element was already the smallest, it would swap the value back into + // itself. However, the one situation where Selection Sort *might* be used + // over Insertion Sort is when the write operation is far more expensive + // than a read operation. So this test preserves that advantage of the + // Selection Sort, by avoiding doing an unnecessary swap. + if (i != iSmallest) { + swap(data[i], data[iSmallest]); + } + } +} } diff --git a/src/ace_sorting/shellSort.h b/src/ace_sorting/shellSort.h index 7ee241c..c9ce68b 100644 --- a/src/ace_sorting/shellSort.h +++ b/src/ace_sorting/shellSort.h @@ -31,8 +31,6 @@ SOFTWARE. #ifndef ACE_SORTING_SHELL_SORT_H #define ACE_SORTING_SHELL_SORT_H -#include "swap.h" - namespace ace_sorting { /** @@ -42,14 +40,15 @@ namespace ace_sorting { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void shellSortClassic(T data[], uint16_t n) { - uint16_t gap = n; - while (gap > 1) { - gap /= 2; + uint16_t gap = n; + while (gap > 1) { + gap /= 2; // Do insertion sort of each sub-array separated by gap. - for (uint16_t i = gap; i < n; i++) { + for (uint16_t i = gap; i < n; i++) { T temp = data[i]; // Shift one slot to the right. @@ -64,30 +63,77 @@ void shellSortClassic(T data[], uint16_t n) { // to be relatively cheap to copy, and checking for (i != j) is more // expensive than just doing the extra assignment. data[j] = temp; - } - } + } + } +} +#else +template +void shellSortClassic(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + shellSortClassic(data, n, lessThan); +} +#endif + +/** + * Shell sort with gap size reduced by factor of 2 each iteration. + * Average complexity: Between O(n^1.3) to O(n^1.5) + * See https://en.wikipedia.org/wiki/Shellsort + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void shellSortClassic(T data[], uint16_t n, F&& lessThan) { + uint16_t gap = n; + while (gap > 1) { + gap /= 2; + + // Do insertion sort of each sub-array separated by gap. + for (uint16_t i = gap; i < n; i++) { + T temp = data[i]; + + // Shift one slot to the right. + uint16_t j; + for (j = i; j >= gap; j -= gap) { + // The following is equivalent to: (data[j - gap] <= temp) + if (! lessThan(temp, data[j - gap])) break; + data[j] = data[j - gap]; + } + + // Just like insertionSort(), this can assign 'temp' back into the + // original slot if no shifting was done. That's ok because T is assumed + // to be relatively cheap to copy, and checking for (i != j) is more + // expensive than just doing the extra assignment. + data[j] = temp; + } + } } +//----------------------------------------------------------------------------- + /** * Shell sort using gap size from Knuth. * Average complexity: Between O(n^1.3) to O(n^1.5) * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void shellSortKnuth(T data[], uint16_t n) { // Calculate the largest gap using Knuth's formula. If n is a compile-time // constant and relatively "small" (observed to be true at least up to 100), // the compiler will precalculate the loop below and replace it with a // compile-time constant. - uint16_t gap = 1; + uint16_t gap = 1; while (gap < n / 3) { gap = gap * 3 + 1; } - while (gap > 0) { + while (gap > 0) { // Do insertion sort of each sub-array separated by gap. - for (uint16_t i = gap; i < n; i++) { + for (uint16_t i = gap; i < n; i++) { T temp = data[i]; // Shift one slot to the right. @@ -102,12 +148,61 @@ void shellSortKnuth(T data[], uint16_t n) { // to be relatively cheap to copy, and checking for (i != j) is more // expensive than just doing the extra assignment. data[j] = temp; - } + } + + gap = (gap - 1) / 3; + } +} +#else +template +void shellSortKnuth(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + shellSortKnuth(data, n, lessThan); +} +#endif + +/** + * Shell sort using gap size from Knuth. + * Average complexity: Between O(n^1.3) to O(n^1.5) + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void shellSortKnuth(T data[], uint16_t n, F&& lessThan) { + uint16_t gap = 1; + while (gap < n / 3) { + gap = gap * 3 + 1; + } + + while (gap > 0) { + // Do insertion sort of each sub-array separated by gap. + for (uint16_t i = gap; i < n; i++) { + T temp = data[i]; + + // Shift one slot to the right. + uint16_t j; + for (j = i; j >= gap; j -= gap) { + // The following is equivalent to: (data[j - gap] <= temp) + if (! lessThan(temp, data[j - gap])) break; + data[j] = data[j - gap]; + } + + // Just like insertionSort(), this can assign 'temp' back into the + // original slot if no shifting was done. That's ok because T is assumed + // to be relatively cheap to copy, and checking for (i != j) is more + // expensive than just doing the extra assignment. + data[j] = temp; + } gap = (gap - 1) / 3; - } + } } +//----------------------------------------------------------------------------- + /** * Shell sort using gap sizes empirically determined by Tokuda. See * https://en.wikipedia.org/wiki/Shellsort and https://oeis.org/A108870. @@ -115,6 +210,7 @@ void shellSortKnuth(T data[], uint16_t n) { * * @tparam T type of data to sort */ +#if defined(ACE_SORTING_DIRECT) template void shellSortTokuda(T data[], const uint16_t n) { @@ -122,20 +218,20 @@ void shellSortTokuda(T data[], const uint16_t n) // https://en.wikipedia.org/wiki/Shellsort // https://oeis.org/A108870 static const uint16_t sGaps[] = { - 1, 4, 9, 20, 46, 103, 233, 525, 1182, 2660, 5985, 13467, 30301, + 1, 4, 9, 20, 46, 103, 233, 525, 1182, 2660, 5985, 13467, 30301, }; const uint16_t nGaps = sizeof(sGaps) / sizeof(uint16_t); // Find the starting gap. - uint16_t iGap; + uint16_t iGap; for (iGap = 0; sGaps[iGap] < n && iGap < nGaps; iGap++) {} if (iGap != 0) iGap--; - while (true) { + while (true) { uint16_t gap = sGaps[iGap]; // Do insertion sort of each sub-array separated by gap. - for (uint16_t i = gap; i < n; i++) { + for (uint16_t i = gap; i < n; i++) { T temp = data[i]; // Shift one slot to the right. @@ -150,11 +246,71 @@ void shellSortTokuda(T data[], const uint16_t n) // to be relatively cheap to copy, and checking for (i != j) is more // expensive than just doing the extra assignment. data[j] = temp; - } + } + + if (iGap == 0) break; + iGap--; + } +} +#else +template +void shellSortTokuda(T data[], uint16_t n) { + // This lambda expression does not perform any captures, so the compiler will + // optimize and inline the less-than expression. + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + shellSortTokuda(data, n, lessThan); +} +#endif + +/** + * Shell sort using gap sizes empirically determined by Tokuda. See + * https://en.wikipedia.org/wiki/Shellsort and https://oeis.org/A108870. + * Average complexity: Between O(n^1.3) to O(n^1.5) + * + * @tparam T type of data to sort + * @tparam F type of lambda expression or function that returns true if a < b + */ +template +void shellSortTokuda(T data[], const uint16_t n, F&& lessThan) +{ + // Experimentally observed ideal gaps. + // https://en.wikipedia.org/wiki/Shellsort + // https://oeis.org/A108870 + static const uint16_t sGaps[] = { + 1, 4, 9, 20, 46, 103, 233, 525, 1182, 2660, 5985, 13467, 30301, + }; + const uint16_t nGaps = sizeof(sGaps) / sizeof(uint16_t); + + // Find the starting gap. + uint16_t iGap; + for (iGap = 0; sGaps[iGap] < n && iGap < nGaps; iGap++) {} + if (iGap != 0) iGap--; + + while (true) { + uint16_t gap = sGaps[iGap]; + + // Do insertion sort of each sub-array separated by gap. + for (uint16_t i = gap; i < n; i++) { + T temp = data[i]; + + // Shift one slot to the right. + uint16_t j; + for (j = i; j >= gap; j -= gap) { + // The following is equivalent to: (data[j - gap] <= temp) + if (! lessThan(temp, data[j - gap])) break; + data[j] = data[j - gap]; + } + + // Just like insertionSort(), this can assign 'temp' back into the + // original slot if no shifting was done. That's ok because T is assumed + // to be relatively cheap to copy, and checking for (i != j) is more + // expensive than just doing the extra assignment. + data[j] = temp; + } if (iGap == 0) break; iGap--; - } + } } } diff --git a/tests/SortingTest/SortingTest.ino b/tests/SortingTest/SortingTest.ino index 0102125..d0ae04f 100644 --- a/tests/SortingTest/SortingTest.ino +++ b/tests/SortingTest/SortingTest.ino @@ -8,6 +8,7 @@ using aunit::TestRunner; using aunit::TestOnce; using ace_common::isSorted; +using ace_common::isReverseSorted; using ace_sorting::bubbleSort; using ace_sorting::insertionSort; using ace_sorting::selectionSort; @@ -97,6 +98,8 @@ class SortingTest : public TestOnce { } }; +//---------------------------------------------------------------------------- + testF(SortingTest, bubbleSort) { assertSort(bubbleSort); } @@ -149,6 +152,123 @@ testF(SortingTest, quickSortMedianSwapped) { assertSort(quickSortMedianSwapped); } +//---------------------------------------------------------------------------- + +/* +// It does not seem possible to create a pointer to the 3-argument version +// of the generic xxxSort() function because of the template F&& argument +// which has no human-readable name because the lambda expression is generated +// by the compiler. So the following attempt does not work. +// +typedef bool (*Compare)(const uint16_t& a, const uint16_t& b); +typedef void (*GenericSortFunction)( + uint16_t data[], uint16_t n, Compare lessThan); +*/ + +// Define lambda expression that reverses the sort order. A normal function will +// also work. The nice thing about using a lambda expression is that it can be +// embedded directly in the calling function and be able to capture variables in +// the local scope, though that feature is not used here. +auto&& greaterThan = [](const uint16_t& a, const uint16_t& b) { + return a > b; +}; + +class ReverseSortingTest : public TestOnce { + protected: + const uint16_t kDataSize = 300; + + void setup() override { + TestOnce::setup(); + mData = new uint16_t[kDataSize]; + fillArray(mData, kDataSize); + } + + void teardown() override { + delete[] mData; + TestOnce::teardown(); + } + + uint16_t* mData; +}; + +testF(ReverseSortingTest, bubbleSort) { + assertFalse(isSorted(mData, kDataSize)); + bubbleSort(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, insertionSort) { + assertFalse(isSorted(mData, kDataSize)); + insertionSort(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, selectionSort) { + assertFalse(isSorted(mData, kDataSize)); + selectionSort(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, shellSortClassic) { + assertFalse(isSorted(mData, kDataSize)); + shellSortClassic(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, shellSortKnuth) { + assertFalse(isSorted(mData, kDataSize)); + shellSortKnuth(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, shellSortTokuda) { + assertFalse(isSorted(mData, kDataSize)); + shellSortTokuda(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, combSort13) { + assertFalse(isSorted(mData, kDataSize)); + combSort13(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, combSort13m) { + assertFalse(isSorted(mData, kDataSize)); + combSort13m(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, combSort133) { + assertFalse(isSorted(mData, kDataSize)); + combSort133(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, combSort133m) { + assertFalse(isSorted(mData, kDataSize)); + combSort133m(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, quickSortMiddle) { + assertFalse(isSorted(mData, kDataSize)); + quickSortMiddle(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, quickSortMedian) { + assertFalse(isSorted(mData, kDataSize)); + quickSortMedian(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + +testF(ReverseSortingTest, quickSortMedianSwapped) { + assertFalse(isSorted(mData, kDataSize)); + quickSortMedianSwapped(mData, kDataSize, greaterThan); + assertTrue(isReverseSorted(mData, kDataSize)); +} + //---------------------------------------------------------------------------- // setup() and loop() //---------------------------------------------------------------------------- From 9bf289f2fdcfae91a454d6ce7399620dbeaedbef Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 21 Aug 2021 14:53:12 -0700 Subject: [PATCH 03/17] src: Add ability to select between direct and indirect versions of the 2-argument sortXxx() algorithms --- src/ace_sorting/bubbleSort.h | 10 +++++++++- src/ace_sorting/combSort.h | 16 ++++++++++++---- src/ace_sorting/insertionSort.h | 10 +++++++++- src/ace_sorting/quickSort.h | 23 ++++++++++++++++++----- src/ace_sorting/selectionSort.h | 10 +++++++++- src/ace_sorting/shellSort.h | 15 ++++++++++++--- 6 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/ace_sorting/bubbleSort.h b/src/ace_sorting/bubbleSort.h index 5caf41a..5af6225 100644 --- a/src/ace_sorting/bubbleSort.h +++ b/src/ace_sorting/bubbleSort.h @@ -33,6 +33,14 @@ SOFTWARE. #include "swap.h" +// If set to 1, use the direct inlined implementation of the 2-argument +// bubbleSort(). Otherwise, use the 3-argument bubbleSort() to implement +// 2-argument bubbleSort(). For bubbleSort, the compiler will optimize both +// versions to be identical. +#if ! defined(ACE_SORTING_DIRECT_BUBBLE_SORT) + #define ACE_SORTING_DIRECT_BUBBLE_SORT 0 +#endif + namespace ace_sorting { /** @@ -41,7 +49,7 @@ namespace ace_sorting { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_BUBBLE_SORT template void bubbleSort(T data[], uint16_t n) { bool swapped; diff --git a/src/ace_sorting/combSort.h b/src/ace_sorting/combSort.h index 85c883b..56237b8 100644 --- a/src/ace_sorting/combSort.h +++ b/src/ace_sorting/combSort.h @@ -33,6 +33,14 @@ SOFTWARE. #include "swap.h" +// If set to 1, use the direct inlined implementation of the 2-argument +// combSortXxx(). Otherwise, use the 3-argument combSortXxx() to implement +// 2-argument combSortXxx(). For combSortXxx(), the compiler will optimize both +// versions to be identical. +#if ! defined(ACE_SORTING_DIRECT_COMB_SORT) + #define ACE_SORTING_DIRECT_COMB_SORT 0 +#endif + namespace ace_sorting { /** @@ -46,7 +54,7 @@ namespace ace_sorting { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_COMB_SORT template void combSort13(T data[], uint16_t n) { bool swapped = true; @@ -119,7 +127,7 @@ void combSort13(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_COMB_SORT template void combSort13m(T data[], uint16_t n) { bool swapped = true; @@ -211,7 +219,7 @@ void combSort13m(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_COMB_SORT template void combSort133(T data[], uint16_t n) { bool swapped = true; @@ -283,7 +291,7 @@ void combSort133(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_COMB_SORT template void combSort133m(T data[], uint16_t n) { bool swapped = true; diff --git a/src/ace_sorting/insertionSort.h b/src/ace_sorting/insertionSort.h index 944be48..659dcea 100644 --- a/src/ace_sorting/insertionSort.h +++ b/src/ace_sorting/insertionSort.h @@ -32,6 +32,14 @@ SOFTWARE. #ifndef ACE_SORTING_INSERTION_SORT_H #define ACE_SORTING_INSERTION_SORT_H +// If set to 1, use the direct inlined implementation of the 2-argument +// insertionSort(). Otherwise, use the 3-argument insertionSort() to implement +// 2-argument insertionSort(). For insertionSort(), the compiler will optimize +// both versions to be identical. +#if ! defined(ACE_SORTING_DIRECT_INSERTION_SORT) + #define ACE_SORTING_DIRECT_INSERTION_SORT 0 +#endif + namespace ace_sorting { /** @@ -41,7 +49,7 @@ namespace ace_sorting { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_INSERTION_SORT template void insertionSort(T data[], uint16_t n) { for (uint16_t i = 1; i < n; i++) { diff --git a/src/ace_sorting/quickSort.h b/src/ace_sorting/quickSort.h index 6993f49..78006e5 100644 --- a/src/ace_sorting/quickSort.h +++ b/src/ace_sorting/quickSort.h @@ -34,6 +34,16 @@ SOFTWARE. #include "swap.h" +// If set to 1, use the direct inlined implementation of the 2-argument +// quickSortXxx(). Otherwise, use the 3-argument quickSortXxx() to implement +// 2-argument quickSortXxx(). Unlike other sorting algorithms, the compiler +// cannot seem to optimize away the extra level of indirection, probably due to +// the recursive calls. We save 40 bytes of flash (out of 200-300 bytes) if we +// use the direct inlined version for the 2-argument variant. Set this to 1. +#if ! defined(ACE_SORTING_DIRECT_QUICK_SORT) + #define ACE_SORTING_DIRECT_QUICK_SORT 1 +#endif + namespace ace_sorting { /** @@ -45,7 +55,7 @@ namespace ace_sorting { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_QUICK_SORT template void quickSortMiddle(T data[], uint16_t n) { if (n <= 1) return; @@ -72,8 +82,11 @@ void quickSortMiddle(T data[], uint16_t n) { #else template void quickSortMiddle(T data[], uint16_t n) { - // This lambda expression does not perform any captures, so the compiler will - // optimize and inline the less-than expression. + // This lambda expression does not perform any captures, so the compiler ought + // to be able to optimize and inline the less-than expression. However, the + // optimization does not seem to work, probably because of the recursive call + // into itself. So we set ACE_SORTING_DIRECT_QUICK_SORT=1 to use the direct + // inlined version. auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; quickSortMiddle(data, n, lessThan); } @@ -121,7 +134,7 @@ void quickSortMiddle(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_QUICK_SORT template void quickSortMedian(T data[], uint16_t n) { if (n <= 1) return; @@ -225,7 +238,7 @@ void quickSortMedian(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_QUICK_SORT template void quickSortMedianSwapped(T data[], uint16_t n) { if (n <= 1) return; diff --git a/src/ace_sorting/selectionSort.h b/src/ace_sorting/selectionSort.h index 0f79113..c283736 100644 --- a/src/ace_sorting/selectionSort.h +++ b/src/ace_sorting/selectionSort.h @@ -36,6 +36,14 @@ SOFTWARE. namespace ace_sorting { +// If set to 1, use the direct inlined implementation of the 2-argument +// selectionSort(). Otherwise, use the 3-argument selectionSort() to implement +// 2-argument selectionSort(). For selectionSort(), the compiler will optimize +// both versions to be identical. +#if ! defined(ACE_SORTING_DIRECT_SELECTION_SORT) + #define ACE_SORTING_DIRECT_SELECTION_SORT 0 +#endif + /** * Selection sort. * Average complexity: O(n^2) @@ -43,7 +51,7 @@ namespace ace_sorting { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_SELECTION_SORT template void selectionSort(T data[], uint16_t n) { for (uint16_t i = 0; i < n; i++) { diff --git a/src/ace_sorting/shellSort.h b/src/ace_sorting/shellSort.h index c9ce68b..c976219 100644 --- a/src/ace_sorting/shellSort.h +++ b/src/ace_sorting/shellSort.h @@ -26,11 +26,20 @@ SOFTWARE. * @file shellSort.h * * Shell sort with different gap algorithms. + * See https://en.wikipedia.org/wiki/Shellsort */ #ifndef ACE_SORTING_SHELL_SORT_H #define ACE_SORTING_SHELL_SORT_H +// If set to 1, use the direct inlined implementation of the 2-argument +// shellSortXxx(). Otherwise, use the 3-argument shellSortXxx() to implement +// 2-argument shellSortXxx(). For shellSortXxx(), the compiler will optimize +// both versions to be identical. +#if ! defined(ACE_SORTING_DIRECT_SHELL_SORT) + #define ACE_SORTING_DIRECT_SHELL_SORT 0 +#endif + namespace ace_sorting { /** @@ -40,7 +49,7 @@ namespace ace_sorting { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_SHELL_SORT template void shellSortClassic(T data[], uint16_t n) { uint16_t gap = n; @@ -119,7 +128,7 @@ void shellSortClassic(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_SHELL_SORT template void shellSortKnuth(T data[], uint16_t n) { // Calculate the largest gap using Knuth's formula. If n is a compile-time @@ -210,7 +219,7 @@ void shellSortKnuth(T data[], uint16_t n, F&& lessThan) { * * @tparam T type of data to sort */ -#if defined(ACE_SORTING_DIRECT) +#if ACE_SORTING_DIRECT_SHELL_SORT template void shellSortTokuda(T data[], const uint16_t n) { From 696a6c5dbe0f51ab12a02a1ae3e6ca8237e647f4 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 22 Aug 2021 15:00:51 -0700 Subject: [PATCH 04/17] MemoryBenchmark: Regenerate with 2-argument versions routing into the 3-argument versions with a default lessThan lambda expression --- examples/MemoryBenchmark/README.md | 23 ++++++++++++++------- examples/MemoryBenchmark/esp8266.txt | 2 +- examples/MemoryBenchmark/generate_readme.py | 7 +++++++ examples/MemoryBenchmark/micro.txt | 2 +- examples/MemoryBenchmark/nano.txt | 2 +- examples/MemoryBenchmark/samd.txt | 4 ++-- examples/MemoryBenchmark/stm32.txt | 2 +- examples/MemoryBenchmark/teensy32.txt | 4 ++-- 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 75d4b10..8248437 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -39,6 +39,13 @@ ASCII table. indicates that the `qsort()` function is already compiled into the ESP32 runtime library. +**v0.2+** + +* Add 3-argument version of sorting functions to pass in a comparison predicate, + and route the 2-argument version into the 3-argument version. +* Usually no difference in flash size, as the compiler seems to be able to + inline the lambda expression. In fact, some actually got a few bytes smaller. + ## Arduino Nano * 16MHz ATmega328P @@ -66,7 +73,7 @@ ASCII table. |----------------------------------------+--------------+-------------| | quickSortMiddle() | 1244/ 214 | 178/ 0 | | quickSortMedian() | 1296/ 214 | 230/ 0 | -| quickSortMedianSwapped() | 1344/ 214 | 278/ 0 | +| quickSortMedianSwapped() | 1342/ 214 | 276/ 0 | |----------------------------------------+--------------+-------------| | qsort() | 2150/ 214 | 1084/ 0 | +---------------------------------------------------------------------+ @@ -100,7 +107,7 @@ ASCII table. |----------------------------------------+--------------+-------------| | quickSortMiddle() | 4238/ 354 | 178/ 0 | | quickSortMedian() | 4290/ 354 | 230/ 0 | -| quickSortMedianSwapped() | 4338/ 354 | 278/ 0 | +| quickSortMedianSwapped() | 4336/ 354 | 276/ 0 | |----------------------------------------+--------------+-------------| | qsort() | 5144/ 354 | 1084/ 0 | +---------------------------------------------------------------------+ @@ -119,13 +126,13 @@ ASCII table. |----------------------------------------+--------------+-------------| | Baseline | 10520/ 0 | 0/ 0 | |----------------------------------------+--------------+-------------| -| bubbleSort() | 10568/ 0 | 48/ 0 | +| bubbleSort() | 10560/ 0 | 40/ 0 | | insertionSort() | 10568/ 0 | 48/ 0 | | selectionSort() | 10584/ 0 | 64/ 0 | |----------------------------------------+--------------+-------------| | shellSortClassic() | 10584/ 0 | 64/ 0 | | shellSortKnuth() | 10576/ 0 | 56/ 0 | -| shellSortTokuda() | 10648/ 0 | 128/ 0 | +| shellSortTokuda() | 10640/ 0 | 120/ 0 | |----------------------------------------+--------------+-------------| | combSort13() | 10584/ 0 | 64/ 0 | | combSort13m() | 10600/ 0 | 80/ 0 | @@ -161,7 +168,7 @@ ASCII table. |----------------------------------------+--------------+-------------| | shellSortClassic() | 26884/ 3844 | 64/ 0 | | shellSortKnuth() | 26900/ 3844 | 80/ 0 | -| shellSortTokuda() | 26956/ 3844 | 136/ 0 | +| shellSortTokuda() | 26944/ 3844 | 124/ 0 | |----------------------------------------+--------------+-------------| | combSort13() | 26896/ 3844 | 76/ 0 | | combSort13m() | 26904/ 3844 | 84/ 0 | @@ -195,7 +202,7 @@ ASCII table. |----------------------------------------+--------------+-------------| | shellSortClassic() | 257180/26976 | 80/ 0 | | shellSortKnuth() | 257212/26976 | 112/ 0 | -| shellSortTokuda() | 257256/27004 | 156/ 28 | +| shellSortTokuda() | 257240/27004 | 140/ 28 | |----------------------------------------+--------------+-------------| | combSort13() | 257196/26976 | 96/ 0 | | combSort13m() | 257212/26976 | 112/ 0 | @@ -261,13 +268,13 @@ usage by objects. |----------------------------------------+--------------+-------------| | Baseline | 7116/ 3256 | 0/ 0 | |----------------------------------------+--------------+-------------| -| bubbleSort() | 7144/ 3256 | 28/ 0 | +| bubbleSort() | 7148/ 3256 | 32/ 0 | | insertionSort() | 7172/ 3256 | 56/ 0 | | selectionSort() | 7180/ 3256 | 64/ 0 | |----------------------------------------+--------------+-------------| | shellSortClassic() | 7196/ 3256 | 80/ 0 | | shellSortKnuth() | 7208/ 3256 | 92/ 0 | -| shellSortTokuda() | 7304/ 3256 | 188/ 0 | +| shellSortTokuda() | 7284/ 3256 | 168/ 0 | |----------------------------------------+--------------+-------------| | combSort13() | 7192/ 3256 | 76/ 0 | | combSort13m() | 7204/ 3256 | 88/ 0 | diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 20aad2b..cd0e9c2 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -4,7 +4,7 @@ 3 257180 1044464 26976 81920 4 257180 1044464 26976 81920 5 257212 1044464 26976 81920 -6 257256 1044464 27004 81920 +6 257240 1044464 27004 81920 7 257196 1044464 26976 81920 8 257212 1044464 26976 81920 9 257180 1044464 26976 81920 diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index 59ee7a1..043c483 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -63,6 +63,13 @@ indicates that the `qsort()` function is already compiled into the ESP32 runtime library. +**v0.2+** + +* Add 3-argument version of sorting functions to pass in a comparison predicate, + and route the 2-argument version into the 3-argument version. +* Usually no difference in flash size, as the compiler seems to be able to + inline the lambda expression. In fact, some actually got a few bytes smaller. + ## Arduino Nano * 16MHz ATmega328P diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index ee3ebeb..2babadb 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -11,5 +11,5 @@ 10 4188 28672 354 2560 11 4238 28672 354 2560 12 4290 28672 354 2560 -13 4338 28672 354 2560 +13 4336 28672 354 2560 14 5144 28672 354 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 4c6cc25..0c60fb2 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -11,5 +11,5 @@ 10 1194 30720 214 2048 11 1244 30720 214 2048 12 1296 30720 214 2048 -13 1344 30720 214 2048 +13 1342 30720 214 2048 14 2150 30720 214 2048 diff --git a/examples/MemoryBenchmark/samd.txt b/examples/MemoryBenchmark/samd.txt index 277d53a..a8c7d0e 100644 --- a/examples/MemoryBenchmark/samd.txt +++ b/examples/MemoryBenchmark/samd.txt @@ -1,10 +1,10 @@ 0 10520 262144 -1 10568 262144 +1 10560 262144 2 10568 262144 3 10584 262144 4 10584 262144 5 10576 262144 -6 10648 262144 +6 10640 262144 7 10584 262144 8 10600 262144 9 10576 262144 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index a564471..47f9d2d 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -4,7 +4,7 @@ 3 26900 131072 3844 20480 4 26884 131072 3844 20480 5 26900 131072 3844 20480 -6 26956 131072 3844 20480 +6 26944 131072 3844 20480 7 26896 131072 3844 20480 8 26904 131072 3844 20480 9 26888 131072 3844 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 54fba26..7938e67 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -1,10 +1,10 @@ 0 7116 262144 3256 65536 -1 7144 262144 3256 65536 +1 7148 262144 3256 65536 2 7172 262144 3256 65536 3 7180 262144 3256 65536 4 7196 262144 3256 65536 5 7208 262144 3256 65536 -6 7304 262144 3256 65536 +6 7284 262144 3256 65536 7 7192 262144 3256 65536 8 7204 262144 3256 65536 9 7172 262144 3256 65536 From da3b1de545c9f4cd446d1c1d62ba43dd9e033d12 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 22 Aug 2021 16:20:54 -0700 Subject: [PATCH 05/17] examples/HelloSort: Add expected output --- examples/HelloSort/HelloSort.ino | 28 ++++++++++++++++++++++------ examples/HelloSort/Makefile | 1 - 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/examples/HelloSort/HelloSort.ino b/examples/HelloSort/HelloSort.ino index 48faf93..0590d21 100644 --- a/examples/HelloSort/HelloSort.ino +++ b/examples/HelloSort/HelloSort.ino @@ -1,11 +1,26 @@ /* * Quick demo of one of the sorting functions, in this example, * shellSortKnuth(). All the other sorting algorithms have the exact same - * function signature. First, create an array of integers with random numbers. - * Then sort the array in different ways, including reverse sorting. Print out - * the unsorted and sorted arrays. The compiler is able to infer the type of the - * data, so you don't normally need to specify the template type to the - * shellSortKnuth() function. + * function signature. The compiler is able to infer the type of the data, so + * you don't normally need to specify the template type to the shellSortKnuth() + * function. + * + * Expected output: + * + * Unsorted: 234 19 95 219 255 132 27 194 83 96 245 161 228 205 193 215 101 216 + * 120 95 + * + * Sorted using implicit ascending: 19 27 83 95 95 96 101 120 132 161 193 194 + * 205 215 216 219 228 234 245 255 + * + * Sorted using function pointer: 19 27 83 95 95 96 101 120 132 161 193 194 205 + * 215 216 219 228 234 245 255 + * + * Sorted using lambda expression: 19 27 83 95 95 96 101 120 132 161 193 194 205 + * 215 216 219 228 234 245 255 + * + * Reverse sorted using lambda expression: 255 245 234 228 219 216 215 205 194 + * 193 161 132 120 101 96 95 95 83 27 19 */ #include @@ -13,11 +28,12 @@ using ace_sorting::shellSortKnuth; +// ESP32 does not define SERIAL_PORT_MONITOR #if !defined(SERIAL_PORT_MONITOR) #define SERIAL_PORT_MONITOR Serial #endif -const uint16_t ARRAY_SIZE = 50; +const uint16_t ARRAY_SIZE = 20; int array[ARRAY_SIZE]; // Print given array. diff --git a/examples/HelloSort/Makefile b/examples/HelloSort/Makefile index 79db6d2..10ae8dd 100644 --- a/examples/HelloSort/Makefile +++ b/examples/HelloSort/Makefile @@ -3,5 +3,4 @@ APP_NAME := HelloSort ARDUINO_LIBS := AceSorting -MORE_CLEAN := more_clean include ../../../EpoxyDuino/EpoxyDuino.mk From 8d0a971fa4b9c9569cc33cc1b8781fa68803a4b4 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 22 Aug 2021 16:21:22 -0700 Subject: [PATCH 06/17] examples/CompoundSortingDemo: Add example of sorting with compound keys --- .../CompoundSortingDemo.ino | 161 ++++++++++++++++++ examples/CompoundSortingDemo/Makefile | 6 + 2 files changed, 167 insertions(+) create mode 100644 examples/CompoundSortingDemo/CompoundSortingDemo.ino create mode 100644 examples/CompoundSortingDemo/Makefile diff --git a/examples/CompoundSortingDemo/CompoundSortingDemo.ino b/examples/CompoundSortingDemo/CompoundSortingDemo.ino new file mode 100644 index 0000000..d7f4423 --- /dev/null +++ b/examples/CompoundSortingDemo/CompoundSortingDemo.ino @@ -0,0 +1,161 @@ +/* + * Demo of a more complex sorting using a compound key and a lambda expression. + * This version uses shellSortKnuth(), but all the other sorting algorithms have + * the exact same function signature. + * + * Expected output: + * + * Unsorted + * -------- + * Michael 3 + * Soren 1 + * Arun 5 + * Meilin 6 + * Emilia 3 + * Dimitri 2 + * Dembe 8 + * Nasir 10 + * Hiromi 9 + * Petra 6 + * + * Sorted by name + * -------------- + * Arun 5 + * Dembe 8 + * Dimitri 2 + * Emilia 3 + * Hiromi 9 + * Meilin 6 + * Michael 3 + * Nasir 10 + * Petra 6 + * Soren 1 + * + * Sorted by (score, name) + * ----------------------- + * Soren 1 + * Dimitri 2 + * Emilia 3 + * Michael 3 + * Arun 5 + * Meilin 6 + * Petra 6 + * Dembe 8 + * Hiromi 9 + * Nasir 10 + */ + +#include // strcmp() +#include +#include + +using ace_sorting::shellSortKnuth; + +// ESP32 does not define SERIAL_PORT_MONITOR +#if ! defined(SERIAL_PORT_MONITOR) + #define SERIAL_PORT_MONITOR Serial +#endif + +// Record of a person's name and score. +struct Record { + const char* name; + int score; +}; + +// List of names and their scores. This table is const so cannot be modified. +// The names and this table could be stored in PROGMEM, but that would +// significantly clutter up the code with type conversions which makes this +// example harder to understand. +const uint16_t ARRAY_SIZE = 10; +const Record RECORDS[ARRAY_SIZE] = { + { "Michael", 3 }, + { "Soren", 1 }, + { "Arun", 5 }, + { "Meilin", 6 }, + { "Emilia", 3 }, + { "Dimitri", 2 }, + { "Dembe", 8 }, + { "Nasir", 10 }, + { "Hiromi", 9 }, + { "Petra", 6 }, +}; + +// Print the records given an array of pointers to Record. +void printRecords(const Record* const records[], uint16_t arraySize) { + for (uint16_t i = 0; i < arraySize; i++) { + const Record* record = records[i]; + SERIAL_PORT_MONITOR.print(record->name); + SERIAL_PORT_MONITOR.print(' '); + SERIAL_PORT_MONITOR.print(record->score); + SERIAL_PORT_MONITOR.println(); + } +} + +// Fill the recordPtrs[] array with the pointers to RECORDS[]. The original +// RECORDS[] is immutable, so we need a helper array to perform the sorting. +void fillRecordPointers(const Record* recordPtrs[], uint16_t arraySize) { + for (uint16_t i = 0; i < arraySize; i++) { + recordPtrs[i] = &RECORDS[i]; + } +} + +// Predicate that returns true if Record 'a' is less than Record 'b' by first +// looking at the 'score', then using 'name' to break the tie on score. +bool sortByScoreThenName(const Record* a, const Record* b) { + if (a->score < b->score) { + return true; + } else if (a->score > b->score) { + return false; + } else { + return strcmp(a->name, b->name) < 0; + } +} + +//----------------------------------------------------------------------------- + +void setup() { +#if ! defined(EPOXY_DUINO) + delay(1000); +#endif + + SERIAL_PORT_MONITOR.begin(115200); + while (!SERIAL_PORT_MONITOR); // Leonardo/Micro + + const Record* recordPtrs[ARRAY_SIZE]; + fillRecordPointers(recordPtrs, ARRAY_SIZE); + + // Print original ordering. + SERIAL_PORT_MONITOR.println(F("Unsorted")); + SERIAL_PORT_MONITOR.println(F("--------")); + printRecords(recordPtrs, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); + + // Sort by name. Use an inline lambda expression because the predicate is + // very short. + SERIAL_PORT_MONITOR.println(F("Sorted by name")); + SERIAL_PORT_MONITOR.println(F("--------------")); + shellSortKnuth( + recordPtrs, + ARRAY_SIZE, + [](const Record* a, const Record* b) { + return strcmp(a->name, b->name) < 0; + } + ); + printRecords(recordPtrs, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); + + // Sort by score then name. Use a helper function for readability because the + // predicate is more complex, but an inlined lambda expression would work + // perfectly fine. + SERIAL_PORT_MONITOR.println(F("Sorted by (score, name)")); + SERIAL_PORT_MONITOR.println(F("-----------------------")); + shellSortKnuth(recordPtrs, ARRAY_SIZE, sortByScoreThenName); + printRecords(recordPtrs, ARRAY_SIZE); + SERIAL_PORT_MONITOR.println(); + +#if defined(EPOXY_DUINO) + exit(0); +#endif +} + +void loop() {} diff --git a/examples/CompoundSortingDemo/Makefile b/examples/CompoundSortingDemo/Makefile new file mode 100644 index 0000000..96f0560 --- /dev/null +++ b/examples/CompoundSortingDemo/Makefile @@ -0,0 +1,6 @@ +# See https://github.com/bxparks/EpoxyDuino for documentation about using +# EpoxyDuino to compile and run AUnit tests natively on Linux or MacOS. + +APP_NAME := CompoundSortingDemo +ARDUINO_LIBS := AceSorting +include ../../../EpoxyDuino/EpoxyDuino.mk From daf956f7b5f6c43b4ae025484a57af9e02837aa7 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 22 Aug 2021 17:31:47 -0700 Subject: [PATCH 07/17] AutoBenchmark: Regenerate with 2-argument versions routing into the 3-argument versions with a default lessThan lambda expression --- examples/AutoBenchmark/README.md | 199 +++++++++++----------- examples/AutoBenchmark/esp32.txt | 158 ++++++++--------- examples/AutoBenchmark/esp8266.txt | 130 +++++++------- examples/AutoBenchmark/generate_readme.py | 5 + examples/AutoBenchmark/micro.txt | 112 ++++++------ examples/AutoBenchmark/nano.txt | 112 ++++++------ examples/AutoBenchmark/samd.txt | 160 ++++++++--------- examples/AutoBenchmark/stm32.txt | 162 +++++++++--------- examples/AutoBenchmark/teensy32.txt | 148 ++++++++-------- 9 files changed, 598 insertions(+), 588 deletions(-) diff --git a/examples/AutoBenchmark/README.md b/examples/AutoBenchmark/README.md index dfc2896..c72b26f 100644 --- a/examples/AutoBenchmark/README.md +++ b/examples/AutoBenchmark/README.md @@ -54,6 +54,11 @@ $ make README.md * The C-library `qsort()` is far slower than the C++ version because it uses a callback to a comparison function through a function pointer. +**v0.2+** + +* No performance change after rerouting 2-argument sorting functions into + the 3-argument versions using a default lambda expression. + ## Results The following results show the runtime of each sorting function in milliseconds, @@ -71,24 +76,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.107 | 1.077 | 12.735 | 116.675 | | | -| insertionSort() | 0.045 | 0.263 | 2.557 | 22.252 | | | -| selectionSort() | 0.088 | 0.560 | 5.600 | 48.892 | | | +| bubbleSort() | 0.099 | 1.044 | 12.305 | 118.589 | | | +| insertionSort() | 0.049 | 0.251 | 2.463 | 21.288 | | | +| selectionSort() | 0.087 | 0.553 | 5.365 | 46.275 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.074 | 0.310 | 1.706 | 6.865 | | | -| shellSortKnuth() | 0.101 | 0.330 | 1.450 | 5.665 | | | -| shellSortTokuda() | 0.075 | 0.327 | 1.614 | 6.540 | | | +| shellSortClassic() | 0.074 | 0.306 | 1.711 | 6.868 | | | +| shellSortKnuth() | 0.100 | 0.325 | 1.431 | 5.683 | | | +| shellSortTokuda() | 0.075 | 0.336 | 1.616 | 6.555 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.160 | 0.534 | 2.214 | 8.167 | | | -| combSort13m() | 0.165 | 0.550 | 2.219 | 8.181 | | | -| combSort133() | 0.086 | 0.396 | 1.944 | 7.702 | | | -| combSort133m() | 0.086 | 0.416 | 1.978 | 7.740 | | | +| combSort13() | 0.167 | 0.534 | 2.215 | 8.260 | | | +| combSort13m() | 0.164 | 0.557 | 2.233 | 8.176 | | | +| combSort133() | 0.084 | 0.400 | 1.968 | 7.730 | | | +| combSort133m() | 0.087 | 0.419 | 1.979 | 7.805 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.096 | 0.368 | 1.568 | 5.651 | | | -| quickSortMedian() | 0.117 | 0.431 | 1.717 | 5.905 | | | -| quickSortMdnSwppd() | 0.094 | 0.341 | 1.417 | 4.909 | | | +| quickSortMiddle() | 0.097 | 0.373 | 1.582 | 5.536 | | | +| quickSortMedian() | 0.117 | 0.423 | 1.717 | 5.905 | | | +| quickSortMdnSwppd() | 0.092 | 0.338 | 1.396 | 4.895 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.204 | 0.855 | 3.629 | 13.021 | | | +| qsort() | 0.208 | 0.827 | 3.642 | 13.068 | | | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -105,24 +110,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.115 | 1.083 | 12.773 | 121.179 | | | -| insertionSort() | 0.041 | 0.291 | 2.527 | 21.032 | | | -| selectionSort() | 0.081 | 0.561 | 5.632 | 49.153 | | | +| bubbleSort() | 0.091 | 1.136 | 12.908 | 120.933 | | | +| insertionSort() | 0.048 | 0.271 | 2.652 | 22.188 | | | +| selectionSort() | 0.084 | 0.556 | 5.391 | 46.513 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.074 | 0.310 | 1.712 | 6.912 | | | -| shellSortKnuth() | 0.101 | 0.339 | 1.445 | 5.601 | | | -| shellSortTokuda() | 0.076 | 0.337 | 1.634 | 6.588 | | | +| shellSortClassic() | 0.075 | 0.314 | 1.730 | 6.950 | | | +| shellSortKnuth() | 0.100 | 0.330 | 1.455 | 5.634 | | | +| shellSortTokuda() | 0.075 | 0.337 | 1.645 | 6.555 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.165 | 0.537 | 2.209 | 8.215 | | | -| combSort13m() | 0.164 | 0.557 | 2.219 | 8.134 | | | -| combSort133() | 0.086 | 0.389 | 1.996 | 7.767 | | | -| combSort133m() | 0.091 | 0.423 | 1.997 | 7.729 | | | +| combSort13() | 0.162 | 0.538 | 2.234 | 8.211 | | | +| combSort13m() | 0.164 | 0.559 | 2.266 | 8.232 | | | +| combSort133() | 0.088 | 0.390 | 1.996 | 7.672 | | | +| combSort133m() | 0.087 | 0.424 | 1.993 | 7.763 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.099 | 0.375 | 1.619 | 5.711 | | | -| quickSortMedian() | 0.119 | 0.427 | 1.748 | 5.976 | | | -| quickSortMdnSwppd() | 0.094 | 0.341 | 1.401 | 4.974 | | | +| quickSortMiddle() | 0.098 | 0.372 | 1.617 | 5.667 | | | +| quickSortMedian() | 0.116 | 0.432 | 1.720 | 5.956 | | | +| quickSortMdnSwppd() | 0.090 | 0.345 | 1.391 | 4.914 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.200 | 0.839 | 3.661 | 12.974 | | | +| qsort() | 0.202 | 0.900 | 3.674 | 13.046 | | | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -138,24 +143,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.039 | 0.357 | 3.984 | 36.967 | 429.557 | | -| insertionSort() | 0.014 | 0.095 | 0.880 | 8.132 | 87.197 | | -| selectionSort() | 0.023 | 0.159 | 1.620 | 14.279 | 157.547 | | +| bubbleSort() | 0.031 | 0.282 | 3.405 | 32.272 | 363.409 | | +| insertionSort() | 0.016 | 0.088 | 0.941 | 8.144 | 89.678 | | +| selectionSort() | 0.024 | 0.162 | 1.629 | 14.306 | 157.639 | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.016 | 0.064 | 0.349 | 1.405 | 5.861 | 22.452 | -| shellSortKnuth() | 0.019 | 0.067 | 0.289 | 1.153 | 5.111 | 19.448 | -| shellSortTokuda() | 0.020 | 0.081 | 0.390 | 1.556 | 6.673 | 24.187 | +| shellSortClassic() | 0.016 | 0.064 | 0.349 | 1.408 | 5.912 | 22.251 | +| shellSortKnuth() | 0.019 | 0.065 | 0.298 | 1.154 | 5.074 | 19.321 | +| shellSortTokuda() | 0.019 | 0.081 | 0.390 | 1.568 | 6.690 | 24.190 | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.035 | 0.118 | 0.496 | 1.859 | 8.180 | 29.661 | -| combSort13m() | 0.035 | 0.124 | 0.512 | 1.882 | 7.892 | 28.483 | -| combSort133() | 0.020 | 0.090 | 0.454 | 1.764 | 7.897 | 26.989 | -| combSort133m() | 0.021 | 0.097 | 0.454 | 1.752 | 7.623 | 27.649 | +| combSort13() | 0.035 | 0.121 | 0.532 | 1.934 | 8.697 | 31.638 | +| combSort13m() | 0.036 | 0.128 | 0.534 | 1.931 | 8.274 | 29.531 | +| combSort133() | 0.021 | 0.090 | 0.452 | 1.825 | 8.259 | 28.640 | +| combSort133m() | 0.021 | 0.100 | 0.470 | 1.822 | 7.949 | 28.592 | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.021 | 0.073 | 0.315 | 1.077 | 4.211 | 14.031 | -| quickSortMedian() | 0.026 | 0.088 | 0.344 | 1.161 | 4.343 | 14.455 | -| quickSortMdnSwppd() | 0.020 | 0.070 | 0.285 | 1.001 | 3.783 | 12.630 | +| quickSortMiddle() | 0.022 | 0.077 | 0.312 | 1.097 | 4.246 | 14.192 | +| quickSortMedian() | 0.026 | 0.088 | 0.338 | 1.158 | 4.387 | 14.495 | +| quickSortMdnSwppd() | 0.020 | 0.069 | 0.281 | 0.980 | 3.720 | 12.486 | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.054 | 0.213 | 0.886 | 3.215 | 12.678 | 42.791 | +| qsort() | 0.052 | 0.204 | 0.873 | 3.088 | 12.102 | 41.217 | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -171,24 +176,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.018 | 0.161 | 2.105 | 19.955 | 225.639 | | -| insertionSort() | 0.010 | 0.054 | 0.495 | 4.486 | 48.616 | | -| selectionSort() | 0.017 | 0.116 | 1.167 | 10.197 | 112.180 | | +| bubbleSort() | 0.022 | 0.169 | 2.156 | 20.662 | 230.118 | | +| insertionSort() | 0.009 | 0.054 | 0.488 | 4.278 | 45.077 | | +| selectionSort() | 0.016 | 0.102 | 1.023 | 8.931 | 98.184 | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.014 | 0.058 | 0.324 | 1.284 | 5.427 | 20.852 | -| shellSortKnuth() | 0.014 | 0.059 | 0.305 | 1.236 | 5.604 | 21.566 | -| shellSortTokuda() | 0.011 | 0.047 | 0.226 | 0.901 | 3.904 | 14.199 | +| shellSortClassic() | 0.014 | 0.057 | 0.305 | 1.243 | 5.157 | 19.747 | +| shellSortKnuth() | 0.013 | 0.057 | 0.276 | 1.131 | 5.058 | 19.403 | +| shellSortTokuda() | 0.012 | 0.048 | 0.226 | 0.905 | 3.888 | 14.123 | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.019 | 0.087 | 0.442 | 1.770 | 7.895 | 28.862 | -| combSort13m() | 0.018 | 0.087 | 0.430 | 1.697 | 7.380 | 26.657 | -| combSort133() | 0.018 | 0.085 | 0.417 | 1.649 | 7.630 | 26.148 | -| combSort133m() | 0.019 | 0.089 | 0.419 | 1.619 | 7.151 | 25.380 | +| combSort13() | 0.017 | 0.080 | 0.396 | 1.601 | 7.173 | 26.248 | +| combSort13m() | 0.018 | 0.084 | 0.416 | 1.585 | 6.998 | 25.575 | +| combSort133() | 0.016 | 0.073 | 0.378 | 1.481 | 6.775 | 22.826 | +| combSort133m() | 0.017 | 0.080 | 0.382 | 1.496 | 6.436 | 23.289 | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.019 | 0.067 | 0.278 | 0.990 | 3.835 | 13.145 | -| quickSortMedian() | 0.020 | 0.076 | 0.311 | 1.101 | 4.212 | 14.381 | -| quickSortMdnSwppd() | 0.015 | 0.056 | 0.228 | 0.836 | 3.285 | 11.265 | +| quickSortMiddle() | 0.017 | 0.064 | 0.260 | 0.941 | 3.559 | 12.330 | +| quickSortMedian() | 0.020 | 0.070 | 0.280 | 0.994 | 3.769 | 12.632 | +| quickSortMdnSwppd() | 0.015 | 0.056 | 0.236 | 0.855 | 3.318 | 11.345 | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.034 | 0.149 | 0.615 | 2.221 | 8.921 | 30.627 | +| qsort() | 0.033 | 0.132 | 0.609 | 2.251 | 8.882 | 30.578 | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -204,24 +209,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.021 | 0.192 | 2.231 | 20.143 | 225.651 | | -| insertionSort() | 0.009 | 0.037 | 0.362 | 3.220 | 34.646 | | -| selectionSort() | 0.017 | 0.085 | 0.892 | 7.930 | 87.723 | | +| bubbleSort() | 0.022 | 0.181 | 2.116 | 19.118 | 213.942 | | +| insertionSort() | 0.011 | 0.037 | 0.361 | 3.222 | 34.652 | | +| selectionSort() | 0.017 | 0.092 | 0.961 | 8.500 | 93.980 | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.011 | 0.039 | 0.215 | 0.878 | 3.609 | 13.789 | -| shellSortKnuth() | 0.010 | 0.036 | 0.172 | 0.690 | 3.022 | 11.304 | -| shellSortTokuda() | 0.009 | 0.039 | 0.183 | 0.735 | 3.140 | 11.366 | +| shellSortClassic() | 0.010 | 0.039 | 0.215 | 0.878 | 3.610 | 13.789 | +| shellSortKnuth() | 0.010 | 0.036 | 0.172 | 0.690 | 3.021 | 11.306 | +| shellSortTokuda() | 0.009 | 0.040 | 0.188 | 0.756 | 3.227 | 11.678 | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.013 | 0.048 | 0.219 | 0.846 | 3.711 | 13.689 | -| combSort13m() | 0.014 | 0.051 | 0.222 | 0.840 | 3.622 | 13.104 | +| combSort13() | 0.013 | 0.048 | 0.219 | 0.846 | 3.712 | 13.695 | +| combSort13m() | 0.013 | 0.051 | 0.223 | 0.840 | 3.625 | 13.102 | | combSort133() | 0.010 | 0.040 | 0.208 | 0.796 | 3.571 | 12.430 | -| combSort133m() | 0.010 | 0.044 | 0.206 | 0.793 | 3.465 | 12.387 | +| combSort133m() | 0.010 | 0.045 | 0.206 | 0.793 | 3.466 | 12.387 | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.013 | 0.045 | 0.185 | 0.651 | 2.519 | 8.307 | -| quickSortMedian() | 0.016 | 0.052 | 0.200 | 0.677 | 2.551 | 8.403 | -| quickSortMdnSwppd() | 0.012 | 0.039 | 0.159 | 0.558 | 2.122 | 7.109 | +| quickSortMiddle() | 0.013 | 0.045 | 0.185 | 0.650 | 2.518 | 8.303 | +| quickSortMedian() | 0.016 | 0.052 | 0.203 | 0.684 | 2.574 | 8.470 | +| quickSortMdnSwppd() | 0.012 | 0.039 | 0.160 | 0.560 | 2.128 | 7.129 | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.028 | 0.092 | 0.416 | 1.516 | 6.010 | 20.789 | +| qsort() | 0.027 | 0.092 | 0.417 | 1.515 | 6.009 | 20.782 | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -237,24 +242,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.006 | 0.049 | 0.622 | 5.704 | 63.678 | | -| insertionSort() | 0.004 | 0.017 | 0.157 | 1.295 | 15.081 | | -| selectionSort() | 0.005 | 0.032 | 0.341 | 3.035 | 33.618 | | +| bubbleSort() | 0.006 | 0.057 | 0.626 | 5.670 | 64.461 | | +| insertionSort() | 0.004 | 0.017 | 0.156 | 1.285 | 14.827 | | +| selectionSort() | 0.006 | 0.030 | 0.304 | 2.671 | 29.458 | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.004 | 0.014 | 0.077 | 0.302 | 1.283 | 4.861 | -| shellSortKnuth() | 0.004 | 0.013 | 0.062 | 0.247 | 1.110 | 4.155 | -| shellSortTokuda() | 0.004 | 0.014 | 0.065 | 0.263 | 1.115 | 4.034 | +| shellSortClassic() | 0.004 | 0.014 | 0.076 | 0.304 | 1.277 | 4.899 | +| shellSortKnuth() | 0.004 | 0.013 | 0.062 | 0.245 | 1.102 | 4.205 | +| shellSortTokuda() | 0.004 | 0.014 | 0.064 | 0.261 | 1.114 | 4.029 | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.005 | 0.019 | 0.095 | 0.377 | 1.688 | 6.257 | -| combSort13m() | 0.005 | 0.020 | 0.097 | 0.373 | 1.641 | 5.996 | -| combSort133() | 0.005 | 0.019 | 0.091 | 0.365 | 1.644 | 5.650 | -| combSort133m() | 0.005 | 0.021 | 0.096 | 0.368 | 1.599 | 5.661 | +| combSort13() | 0.005 | 0.019 | 0.095 | 0.376 | 1.704 | 6.222 | +| combSort13m() | 0.006 | 0.020 | 0.098 | 0.381 | 1.640 | 5.996 | +| combSort133() | 0.005 | 0.019 | 0.093 | 0.368 | 1.649 | 5.668 | +| combSort133m() | 0.005 | 0.021 | 0.095 | 0.360 | 1.588 | 5.684 | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.005 | 0.018 | 0.070 | 0.249 | 0.975 | 3.346 | -| quickSortMedian() | 0.006 | 0.018 | 0.072 | 0.255 | 0.967 | 3.249 | -| quickSortMdnSwppd() | 0.004 | 0.014 | 0.059 | 0.211 | 0.826 | 2.803 | +| quickSortMiddle() | 0.005 | 0.017 | 0.071 | 0.252 | 0.987 | 3.427 | +| quickSortMedian() | 0.006 | 0.018 | 0.073 | 0.255 | 0.969 | 3.263 | +| quickSortMdnSwppd() | 0.004 | 0.014 | 0.059 | 0.209 | 0.815 | 2.804 | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.008 | 0.032 | 0.143 | 0.524 | 2.099 | 7.221 | +| qsort() | 0.008 | 0.033 | 0.144 | 0.522 | 2.131 | 7.245 | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -271,24 +276,24 @@ when sorting different array sizes. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.009 | 0.079 | 0.824 | 8.469 | 98.471 | | -| insertionSort() | 0.006 | 0.041 | 0.394 | 3.390 | 36.820 | | -| selectionSort() | 0.008 | 0.057 | 0.590 | 5.215 | 57.558 | | +| bubbleSort() | 0.009 | 0.083 | 0.945 | 9.217 | 102.362 | | +| insertionSort() | 0.005 | 0.040 | 0.399 | 3.290 | 36.427 | | +| selectionSort() | 0.009 | 0.065 | 0.653 | 5.715 | 62.889 | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.007 | 0.029 | 0.162 | 0.648 | 2.712 | 10.394 | -| shellSortKnuth() | 0.006 | 0.027 | 0.133 | 0.531 | 2.339 | 8.903 | -| shellSortTokuda() | 0.007 | 0.028 | 0.136 | 0.539 | 2.314 | 8.366 | +| shellSortClassic() | 0.007 | 0.029 | 0.159 | 0.648 | 2.694 | 10.372 | +| shellSortKnuth() | 0.006 | 0.027 | 0.131 | 0.526 | 2.345 | 8.972 | +| shellSortTokuda() | 0.007 | 0.028 | 0.135 | 0.539 | 2.312 | 8.365 | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.008 | 0.036 | 0.182 | 0.722 | 3.233 | 11.887 | -| combSort13m() | 0.008 | 0.038 | 0.186 | 0.725 | 3.139 | 11.431 | -| combSort133() | 0.008 | 0.035 | 0.174 | 0.698 | 3.101 | 10.902 | -| combSort133m() | 0.008 | 0.038 | 0.180 | 0.710 | 3.030 | 10.801 | +| combSort13() | 0.008 | 0.037 | 0.182 | 0.720 | 3.234 | 11.948 | +| combSort13m() | 0.008 | 0.038 | 0.182 | 0.721 | 3.146 | 11.470 | +| combSort133() | 0.008 | 0.035 | 0.175 | 0.693 | 3.142 | 10.841 | +| combSort133m() | 0.008 | 0.038 | 0.179 | 0.700 | 3.037 | 10.841 | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.007 | 0.026 | 0.109 | 0.388 | 1.520 | 5.278 | -| quickSortMedian() | 0.009 | 0.030 | 0.122 | 0.423 | 1.590 | 5.387 | -| quickSortMdnSwppd() | 0.007 | 0.025 | 0.100 | 0.365 | 1.412 | 4.752 | +| quickSortMiddle() | 0.007 | 0.026 | 0.108 | 0.399 | 1.543 | 5.324 | +| quickSortMedian() | 0.009 | 0.030 | 0.122 | 0.414 | 1.598 | 5.353 | +| quickSortMdnSwppd() | 0.007 | 0.025 | 0.103 | 0.357 | 1.403 | 4.750 | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.017 | 0.073 | 0.315 | 1.156 | 4.576 | 15.732 | +| qsort() | 0.017 | 0.071 | 0.317 | 1.154 | 4.579 | 15.830 | +---------------------+-------+-------+--------+---------+---------+---------+ ``` diff --git a/examples/AutoBenchmark/esp32.txt b/examples/AutoBenchmark/esp32.txt index 07495aa..49da306 100644 --- a/examples/AutoBenchmark/esp32.txt +++ b/examples/AutoBenchmark/esp32.txt @@ -1,83 +1,83 @@ BENCHMARKS -bubbleSort() 10 0.004 0.006 0.008 3 -bubbleSort() 30 0.039 0.049 0.057 3 -bubbleSort() 100 0.592 0.622 0.640 3 -bubbleSort() 300 5.452 5.704 5.860 3 -bubbleSort() 1000 62.985 63.678 64.192 3 -insertionSort() 10 0.002 0.004 0.006 3 -insertionSort() 30 0.015 0.017 0.018 3 -insertionSort() 100 0.143 0.157 0.173 3 -insertionSort() 300 1.263 1.295 1.343 3 -insertionSort() 1000 14.992 15.081 15.257 3 -selectionSort() 10 0.004 0.005 0.007 3 -selectionSort() 30 0.032 0.032 0.033 3 -selectionSort() 100 0.338 0.341 0.346 3 -selectionSort() 300 3.035 3.035 3.035 3 -selectionSort() 1000 33.613 33.618 33.620 3 -shellSortClassic() 10 0.003 0.004 0.006 20 -shellSortClassic() 30 0.013 0.014 0.016 20 -shellSortClassic() 100 0.071 0.077 0.087 20 -shellSortClassic() 300 0.294 0.302 0.318 20 -shellSortClassic() 1000 1.250 1.283 1.347 20 -shellSortClassic() 3000 4.675 4.861 5.049 20 -shellSortKnuth() 10 0.003 0.004 0.008 20 -shellSortKnuth() 30 0.011 0.013 0.015 20 -shellSortKnuth() 100 0.058 0.062 0.070 20 -shellSortKnuth() 300 0.236 0.247 0.259 20 -shellSortKnuth() 1000 1.067 1.110 1.203 20 -shellSortKnuth() 3000 3.935 4.155 4.279 20 -shellSortTokuda() 10 0.003 0.004 0.008 20 -shellSortTokuda() 30 0.013 0.014 0.023 20 -shellSortTokuda() 100 0.062 0.065 0.075 20 -shellSortTokuda() 300 0.255 0.263 0.274 20 -shellSortTokuda() 1000 1.100 1.115 1.144 20 -shellSortTokuda() 3000 4.003 4.034 4.061 20 -combSort13() 10 0.004 0.005 0.008 20 -combSort13() 30 0.018 0.019 0.021 20 -combSort13() 100 0.092 0.095 0.100 20 -combSort13() 300 0.358 0.377 0.410 20 -combSort13() 1000 1.571 1.688 1.789 20 -combSort13() 3000 5.826 6.257 6.734 20 -combSort13m() 10 0.003 0.005 0.008 20 -combSort13m() 30 0.020 0.020 0.022 20 -combSort13m() 100 0.092 0.097 0.107 20 -combSort13m() 300 0.358 0.373 0.389 20 -combSort13m() 1000 1.565 1.641 1.714 20 -combSort13m() 3000 5.827 5.996 6.053 20 -combSort133() 10 0.004 0.005 0.008 20 +bubbleSort() 10 0.004 0.006 0.009 3 +bubbleSort() 30 0.052 0.057 0.060 3 +bubbleSort() 100 0.605 0.626 0.666 3 +bubbleSort() 300 5.372 5.670 5.840 3 +bubbleSort() 1000 62.177 64.461 65.873 3 +insertionSort() 10 0.003 0.004 0.007 3 +insertionSort() 30 0.014 0.017 0.022 3 +insertionSort() 100 0.145 0.156 0.166 3 +insertionSort() 300 1.277 1.285 1.290 3 +insertionSort() 1000 14.567 14.827 15.048 3 +selectionSort() 10 0.004 0.006 0.008 3 +selectionSort() 30 0.029 0.030 0.030 3 +selectionSort() 100 0.301 0.304 0.309 3 +selectionSort() 300 2.671 2.671 2.672 3 +selectionSort() 1000 29.455 29.458 29.463 3 +shellSortClassic() 10 0.003 0.004 0.007 20 +shellSortClassic() 30 0.013 0.014 0.015 20 +shellSortClassic() 100 0.069 0.076 0.082 20 +shellSortClassic() 300 0.295 0.304 0.323 20 +shellSortClassic() 1000 1.243 1.277 1.339 20 +shellSortClassic() 3000 4.709 4.899 5.132 20 +shellSortKnuth() 10 0.003 0.004 0.007 20 +shellSortKnuth() 30 0.012 0.013 0.016 20 +shellSortKnuth() 100 0.059 0.062 0.066 20 +shellSortKnuth() 300 0.235 0.245 0.255 20 +shellSortKnuth() 1000 1.065 1.102 1.179 20 +shellSortKnuth() 3000 3.994 4.205 4.379 20 +shellSortTokuda() 10 0.003 0.004 0.010 20 +shellSortTokuda() 30 0.013 0.014 0.015 20 +shellSortTokuda() 100 0.061 0.064 0.072 20 +shellSortTokuda() 300 0.250 0.261 0.268 20 +shellSortTokuda() 1000 1.097 1.114 1.136 20 +shellSortTokuda() 3000 3.985 4.029 4.075 20 +combSort13() 10 0.004 0.005 0.007 20 +combSort13() 30 0.018 0.019 0.022 20 +combSort13() 100 0.092 0.095 0.107 20 +combSort13() 300 0.358 0.376 0.403 20 +combSort13() 1000 1.564 1.704 1.864 20 +combSort13() 3000 5.819 6.222 6.509 20 +combSort13m() 10 0.004 0.006 0.013 20 +combSort13m() 30 0.020 0.020 0.023 20 +combSort13m() 100 0.092 0.098 0.107 20 +combSort13m() 300 0.358 0.381 0.411 20 +combSort13m() 1000 1.572 1.640 1.722 20 +combSort13m() 3000 5.827 5.996 6.277 20 +combSort133() 10 0.004 0.005 0.007 20 combSort133() 30 0.018 0.019 0.021 20 -combSort133() 100 0.085 0.091 0.108 20 -combSort133() 300 0.341 0.365 0.409 20 -combSort133() 1000 1.519 1.644 1.812 20 -combSort133() 3000 5.442 5.650 6.125 20 -combSort133m() 10 0.004 0.005 0.007 20 +combSort133() 100 0.085 0.093 0.123 20 +combSort133() 300 0.342 0.368 0.394 20 +combSort133() 1000 1.513 1.649 1.819 20 +combSort133() 3000 5.442 5.668 5.899 20 +combSort133m() 10 0.004 0.005 0.008 20 combSort133m() 30 0.020 0.021 0.028 20 -combSort133m() 100 0.092 0.096 0.108 20 -combSort133m() 300 0.341 0.368 0.394 20 -combSort133m() 1000 1.587 1.599 1.670 20 -combSort133m() 3000 5.442 5.661 6.350 20 -quickSortMiddle() 10 0.004 0.005 0.008 20 -quickSortMiddle() 30 0.014 0.018 0.027 20 -quickSortMiddle() 100 0.062 0.070 0.083 20 -quickSortMiddle() 300 0.218 0.249 0.296 20 -quickSortMiddle() 1000 0.886 0.975 1.064 20 -quickSortMiddle() 3000 3.149 3.346 3.712 20 -quickSortMedian() 10 0.005 0.006 0.010 20 -quickSortMedian() 30 0.016 0.018 0.020 20 -quickSortMedian() 100 0.068 0.072 0.083 20 -quickSortMedian() 300 0.235 0.255 0.271 20 -quickSortMedian() 1000 0.920 0.967 1.054 20 -quickSortMedian() 3000 3.106 3.249 3.393 20 -quickSortMedianSwapped() 10 0.003 0.004 0.011 20 -quickSortMedianSwapped() 30 0.013 0.014 0.016 20 -quickSortMedianSwapped() 100 0.056 0.059 0.068 20 -quickSortMedianSwapped() 300 0.200 0.211 0.224 20 -quickSortMedianSwapped() 1000 0.794 0.826 0.898 20 -quickSortMedianSwapped() 3000 2.694 2.803 2.989 20 -qsort() 10 0.006 0.008 0.017 20 -qsort() 30 0.029 0.032 0.042 20 -qsort() 100 0.132 0.143 0.160 20 -qsort() 300 0.509 0.524 0.551 20 -qsort() 1000 2.043 2.099 2.169 20 -qsort() 3000 7.136 7.221 7.391 20 +combSort133m() 100 0.092 0.095 0.108 20 +combSort133m() 300 0.341 0.360 0.372 20 +combSort133m() 1000 1.512 1.588 1.595 20 +combSort133m() 3000 5.442 5.684 6.582 20 +quickSortMiddle() 10 0.004 0.005 0.011 20 +quickSortMiddle() 30 0.015 0.017 0.019 20 +quickSortMiddle() 100 0.064 0.071 0.077 20 +quickSortMiddle() 300 0.227 0.252 0.287 20 +quickSortMiddle() 1000 0.915 0.987 1.165 20 +quickSortMiddle() 3000 3.140 3.427 3.707 20 +quickSortMedian() 10 0.004 0.006 0.010 20 +quickSortMedian() 30 0.016 0.018 0.026 20 +quickSortMedian() 100 0.068 0.073 0.080 20 +quickSortMedian() 300 0.237 0.255 0.275 20 +quickSortMedian() 1000 0.930 0.969 1.027 20 +quickSortMedian() 3000 3.144 3.263 3.479 20 +quickSortMedianSwapped() 10 0.004 0.004 0.009 20 +quickSortMedianSwapped() 30 0.012 0.014 0.016 20 +quickSortMedianSwapped() 100 0.054 0.059 0.075 20 +quickSortMedianSwapped() 300 0.198 0.209 0.231 20 +quickSortMedianSwapped() 1000 0.789 0.815 0.857 20 +quickSortMedianSwapped() 3000 2.682 2.804 2.930 20 +qsort() 10 0.006 0.008 0.014 20 +qsort() 30 0.029 0.033 0.044 20 +qsort() 100 0.135 0.144 0.171 20 +qsort() 300 0.507 0.522 0.557 20 +qsort() 1000 2.071 2.131 2.223 20 +qsort() 3000 7.140 7.245 7.592 20 END diff --git a/examples/AutoBenchmark/esp8266.txt b/examples/AutoBenchmark/esp8266.txt index 3e28d90..016e1be 100644 --- a/examples/AutoBenchmark/esp8266.txt +++ b/examples/AutoBenchmark/esp8266.txt @@ -1,83 +1,83 @@ BENCHMARKS -bubbleSort() 10 0.014 0.021 0.031 3 -bubbleSort() 30 0.184 0.192 0.199 3 -bubbleSort() 100 2.177 2.231 2.318 3 -bubbleSort() 300 18.915 20.143 21.185 3 -bubbleSort() 1000 222.008 225.651 230.578 3 -insertionSort() 10 0.006 0.009 0.013 3 -insertionSort() 30 0.036 0.037 0.039 3 -insertionSort() 100 0.338 0.362 0.383 3 -insertionSort() 300 3.106 3.220 3.331 3 -insertionSort() 1000 34.432 34.646 35.043 3 -selectionSort() 10 0.011 0.017 0.028 3 -selectionSort() 30 0.084 0.085 0.085 3 -selectionSort() 100 0.891 0.892 0.892 3 -selectionSort() 300 7.924 7.930 7.939 3 -selectionSort() 1000 87.681 87.723 87.751 3 -shellSortClassic() 10 0.009 0.011 0.024 20 +bubbleSort() 10 0.013 0.022 0.034 3 +bubbleSort() 30 0.175 0.181 0.188 3 +bubbleSort() 100 2.065 2.116 2.198 3 +bubbleSort() 300 17.936 19.118 20.139 3 +bubbleSort() 1000 210.481 213.942 218.615 3 +insertionSort() 10 0.006 0.011 0.020 3 +insertionSort() 30 0.036 0.037 0.038 3 +insertionSort() 100 0.335 0.361 0.383 3 +insertionSort() 300 3.109 3.222 3.335 3 +insertionSort() 1000 34.450 34.652 35.054 3 +selectionSort() 10 0.013 0.017 0.024 3 +selectionSort() 30 0.092 0.092 0.092 3 +selectionSort() 100 0.959 0.961 0.963 3 +selectionSort() 300 8.498 8.500 8.502 3 +selectionSort() 1000 93.959 93.980 93.993 3 +shellSortClassic() 10 0.009 0.010 0.025 20 shellSortClassic() 30 0.037 0.039 0.041 20 shellSortClassic() 100 0.205 0.215 0.226 20 -shellSortClassic() 300 0.848 0.878 0.907 20 -shellSortClassic() 1000 3.506 3.609 3.755 20 -shellSortClassic() 3000 13.416 13.789 14.644 20 -shellSortKnuth() 10 0.008 0.010 0.029 20 +shellSortClassic() 300 0.847 0.878 0.907 20 +shellSortClassic() 1000 3.505 3.610 3.769 20 +shellSortClassic() 3000 13.417 13.789 14.640 20 +shellSortKnuth() 10 0.008 0.010 0.028 20 shellSortKnuth() 30 0.033 0.036 0.041 20 -shellSortKnuth() 100 0.159 0.172 0.186 20 -shellSortKnuth() 300 0.664 0.690 0.722 20 -shellSortKnuth() 1000 2.882 3.022 3.250 20 -shellSortKnuth() 3000 10.877 11.304 12.011 20 +shellSortKnuth() 100 0.159 0.172 0.185 20 +shellSortKnuth() 300 0.664 0.690 0.719 20 +shellSortKnuth() 1000 2.882 3.021 3.250 20 +shellSortKnuth() 3000 10.914 11.306 12.014 20 shellSortTokuda() 10 0.008 0.009 0.020 20 -shellSortTokuda() 30 0.036 0.039 0.042 20 -shellSortTokuda() 100 0.177 0.183 0.188 20 -shellSortTokuda() 300 0.724 0.735 0.745 20 -shellSortTokuda() 1000 3.088 3.140 3.211 20 -shellSortTokuda() 3000 11.265 11.366 11.473 20 +shellSortTokuda() 30 0.037 0.040 0.042 20 +shellSortTokuda() 100 0.181 0.188 0.194 20 +shellSortTokuda() 300 0.745 0.756 0.766 20 +shellSortTokuda() 1000 3.177 3.227 3.275 20 +shellSortTokuda() 3000 11.566 11.678 11.781 20 combSort13() 10 0.012 0.013 0.024 20 combSort13() 30 0.045 0.048 0.051 20 combSort13() 100 0.196 0.219 0.247 20 combSort13() 300 0.803 0.846 0.951 20 -combSort13() 1000 3.611 3.711 4.106 20 -combSort13() 3000 12.774 13.689 14.229 20 -combSort13m() 10 0.011 0.014 0.028 20 +combSort13() 1000 3.611 3.712 4.103 20 +combSort13() 3000 12.762 13.695 14.261 20 +combSort13m() 10 0.011 0.013 0.028 20 combSort13m() 30 0.050 0.051 0.056 20 -combSort13m() 100 0.213 0.222 0.247 20 -combSort13m() 300 0.804 0.840 0.904 20 -combSort13m() 1000 3.611 3.622 3.775 20 -combSort13m() 3000 12.754 13.104 13.735 20 -combSort133() 10 0.008 0.010 0.017 20 +combSort13m() 100 0.213 0.223 0.247 20 +combSort13m() 300 0.804 0.840 0.903 20 +combSort13m() 1000 3.611 3.625 3.783 20 +combSort13m() 3000 12.754 13.102 13.747 20 +combSort133() 10 0.008 0.010 0.020 20 combSort133() 30 0.039 0.040 0.040 20 -combSort133() 100 0.188 0.208 0.270 20 +combSort133() 100 0.188 0.208 0.271 20 combSort133() 300 0.751 0.796 0.997 20 -combSort133() 1000 3.315 3.571 3.804 20 -combSort133() 3000 11.911 12.430 12.895 20 -combSort133m() 10 0.009 0.010 0.017 20 -combSort133m() 30 0.043 0.044 0.049 20 -combSort133m() 100 0.204 0.206 0.221 20 +combSort133() 1000 3.315 3.571 3.825 20 +combSort133() 3000 11.915 12.430 12.923 20 +combSort133m() 10 0.009 0.010 0.021 20 +combSort133m() 30 0.043 0.045 0.058 20 +combSort133m() 100 0.204 0.206 0.220 20 combSort133m() 300 0.753 0.793 0.804 20 -combSort133m() 1000 3.317 3.465 3.497 20 -combSort133m() 3000 11.916 12.387 13.395 20 +combSort133m() 1000 3.316 3.466 3.505 20 +combSort133m() 3000 11.914 12.387 13.381 20 quickSortMiddle() 10 0.011 0.013 0.027 20 -quickSortMiddle() 30 0.039 0.045 0.052 20 -quickSortMiddle() 100 0.162 0.185 0.213 20 -quickSortMiddle() 300 0.602 0.651 0.755 20 -quickSortMiddle() 1000 2.359 2.519 2.770 20 -quickSortMiddle() 3000 7.920 8.307 8.785 20 +quickSortMiddle() 30 0.039 0.045 0.053 20 +quickSortMiddle() 100 0.161 0.185 0.213 20 +quickSortMiddle() 300 0.602 0.650 0.755 20 +quickSortMiddle() 1000 2.359 2.518 2.762 20 +quickSortMiddle() 3000 7.905 8.303 8.786 20 quickSortMedian() 10 0.013 0.016 0.035 20 quickSortMedian() 30 0.046 0.052 0.055 20 -quickSortMedian() 100 0.186 0.200 0.216 20 -quickSortMedian() 300 0.640 0.677 0.715 20 -quickSortMedian() 1000 2.461 2.551 2.642 20 -quickSortMedian() 3000 8.200 8.403 8.587 20 -quickSortMedianSwapped() 10 0.009 0.012 0.035 20 -quickSortMedianSwapped() 30 0.034 0.039 0.045 20 -quickSortMedianSwapped() 100 0.150 0.159 0.186 20 -quickSortMedianSwapped() 300 0.530 0.558 0.597 20 -quickSortMedianSwapped() 1000 2.029 2.122 2.304 20 -quickSortMedianSwapped() 3000 6.933 7.109 7.609 20 -qsort() 10 0.017 0.028 0.150 20 +quickSortMedian() 100 0.189 0.203 0.219 20 +quickSortMedian() 300 0.646 0.684 0.721 20 +quickSortMedian() 1000 2.484 2.574 2.665 20 +quickSortMedian() 3000 8.280 8.470 8.656 20 +quickSortMedianSwapped() 10 0.009 0.012 0.031 20 +quickSortMedianSwapped() 30 0.035 0.039 0.045 20 +quickSortMedianSwapped() 100 0.150 0.160 0.176 20 +quickSortMedianSwapped() 300 0.532 0.560 0.600 20 +quickSortMedianSwapped() 1000 2.035 2.128 2.313 20 +quickSortMedianSwapped() 3000 6.956 7.129 7.623 20 +qsort() 10 0.017 0.027 0.143 20 qsort() 30 0.085 0.092 0.105 20 -qsort() 100 0.399 0.416 0.450 20 -qsort() 300 1.480 1.516 1.694 20 -qsort() 1000 5.884 6.010 6.152 20 -qsort() 3000 20.491 20.789 21.354 20 +qsort() 100 0.399 0.417 0.472 20 +qsort() 300 1.480 1.515 1.694 20 +qsort() 1000 5.899 6.009 6.148 20 +qsort() 3000 20.499 20.782 21.323 20 END diff --git a/examples/AutoBenchmark/generate_readme.py b/examples/AutoBenchmark/generate_readme.py index 7967a22..16ee0af 100755 --- a/examples/AutoBenchmark/generate_readme.py +++ b/examples/AutoBenchmark/generate_readme.py @@ -79,6 +79,11 @@ * The C-library `qsort()` is far slower than the C++ version because it uses a callback to a comparison function through a function pointer. +**v0.2+** + +* No performance change after rerouting 2-argument sorting functions into + the 3-argument versions using a default lambda expression. + ## Results The following results show the runtime of each sorting function in milliseconds, diff --git a/examples/AutoBenchmark/micro.txt b/examples/AutoBenchmark/micro.txt index 5b18b42..7334f61 100644 --- a/examples/AutoBenchmark/micro.txt +++ b/examples/AutoBenchmark/micro.txt @@ -1,58 +1,58 @@ BENCHMARKS -bubbleSort() 10 0.096 0.115 0.140 3 -bubbleSort() 30 1.004 1.083 1.128 3 -bubbleSort() 100 12.076 12.773 13.428 3 -bubbleSort() 300 118.872 121.179 123.004 3 -insertionSort() 10 0.040 0.041 0.044 3 -insertionSort() 30 0.276 0.291 0.312 3 -insertionSort() 100 2.396 2.527 2.616 3 -insertionSort() 300 20.624 21.032 21.504 3 -selectionSort() 10 0.076 0.081 0.084 3 -selectionSort() 30 0.552 0.561 0.568 3 -selectionSort() 100 5.628 5.632 5.636 3 -selectionSort() 300 49.144 49.153 49.160 3 -shellSortClassic() 10 0.064 0.074 0.084 25 -shellSortClassic() 30 0.288 0.310 0.328 25 -shellSortClassic() 100 1.612 1.712 1.864 25 -shellSortClassic() 300 6.724 6.912 7.196 25 -shellSortKnuth() 10 0.092 0.101 0.116 25 -shellSortKnuth() 30 0.312 0.339 0.396 25 -shellSortKnuth() 100 1.368 1.445 1.568 25 -shellSortKnuth() 300 5.364 5.601 5.872 25 -shellSortTokuda() 10 0.064 0.076 0.088 25 -shellSortTokuda() 30 0.308 0.337 0.368 25 -shellSortTokuda() 100 1.556 1.634 1.688 25 -shellSortTokuda() 300 6.448 6.588 6.820 25 -combSort13() 10 0.156 0.165 0.192 25 -combSort13() 30 0.496 0.537 0.576 25 -combSort13() 100 1.988 2.209 2.648 25 -combSort13() 300 7.836 8.215 8.808 25 -combSort13m() 10 0.136 0.164 0.204 25 -combSort13m() 30 0.540 0.557 0.624 25 -combSort13m() 100 2.128 2.219 2.364 25 -combSort13m() 300 7.864 8.134 8.376 25 -combSort133() 10 0.080 0.086 0.104 25 -combSort133() 30 0.376 0.389 0.432 25 -combSort133() 100 1.824 1.996 2.404 25 -combSort133() 300 7.332 7.767 8.240 25 -combSort133m() 10 0.080 0.091 0.112 25 -combSort133m() 30 0.408 0.423 0.464 25 -combSort133m() 100 1.952 1.997 2.144 25 -combSort133m() 300 7.312 7.729 8.268 25 -quickSortMiddle() 10 0.084 0.099 0.116 25 -quickSortMiddle() 30 0.340 0.375 0.444 25 -quickSortMiddle() 100 1.444 1.619 1.924 25 -quickSortMiddle() 300 5.196 5.711 6.424 25 -quickSortMedian() 10 0.100 0.119 0.136 25 -quickSortMedian() 30 0.396 0.427 0.480 25 -quickSortMedian() 100 1.632 1.748 1.944 25 -quickSortMedian() 300 5.764 5.976 6.464 25 -quickSortMedianSwapped() 10 0.076 0.094 0.116 25 -quickSortMedianSwapped() 30 0.312 0.341 0.376 25 -quickSortMedianSwapped() 100 1.304 1.401 1.476 25 -quickSortMedianSwapped() 300 4.728 4.974 5.368 25 -qsort() 10 0.160 0.200 0.244 25 -qsort() 30 0.756 0.839 0.984 25 -qsort() 100 3.472 3.661 3.852 25 -qsort() 300 12.516 12.974 13.364 25 +bubbleSort() 10 0.056 0.091 0.140 3 +bubbleSort() 30 1.108 1.136 1.172 3 +bubbleSort() 100 12.496 12.908 13.684 3 +bubbleSort() 300 117.940 120.933 124.088 3 +insertionSort() 10 0.036 0.048 0.056 3 +insertionSort() 30 0.260 0.271 0.284 3 +insertionSort() 100 2.492 2.652 2.744 3 +insertionSort() 300 21.436 22.188 23.432 3 +selectionSort() 10 0.084 0.084 0.084 3 +selectionSort() 30 0.552 0.556 0.560 3 +selectionSort() 100 5.388 5.391 5.392 3 +selectionSort() 300 46.508 46.513 46.524 3 +shellSortClassic() 10 0.068 0.075 0.084 25 +shellSortClassic() 30 0.288 0.314 0.344 25 +shellSortClassic() 100 1.584 1.730 1.820 25 +shellSortClassic() 300 6.676 6.950 7.300 25 +shellSortKnuth() 10 0.092 0.100 0.112 25 +shellSortKnuth() 30 0.304 0.330 0.384 25 +shellSortKnuth() 100 1.376 1.455 1.540 25 +shellSortKnuth() 300 5.388 5.634 5.988 25 +shellSortTokuda() 10 0.068 0.075 0.084 25 +shellSortTokuda() 30 0.312 0.337 0.380 25 +shellSortTokuda() 100 1.572 1.645 1.728 25 +shellSortTokuda() 300 6.364 6.555 6.692 25 +combSort13() 10 0.152 0.162 0.188 25 +combSort13() 30 0.492 0.538 0.632 25 +combSort13() 100 2.124 2.234 2.500 25 +combSort13() 300 7.844 8.211 8.756 25 +combSort13m() 10 0.132 0.164 0.192 25 +combSort13m() 30 0.544 0.559 0.616 25 +combSort13m() 100 2.132 2.266 2.504 25 +combSort13m() 300 7.876 8.232 8.812 25 +combSort133() 10 0.080 0.088 0.108 25 +combSort133() 30 0.372 0.390 0.448 25 +combSort133() 100 1.820 1.996 2.724 25 +combSort133() 300 7.332 7.672 7.888 25 +combSort133m() 10 0.080 0.087 0.100 25 +combSort133m() 30 0.412 0.424 0.464 25 +combSort133m() 100 1.944 1.993 2.136 25 +combSort133m() 300 7.328 7.763 8.296 25 +quickSortMiddle() 10 0.080 0.098 0.112 25 +quickSortMiddle() 30 0.332 0.372 0.428 25 +quickSortMiddle() 100 1.456 1.617 1.908 25 +quickSortMiddle() 300 5.216 5.667 6.756 25 +quickSortMedian() 10 0.088 0.116 0.132 25 +quickSortMedian() 30 0.396 0.432 0.480 25 +quickSortMedian() 100 1.632 1.720 1.868 25 +quickSortMedian() 300 5.708 5.956 6.304 25 +quickSortMedianSwapped() 10 0.076 0.090 0.104 25 +quickSortMedianSwapped() 30 0.316 0.345 0.376 25 +quickSortMedianSwapped() 100 1.264 1.391 1.572 25 +quickSortMedianSwapped() 300 4.708 4.914 5.120 25 +qsort() 10 0.164 0.202 0.272 25 +qsort() 30 0.772 0.900 1.728 25 +qsort() 100 3.496 3.674 3.968 25 +qsort() 300 12.676 13.046 13.680 25 END diff --git a/examples/AutoBenchmark/nano.txt b/examples/AutoBenchmark/nano.txt index c3a2e5c..bde69ec 100644 --- a/examples/AutoBenchmark/nano.txt +++ b/examples/AutoBenchmark/nano.txt @@ -1,58 +1,58 @@ BENCHMARKS -bubbleSort() 10 0.084 0.107 0.132 3 -bubbleSort() 30 0.976 1.077 1.192 3 -bubbleSort() 100 11.836 12.735 13.648 3 -bubbleSort() 300 116.268 116.675 117.240 3 -insertionSort() 10 0.040 0.045 0.056 3 -insertionSort() 30 0.252 0.263 0.276 3 -insertionSort() 100 2.532 2.557 2.572 3 -insertionSort() 300 22.036 22.252 22.396 3 -selectionSort() 10 0.084 0.088 0.096 3 -selectionSort() 30 0.556 0.560 0.564 3 -selectionSort() 100 5.596 5.600 5.604 3 -selectionSort() 300 48.888 48.892 48.896 3 -shellSortClassic() 10 0.068 0.074 0.080 25 -shellSortClassic() 30 0.292 0.310 0.332 25 -shellSortClassic() 100 1.588 1.706 1.824 25 -shellSortClassic() 300 6.640 6.865 7.056 25 -shellSortKnuth() 10 0.092 0.101 0.112 25 -shellSortKnuth() 30 0.300 0.330 0.380 25 -shellSortKnuth() 100 1.340 1.450 1.652 25 -shellSortKnuth() 300 5.444 5.665 6.232 25 -shellSortTokuda() 10 0.068 0.075 0.084 25 -shellSortTokuda() 30 0.312 0.327 0.348 25 -shellSortTokuda() 100 1.556 1.614 1.700 25 -shellSortTokuda() 300 6.424 6.540 6.688 25 -combSort13() 10 0.128 0.160 0.204 25 -combSort13() 30 0.492 0.534 0.576 25 -combSort13() 100 2.120 2.214 2.640 25 -combSort13() 300 7.816 8.167 8.336 25 -combSort13m() 10 0.156 0.165 0.196 25 -combSort13m() 30 0.532 0.550 0.564 25 -combSort13m() 100 2.104 2.219 2.348 25 -combSort13m() 300 7.820 8.181 8.720 25 -combSort133() 10 0.080 0.086 0.108 25 -combSort133() 30 0.380 0.396 0.520 25 -combSort133() 100 1.808 1.944 2.288 25 -combSort133() 300 7.292 7.702 8.232 25 -combSort133m() 10 0.068 0.086 0.100 25 -combSort133m() 30 0.404 0.416 0.428 25 -combSort133m() 100 1.940 1.978 2.120 25 -combSort133m() 300 7.328 7.740 8.228 25 -quickSortMiddle() 10 0.076 0.096 0.112 25 -quickSortMiddle() 30 0.332 0.368 0.428 25 -quickSortMiddle() 100 1.436 1.568 1.808 25 -quickSortMiddle() 300 5.220 5.651 6.248 25 -quickSortMedian() 10 0.100 0.117 0.136 25 -quickSortMedian() 30 0.396 0.431 0.488 25 -quickSortMedian() 100 1.620 1.717 1.864 25 -quickSortMedian() 300 5.652 5.905 6.168 25 -quickSortMedianSwapped() 10 0.080 0.094 0.116 25 -quickSortMedianSwapped() 30 0.312 0.341 0.380 25 -quickSortMedianSwapped() 100 1.296 1.417 1.536 25 -quickSortMedianSwapped() 300 4.672 4.909 5.256 25 -qsort() 10 0.160 0.204 0.232 25 -qsort() 30 0.784 0.855 0.928 25 -qsort() 100 3.424 3.629 3.852 25 -qsort() 300 12.600 13.021 13.828 25 +bubbleSort() 10 0.064 0.099 0.124 3 +bubbleSort() 30 0.696 1.044 1.248 3 +bubbleSort() 100 11.920 12.305 12.540 3 +bubbleSort() 300 116.980 118.589 121.404 3 +insertionSort() 10 0.044 0.049 0.052 3 +insertionSort() 30 0.248 0.251 0.256 3 +insertionSort() 100 2.300 2.463 2.556 3 +insertionSort() 300 20.540 21.288 22.056 3 +selectionSort() 10 0.084 0.087 0.088 3 +selectionSort() 30 0.552 0.553 0.556 3 +selectionSort() 100 5.360 5.365 5.372 3 +selectionSort() 300 46.272 46.275 46.276 3 +shellSortClassic() 10 0.064 0.074 0.084 25 +shellSortClassic() 30 0.276 0.306 0.328 25 +shellSortClassic() 100 1.620 1.711 1.800 25 +shellSortClassic() 300 6.732 6.868 7.164 25 +shellSortKnuth() 10 0.092 0.100 0.112 25 +shellSortKnuth() 30 0.304 0.325 0.356 25 +shellSortKnuth() 100 1.328 1.431 1.536 25 +shellSortKnuth() 300 5.360 5.683 6.208 25 +shellSortTokuda() 10 0.064 0.075 0.092 25 +shellSortTokuda() 30 0.312 0.336 0.356 25 +shellSortTokuda() 100 1.536 1.616 1.700 25 +shellSortTokuda() 300 6.384 6.555 6.740 25 +combSort13() 10 0.152 0.167 0.196 25 +combSort13() 30 0.492 0.534 0.620 25 +combSort13() 100 2.116 2.215 2.488 25 +combSort13() 300 7.840 8.260 8.756 25 +combSort13m() 10 0.156 0.164 0.192 25 +combSort13m() 30 0.540 0.557 0.616 25 +combSort13m() 100 2.108 2.233 2.524 25 +combSort13m() 300 7.792 8.176 8.756 25 +combSort133() 10 0.076 0.084 0.100 25 +combSort133() 30 0.372 0.400 0.524 25 +combSort133() 100 1.816 1.968 2.272 25 +combSort133() 300 7.304 7.730 8.604 25 +combSort133m() 10 0.080 0.087 0.108 25 +combSort133m() 30 0.408 0.419 0.432 25 +combSort133m() 100 1.936 1.979 2.108 25 +combSort133m() 300 7.280 7.805 8.648 25 +quickSortMiddle() 10 0.084 0.097 0.120 25 +quickSortMiddle() 30 0.336 0.373 0.428 25 +quickSortMiddle() 100 1.480 1.582 1.712 25 +quickSortMiddle() 300 5.016 5.536 6.248 25 +quickSortMedian() 10 0.092 0.117 0.136 25 +quickSortMedian() 30 0.384 0.423 0.468 25 +quickSortMedian() 100 1.632 1.717 1.824 25 +quickSortMedian() 300 5.684 5.905 6.184 25 +quickSortMedianSwapped() 10 0.072 0.092 0.104 25 +quickSortMedianSwapped() 30 0.308 0.338 0.364 25 +quickSortMedianSwapped() 100 1.312 1.396 1.568 25 +quickSortMedianSwapped() 300 4.616 4.895 5.544 25 +qsort() 10 0.152 0.208 0.300 25 +qsort() 30 0.756 0.827 0.952 25 +qsort() 100 3.424 3.642 3.844 25 +qsort() 300 12.584 13.068 13.504 25 END diff --git a/examples/AutoBenchmark/samd.txt b/examples/AutoBenchmark/samd.txt index 5af15f7..4a7b997 100644 --- a/examples/AutoBenchmark/samd.txt +++ b/examples/AutoBenchmark/samd.txt @@ -1,83 +1,83 @@ BENCHMARKS -bubbleSort() 10 0.036 0.039 0.044 3 -bubbleSort() 30 0.315 0.357 0.387 3 -bubbleSort() 100 3.964 3.984 4.011 3 -bubbleSort() 300 35.300 36.967 38.476 3 -bubbleSort() 1000 425.463 429.557 431.644 3 -insertionSort() 10 0.012 0.014 0.016 3 -insertionSort() 30 0.087 0.095 0.108 3 -insertionSort() 100 0.834 0.880 0.948 3 -insertionSort() 300 7.820 8.132 8.320 3 -insertionSort() 1000 86.152 87.197 88.020 3 -selectionSort() 10 0.023 0.023 0.023 3 -selectionSort() 30 0.157 0.159 0.161 3 -selectionSort() 100 1.619 1.620 1.621 3 -selectionSort() 300 14.278 14.279 14.281 3 -selectionSort() 1000 157.534 157.547 157.568 3 -shellSortClassic() 10 0.014 0.016 0.018 20 -shellSortClassic() 30 0.058 0.064 0.071 20 -shellSortClassic() 100 0.334 0.349 0.380 20 -shellSortClassic() 300 1.363 1.405 1.460 20 -shellSortClassic() 1000 5.677 5.861 6.097 20 -shellSortClassic() 3000 21.989 22.452 23.069 20 -shellSortKnuth() 10 0.017 0.019 0.021 20 -shellSortKnuth() 30 0.062 0.067 0.074 20 -shellSortKnuth() 100 0.277 0.289 0.310 20 -shellSortKnuth() 300 1.102 1.153 1.206 20 -shellSortKnuth() 1000 4.867 5.111 5.437 20 -shellSortKnuth() 3000 18.550 19.448 20.784 20 -shellSortTokuda() 10 0.017 0.020 0.021 20 -shellSortTokuda() 30 0.076 0.081 0.085 20 -shellSortTokuda() 100 0.371 0.390 0.409 20 -shellSortTokuda() 300 1.514 1.556 1.596 20 -shellSortTokuda() 1000 6.580 6.673 6.773 20 -shellSortTokuda() 3000 23.952 24.187 24.643 20 -combSort13() 10 0.033 0.035 0.039 20 -combSort13() 30 0.109 0.118 0.124 20 -combSort13() 100 0.450 0.496 0.553 20 -combSort13() 300 1.777 1.859 1.987 20 -combSort13() 1000 7.915 8.180 8.935 20 -combSort13() 3000 28.934 29.661 31.978 20 -combSort13m() 10 0.034 0.035 0.041 20 -combSort13m() 30 0.121 0.124 0.137 20 -combSort13m() 100 0.481 0.512 0.560 20 -combSort13m() 300 1.784 1.882 1.991 20 -combSort13m() 1000 7.561 7.892 8.251 20 -combSort13m() 3000 27.894 28.483 28.964 20 -combSort133() 10 0.019 0.020 0.023 20 -combSort133() 30 0.086 0.090 0.102 20 -combSort133() 100 0.409 0.454 0.590 20 -combSort133() 300 1.652 1.764 1.868 20 -combSort133() 1000 7.282 7.897 8.620 20 -combSort133() 3000 26.165 26.989 28.205 20 +bubbleSort() 10 0.027 0.031 0.035 3 +bubbleSort() 30 0.216 0.282 0.331 3 +bubbleSort() 100 3.366 3.405 3.468 3 +bubbleSort() 300 31.077 32.272 33.701 3 +bubbleSort() 1000 355.351 363.409 370.085 3 +insertionSort() 10 0.013 0.016 0.019 3 +insertionSort() 30 0.078 0.088 0.093 3 +insertionSort() 100 0.868 0.941 0.989 3 +insertionSort() 300 7.541 8.144 8.547 3 +insertionSort() 1000 87.778 89.678 91.223 3 +selectionSort() 10 0.023 0.024 0.024 3 +selectionSort() 30 0.160 0.162 0.163 3 +selectionSort() 100 1.627 1.629 1.630 3 +selectionSort() 300 14.304 14.306 14.310 3 +selectionSort() 1000 157.626 157.639 157.659 3 +shellSortClassic() 10 0.015 0.016 0.018 20 +shellSortClassic() 30 0.060 0.064 0.068 20 +shellSortClassic() 100 0.325 0.349 0.377 20 +shellSortClassic() 300 1.369 1.408 1.480 20 +shellSortClassic() 1000 5.636 5.912 6.118 20 +shellSortClassic() 3000 21.351 22.251 22.906 20 +shellSortKnuth() 10 0.018 0.019 0.020 20 +shellSortKnuth() 30 0.060 0.065 0.079 20 +shellSortKnuth() 100 0.272 0.298 0.320 20 +shellSortKnuth() 300 1.099 1.154 1.236 20 +shellSortKnuth() 1000 4.889 5.074 5.429 20 +shellSortKnuth() 3000 18.413 19.321 20.476 20 +shellSortTokuda() 10 0.017 0.019 0.021 20 +shellSortTokuda() 30 0.075 0.081 0.087 20 +shellSortTokuda() 100 0.371 0.390 0.412 20 +shellSortTokuda() 300 1.528 1.568 1.618 20 +shellSortTokuda() 1000 6.609 6.690 6.771 20 +shellSortTokuda() 3000 23.886 24.190 24.533 20 +combSort13() 10 0.029 0.035 0.039 20 +combSort13() 30 0.113 0.121 0.137 20 +combSort13() 100 0.497 0.532 0.617 20 +combSort13() 300 1.850 1.934 1.973 20 +combSort13() 1000 8.271 8.697 10.070 20 +combSort13() 3000 30.277 31.638 34.597 20 +combSort13m() 10 0.034 0.036 0.042 20 +combSort13m() 30 0.124 0.128 0.138 20 +combSort13m() 100 0.500 0.534 0.655 20 +combSort13m() 300 1.852 1.931 2.077 20 +combSort13m() 1000 7.921 8.274 8.616 20 +combSort13m() 3000 29.195 29.531 30.300 20 +combSort133() 10 0.019 0.021 0.024 20 +combSort133() 30 0.089 0.090 0.093 20 +combSort133() 100 0.427 0.452 0.508 20 +combSort133() 300 1.724 1.825 1.942 20 +combSort133() 1000 7.613 8.259 9.418 20 +combSort133() 3000 27.321 28.640 32.716 20 combSort133m() 10 0.021 0.021 0.023 20 -combSort133m() 30 0.096 0.097 0.101 20 -combSort133m() 100 0.446 0.454 0.487 20 -combSort133m() 300 1.653 1.752 1.870 20 -combSort133m() 1000 7.293 7.623 7.971 20 -combSort133m() 3000 26.179 27.649 32.205 20 -quickSortMiddle() 10 0.017 0.021 0.027 20 -quickSortMiddle() 30 0.062 0.073 0.089 20 -quickSortMiddle() 100 0.283 0.315 0.383 20 -quickSortMiddle() 300 1.005 1.077 1.182 20 -quickSortMiddle() 1000 3.864 4.211 4.759 20 -quickSortMiddle() 3000 13.376 14.031 14.748 20 -quickSortMedian() 10 0.022 0.026 0.031 20 -quickSortMedian() 30 0.077 0.088 0.100 20 -quickSortMedian() 100 0.328 0.344 0.369 20 -quickSortMedian() 300 1.106 1.161 1.227 20 -quickSortMedian() 1000 4.233 4.343 4.525 20 -quickSortMedian() 3000 14.120 14.455 15.235 20 -quickSortMedianSwapped() 10 0.017 0.020 0.023 20 -quickSortMedianSwapped() 30 0.064 0.070 0.077 20 -quickSortMedianSwapped() 100 0.264 0.285 0.315 20 -quickSortMedianSwapped() 300 0.939 1.001 1.065 20 -quickSortMedianSwapped() 1000 3.631 3.783 4.090 20 -quickSortMedianSwapped() 3000 12.076 12.630 13.381 20 -qsort() 10 0.041 0.054 0.068 20 -qsort() 30 0.189 0.213 0.249 20 -qsort() 100 0.827 0.886 0.921 20 -qsort() 300 3.118 3.215 3.375 20 -qsort() 1000 12.392 12.678 12.994 20 -qsort() 3000 42.268 42.791 43.244 20 +combSort133m() 30 0.098 0.100 0.103 20 +combSort133m() 100 0.464 0.470 0.507 20 +combSort133m() 300 1.718 1.822 1.949 20 +combSort133m() 1000 7.605 7.949 7.982 20 +combSort133m() 3000 27.355 28.592 31.646 20 +quickSortMiddle() 10 0.017 0.022 0.028 20 +quickSortMiddle() 30 0.065 0.077 0.090 20 +quickSortMiddle() 100 0.288 0.312 0.363 20 +quickSortMiddle() 300 0.998 1.097 1.210 20 +quickSortMiddle() 1000 3.962 4.246 4.576 20 +quickSortMiddle() 3000 13.572 14.192 15.172 20 +quickSortMedian() 10 0.022 0.026 0.028 20 +quickSortMedian() 30 0.080 0.088 0.094 20 +quickSortMedian() 100 0.323 0.338 0.347 20 +quickSortMedian() 300 1.114 1.158 1.197 20 +quickSortMedian() 1000 4.246 4.387 4.612 20 +quickSortMedian() 3000 14.131 14.495 15.369 20 +quickSortMedianSwapped() 10 0.017 0.020 0.024 20 +quickSortMedianSwapped() 30 0.063 0.069 0.077 20 +quickSortMedianSwapped() 100 0.263 0.281 0.299 20 +quickSortMedianSwapped() 300 0.931 0.980 1.031 20 +quickSortMedianSwapped() 1000 3.583 3.720 3.916 20 +quickSortMedianSwapped() 3000 12.021 12.486 13.078 20 +qsort() 10 0.040 0.052 0.061 20 +qsort() 30 0.183 0.204 0.231 20 +qsort() 100 0.825 0.873 0.928 20 +qsort() 300 3.017 3.088 3.205 20 +qsort() 1000 11.895 12.102 12.361 20 +qsort() 3000 40.749 41.217 42.525 20 END diff --git a/examples/AutoBenchmark/stm32.txt b/examples/AutoBenchmark/stm32.txt index a3c6365..c744f63 100644 --- a/examples/AutoBenchmark/stm32.txt +++ b/examples/AutoBenchmark/stm32.txt @@ -1,83 +1,83 @@ BENCHMARKS -bubbleSort() 10 0.013 0.018 0.025 3 -bubbleSort() 30 0.128 0.161 0.214 3 -bubbleSort() 100 2.064 2.105 2.186 3 -bubbleSort() 300 19.574 19.955 20.358 3 -bubbleSort() 1000 222.869 225.639 229.515 3 -insertionSort() 10 0.008 0.010 0.011 3 -insertionSort() 30 0.051 0.054 0.057 3 -insertionSort() 100 0.466 0.495 0.544 3 -insertionSort() 300 4.402 4.486 4.636 3 -insertionSort() 1000 47.204 48.616 49.785 3 -selectionSort() 10 0.017 0.017 0.017 3 -selectionSort() 30 0.115 0.116 0.116 3 -selectionSort() 100 1.165 1.167 1.169 3 -selectionSort() 300 10.196 10.197 10.200 3 -selectionSort() 1000 112.178 112.180 112.183 3 -shellSortClassic() 10 0.013 0.014 0.015 20 -shellSortClassic() 30 0.055 0.058 0.064 20 -shellSortClassic() 100 0.297 0.324 0.362 20 -shellSortClassic() 300 1.229 1.284 1.337 20 -shellSortClassic() 1000 5.292 5.427 5.557 20 -shellSortClassic() 3000 20.049 20.852 21.631 20 -shellSortKnuth() 10 0.012 0.014 0.019 20 -shellSortKnuth() 30 0.054 0.059 0.068 20 -shellSortKnuth() 100 0.287 0.305 0.331 20 -shellSortKnuth() 300 1.168 1.236 1.322 20 -shellSortKnuth() 1000 5.335 5.604 6.061 20 -shellSortKnuth() 3000 20.874 21.566 22.651 20 -shellSortTokuda() 10 0.010 0.011 0.012 20 -shellSortTokuda() 30 0.042 0.047 0.051 20 -shellSortTokuda() 100 0.217 0.226 0.235 20 -shellSortTokuda() 300 0.874 0.901 0.927 20 -shellSortTokuda() 1000 3.816 3.904 3.968 20 -shellSortTokuda() 3000 14.045 14.199 14.364 20 -combSort13() 10 0.018 0.019 0.022 20 -combSort13() 30 0.081 0.087 0.104 20 -combSort13() 100 0.428 0.442 0.498 20 -combSort13() 300 1.674 1.770 1.886 20 -combSort13() 1000 7.301 7.895 8.699 20 -combSort13() 3000 28.178 28.862 30.275 20 -combSort13m() 10 0.017 0.018 0.025 20 -combSort13m() 30 0.087 0.087 0.092 20 -combSort13m() 100 0.409 0.430 0.448 20 -combSort13m() 300 1.611 1.697 1.814 20 -combSort13m() 1000 7.009 7.380 7.683 20 -combSort13m() 3000 26.049 26.657 28.064 20 -combSort133() 10 0.017 0.018 0.022 20 -combSort133() 30 0.082 0.085 0.107 20 -combSort133() 100 0.394 0.417 0.468 20 -combSort133() 300 1.585 1.649 1.693 20 -combSort133() 1000 7.000 7.630 8.396 20 -combSort133() 3000 25.152 26.148 28.293 20 -combSort133m() 10 0.014 0.019 0.021 20 -combSort133m() 30 0.087 0.089 0.098 20 -combSort133m() 100 0.413 0.419 0.448 20 -combSort133m() 300 1.535 1.619 1.643 20 -combSort133m() 1000 6.783 7.151 7.787 20 -combSort133m() 3000 24.373 25.380 27.393 20 -quickSortMiddle() 10 0.016 0.019 0.033 20 -quickSortMiddle() 30 0.059 0.067 0.079 20 -quickSortMiddle() 100 0.259 0.278 0.301 20 -quickSortMiddle() 300 0.926 0.990 1.096 20 -quickSortMiddle() 1000 3.620 3.835 4.171 20 -quickSortMiddle() 3000 12.483 13.145 13.883 20 -quickSortMedian() 10 0.018 0.020 0.026 20 -quickSortMedian() 30 0.071 0.076 0.079 20 -quickSortMedian() 100 0.289 0.311 0.345 20 -quickSortMedian() 300 1.054 1.101 1.167 20 -quickSortMedian() 1000 4.050 4.212 4.573 20 -quickSortMedian() 3000 13.888 14.381 15.341 20 -quickSortMedianSwapped() 10 0.012 0.015 0.018 20 -quickSortMedianSwapped() 30 0.051 0.056 0.061 20 -quickSortMedianSwapped() 100 0.217 0.228 0.243 20 -quickSortMedianSwapped() 300 0.788 0.836 0.909 20 -quickSortMedianSwapped() 1000 3.162 3.285 3.619 20 -quickSortMedianSwapped() 3000 10.776 11.265 12.538 20 -qsort() 10 0.025 0.034 0.047 20 -qsort() 30 0.123 0.149 0.317 20 -qsort() 100 0.566 0.615 0.836 20 -qsort() 300 2.173 2.221 2.313 20 -qsort() 1000 8.652 8.921 9.368 20 -qsort() 3000 30.092 30.627 31.322 20 +bubbleSort() 10 0.018 0.022 0.027 3 +bubbleSort() 30 0.152 0.169 0.193 3 +bubbleSort() 100 1.927 2.156 2.353 3 +bubbleSort() 300 19.949 20.662 21.305 3 +bubbleSort() 1000 228.374 230.118 232.415 3 +insertionSort() 10 0.008 0.009 0.009 3 +insertionSort() 30 0.052 0.054 0.057 3 +insertionSort() 100 0.469 0.488 0.522 3 +insertionSort() 300 4.091 4.278 4.452 3 +insertionSort() 1000 43.610 45.077 46.415 3 +selectionSort() 10 0.015 0.016 0.016 3 +selectionSort() 30 0.102 0.102 0.103 3 +selectionSort() 100 1.023 1.023 1.024 3 +selectionSort() 300 8.928 8.931 8.932 3 +selectionSort() 1000 98.184 98.184 98.184 3 +shellSortClassic() 10 0.013 0.014 0.027 20 +shellSortClassic() 30 0.054 0.057 0.062 20 +shellSortClassic() 100 0.294 0.305 0.329 20 +shellSortClassic() 300 1.207 1.243 1.282 20 +shellSortClassic() 1000 5.022 5.157 5.329 20 +shellSortClassic() 3000 19.189 19.747 20.193 20 +shellSortKnuth() 10 0.012 0.013 0.024 20 +shellSortKnuth() 30 0.050 0.057 0.069 20 +shellSortKnuth() 100 0.248 0.276 0.293 20 +shellSortKnuth() 300 1.075 1.131 1.219 20 +shellSortKnuth() 1000 4.758 5.058 5.285 20 +shellSortKnuth() 3000 18.788 19.403 20.601 20 +shellSortTokuda() 10 0.009 0.012 0.019 20 +shellSortTokuda() 30 0.044 0.048 0.054 20 +shellSortTokuda() 100 0.213 0.226 0.240 20 +shellSortTokuda() 300 0.887 0.905 0.937 20 +shellSortTokuda() 1000 3.845 3.888 3.933 20 +shellSortTokuda() 3000 13.971 14.123 14.372 20 +combSort13() 10 0.016 0.017 0.025 20 +combSort13() 30 0.074 0.080 0.094 20 +combSort13() 100 0.389 0.396 0.458 20 +combSort13() 300 1.526 1.601 1.723 20 +combSort13() 1000 6.661 7.173 7.623 20 +combSort13() 3000 24.752 26.248 27.647 20 +combSort13m() 10 0.016 0.018 0.025 20 +combSort13m() 30 0.083 0.084 0.092 20 +combSort13m() 100 0.389 0.416 0.523 20 +combSort13m() 300 1.529 1.585 1.630 20 +combSort13m() 1000 6.658 6.998 7.306 20 +combSort13m() 3000 24.757 25.575 26.686 20 +combSort133() 10 0.013 0.016 0.024 20 +combSort133() 30 0.072 0.073 0.077 20 +combSort133() 100 0.346 0.378 0.474 20 +combSort133() 300 1.395 1.481 1.674 20 +combSort133() 1000 6.161 6.775 8.620 20 +combSort133() 3000 22.134 22.826 23.977 20 +combSort133m() 10 0.016 0.017 0.025 20 +combSort133m() 30 0.079 0.080 0.081 20 +combSort133m() 100 0.376 0.382 0.410 20 +combSort133m() 300 1.399 1.496 1.583 20 +combSort133m() 1000 6.159 6.436 6.470 20 +combSort133m() 3000 22.137 23.289 27.667 20 +quickSortMiddle() 10 0.013 0.017 0.026 20 +quickSortMiddle() 30 0.053 0.064 0.072 20 +quickSortMiddle() 100 0.225 0.260 0.288 20 +quickSortMiddle() 300 0.868 0.941 1.011 20 +quickSortMiddle() 1000 3.303 3.559 3.920 20 +quickSortMiddle() 3000 11.224 12.330 13.212 20 +quickSortMedian() 10 0.016 0.020 0.032 20 +quickSortMedian() 30 0.064 0.070 0.077 20 +quickSortMedian() 100 0.266 0.280 0.296 20 +quickSortMedian() 300 0.928 0.994 1.069 20 +quickSortMedian() 1000 3.654 3.769 3.937 20 +quickSortMedian() 3000 12.272 12.632 13.990 20 +quickSortMedianSwapped() 10 0.013 0.015 0.024 20 +quickSortMedianSwapped() 30 0.049 0.056 0.063 20 +quickSortMedianSwapped() 100 0.219 0.236 0.254 20 +quickSortMedianSwapped() 300 0.803 0.855 0.970 20 +quickSortMedianSwapped() 1000 3.203 3.318 3.567 20 +quickSortMedianSwapped() 3000 10.810 11.345 12.163 20 +qsort() 10 0.026 0.033 0.040 20 +qsort() 30 0.119 0.132 0.145 20 +qsort() 100 0.579 0.609 0.643 20 +qsort() 300 2.187 2.251 2.448 20 +qsort() 1000 8.719 8.882 9.120 20 +qsort() 3000 30.058 30.578 31.259 20 END diff --git a/examples/AutoBenchmark/teensy32.txt b/examples/AutoBenchmark/teensy32.txt index ece77a7..a0af23c 100644 --- a/examples/AutoBenchmark/teensy32.txt +++ b/examples/AutoBenchmark/teensy32.txt @@ -1,83 +1,83 @@ BENCHMARKS bubbleSort() 10 0.008 0.009 0.010 3 -bubbleSort() 30 0.073 0.079 0.082 3 -bubbleSort() 100 0.743 0.824 0.940 3 -bubbleSort() 300 8.002 8.469 8.977 3 -bubbleSort() 1000 94.984 98.471 101.370 3 -insertionSort() 10 0.006 0.006 0.007 3 -insertionSort() 30 0.036 0.041 0.049 3 -insertionSort() 100 0.385 0.394 0.402 3 -insertionSort() 300 3.300 3.390 3.485 3 -insertionSort() 1000 36.376 36.820 37.584 3 -selectionSort() 10 0.008 0.008 0.008 3 -selectionSort() 30 0.057 0.057 0.058 3 -selectionSort() 100 0.589 0.590 0.590 3 -selectionSort() 300 5.212 5.215 5.218 3 -selectionSort() 1000 57.556 57.558 57.560 3 +bubbleSort() 30 0.074 0.083 0.091 3 +bubbleSort() 100 0.870 0.945 1.020 3 +bubbleSort() 300 9.099 9.217 9.399 3 +bubbleSort() 1000 98.266 102.362 104.583 3 +insertionSort() 10 0.005 0.005 0.006 3 +insertionSort() 30 0.038 0.040 0.043 3 +insertionSort() 100 0.385 0.399 0.409 3 +insertionSort() 300 3.220 3.290 3.365 3 +insertionSort() 1000 35.585 36.427 37.111 3 +selectionSort() 10 0.009 0.009 0.010 3 +selectionSort() 30 0.064 0.065 0.065 3 +selectionSort() 100 0.652 0.653 0.654 3 +selectionSort() 300 5.714 5.715 5.718 3 +selectionSort() 1000 62.887 62.889 62.892 3 shellSortClassic() 10 0.006 0.007 0.009 20 shellSortClassic() 30 0.027 0.029 0.031 20 -shellSortClassic() 100 0.150 0.162 0.173 20 -shellSortClassic() 300 0.630 0.648 0.671 20 -shellSortClassic() 1000 2.651 2.712 2.809 20 -shellSortClassic() 3000 9.971 10.394 10.906 20 -shellSortKnuth() 10 0.005 0.006 0.008 20 -shellSortKnuth() 30 0.025 0.027 0.032 20 -shellSortKnuth() 100 0.123 0.133 0.141 20 -shellSortKnuth() 300 0.511 0.531 0.552 20 -shellSortKnuth() 1000 2.244 2.339 2.490 20 -shellSortKnuth() 3000 8.658 8.903 9.199 20 +shellSortClassic() 100 0.150 0.159 0.171 20 +shellSortClassic() 300 0.628 0.648 0.661 20 +shellSortClassic() 1000 2.631 2.694 2.862 20 +shellSortClassic() 3000 10.140 10.372 10.594 20 +shellSortKnuth() 10 0.005 0.006 0.007 20 +shellSortKnuth() 30 0.023 0.027 0.031 20 +shellSortKnuth() 100 0.125 0.131 0.140 20 +shellSortKnuth() 300 0.511 0.526 0.556 20 +shellSortKnuth() 1000 2.274 2.345 2.463 20 +shellSortKnuth() 3000 8.421 8.972 9.684 20 shellSortTokuda() 10 0.006 0.007 0.008 20 -shellSortTokuda() 30 0.026 0.028 0.030 20 -shellSortTokuda() 100 0.130 0.136 0.142 20 -shellSortTokuda() 300 0.529 0.539 0.547 20 -shellSortTokuda() 1000 2.256 2.314 2.364 20 -shellSortTokuda() 3000 8.287 8.366 8.440 20 -combSort13() 10 0.007 0.008 0.010 20 -combSort13() 30 0.033 0.036 0.039 20 -combSort13() 100 0.175 0.182 0.212 20 -combSort13() 300 0.688 0.722 0.770 20 -combSort13() 1000 3.134 3.233 3.414 20 -combSort13() 3000 11.533 11.887 12.768 20 +shellSortTokuda() 30 0.027 0.028 0.030 20 +shellSortTokuda() 100 0.131 0.135 0.140 20 +shellSortTokuda() 300 0.526 0.539 0.549 20 +shellSortTokuda() 1000 2.280 2.312 2.342 20 +shellSortTokuda() 3000 8.292 8.365 8.436 20 +combSort13() 10 0.007 0.008 0.009 20 +combSort13() 30 0.033 0.037 0.046 20 +combSort13() 100 0.175 0.182 0.208 20 +combSort13() 300 0.687 0.720 0.733 20 +combSort13() 1000 3.134 3.234 3.550 20 +combSort13() 3000 11.535 11.948 12.772 20 combSort13m() 10 0.008 0.008 0.010 20 -combSort13m() 30 0.037 0.038 0.040 20 -combSort13m() 100 0.176 0.186 0.220 20 -combSort13m() 300 0.689 0.725 0.770 20 -combSort13m() 1000 3.128 3.139 3.272 20 -combSort13m() 3000 11.124 11.431 11.545 20 +combSort13m() 30 0.037 0.038 0.038 20 +combSort13m() 100 0.175 0.182 0.194 20 +combSort13m() 300 0.687 0.721 0.773 20 +combSort13m() 1000 2.997 3.146 3.272 20 +combSort13m() 3000 11.118 11.470 11.939 20 combSort133() 10 0.007 0.008 0.009 20 -combSort133() 30 0.034 0.035 0.035 20 -combSort133() 100 0.163 0.174 0.207 20 -combSort133() 300 0.660 0.698 0.745 20 -combSort133() 1000 2.904 3.101 3.319 20 -combSort133() 3000 10.451 10.902 12.078 20 +combSort133() 30 0.034 0.035 0.037 20 +combSort133() 100 0.163 0.175 0.220 20 +combSort133() 300 0.658 0.693 0.708 20 +combSort133() 1000 3.039 3.142 3.327 20 +combSort133() 3000 10.451 10.841 12.484 20 combSort133m() 10 0.007 0.008 0.010 20 -combSort133m() 30 0.037 0.038 0.042 20 -combSort133m() 100 0.176 0.180 0.191 20 -combSort133m() 300 0.699 0.710 0.746 20 -combSort133m() 1000 2.908 3.030 3.050 20 -combSort133m() 3000 10.448 10.801 11.276 20 -quickSortMiddle() 10 0.006 0.007 0.009 20 -quickSortMiddle() 30 0.023 0.026 0.028 20 -quickSortMiddle() 100 0.095 0.109 0.140 20 -quickSortMiddle() 300 0.353 0.388 0.423 20 -quickSortMiddle() 1000 1.424 1.520 1.806 20 -quickSortMiddle() 3000 4.957 5.278 5.846 20 -quickSortMedian() 10 0.007 0.009 0.010 20 -quickSortMedian() 30 0.028 0.030 0.032 20 -quickSortMedian() 100 0.114 0.122 0.134 20 -quickSortMedian() 300 0.399 0.423 0.456 20 -quickSortMedian() 1000 1.520 1.590 1.663 20 -quickSortMedian() 3000 5.180 5.387 5.604 20 -quickSortMedianSwapped() 10 0.006 0.007 0.009 20 -quickSortMedianSwapped() 30 0.022 0.025 0.028 20 -quickSortMedianSwapped() 100 0.094 0.100 0.108 20 -quickSortMedianSwapped() 300 0.345 0.365 0.381 20 -quickSortMedianSwapped() 1000 1.341 1.412 1.662 20 -quickSortMedianSwapped() 3000 4.559 4.752 5.080 20 -qsort() 10 0.013 0.017 0.022 20 -qsort() 30 0.067 0.073 0.101 20 -qsort() 100 0.301 0.315 0.335 20 -qsort() 300 1.135 1.156 1.197 20 -qsort() 1000 4.474 4.576 4.722 20 -qsort() 3000 15.456 15.732 16.127 20 +combSort133m() 30 0.037 0.038 0.040 20 +combSort133m() 100 0.176 0.179 0.193 20 +combSort133m() 300 0.659 0.700 0.744 20 +combSort133m() 1000 2.911 3.037 3.052 20 +combSort133m() 3000 10.443 10.841 12.494 20 +quickSortMiddle() 10 0.005 0.007 0.009 20 +quickSortMiddle() 30 0.023 0.026 0.030 20 +quickSortMiddle() 100 0.095 0.108 0.119 20 +quickSortMiddle() 300 0.360 0.399 0.453 20 +quickSortMiddle() 1000 1.405 1.543 1.738 20 +quickSortMiddle() 3000 5.032 5.324 6.742 20 +quickSortMedian() 10 0.007 0.009 0.009 20 +quickSortMedian() 30 0.027 0.030 0.032 20 +quickSortMedian() 100 0.116 0.122 0.132 20 +quickSortMedian() 300 0.394 0.414 0.440 20 +quickSortMedian() 1000 1.542 1.598 1.672 20 +quickSortMedian() 3000 5.201 5.353 5.734 20 +quickSortMedianSwapped() 10 0.005 0.007 0.009 20 +quickSortMedianSwapped() 30 0.022 0.025 0.029 20 +quickSortMedianSwapped() 100 0.093 0.103 0.113 20 +quickSortMedianSwapped() 300 0.337 0.357 0.378 20 +quickSortMedianSwapped() 1000 1.348 1.403 1.454 20 +quickSortMedianSwapped() 3000 4.563 4.750 4.938 20 +qsort() 10 0.014 0.017 0.022 20 +qsort() 30 0.062 0.071 0.077 20 +qsort() 100 0.308 0.317 0.336 20 +qsort() 300 1.118 1.154 1.183 20 +qsort() 1000 4.483 4.579 4.710 20 +qsort() 3000 15.545 15.830 16.163 20 END From 01b8542e50c09be2c07afdd09a1bf059c941b92b Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 08:30:34 -0700 Subject: [PATCH 08/17] README.md: Update MemoryBenchmark and AutoBenchmark samples --- README.md | 58 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index b42ab58..762b30c 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,7 @@ The full details of flash and static memory consumptions are given in |----------------------------------------+--------------+-------------| | quickSortMiddle() | 1244/ 214 | 178/ 0 | | quickSortMedian() | 1296/ 214 | 230/ 0 | -| quickSortMedianSwapped() | 1344/ 214 | 278/ 0 | +| quickSortMedianSwapped() | 1344/ 214 | 276/ 0 | |----------------------------------------+--------------+-------------| | qsort() | 2150/ 214 | 1084/ 0 | +---------------------------------------------------------------------+ @@ -437,7 +437,7 @@ The full details of flash and static memory consumptions are given in |----------------------------------------+--------------+-------------| | shellSortClassic() | 257180/26976 | 80/ 0 | | shellSortKnuth() | 257212/26976 | 112/ 0 | -| shellSortTokuda() | 257256/27004 | 156/ 28 | +| shellSortTokuda() | 257256/27004 | 140/ 28 | |----------------------------------------+--------------+-------------| | combSort13() | 257196/26976 | 96/ 0 | | combSort13m() | 257212/26976 | 112/ 0 | @@ -466,24 +466,24 @@ Here are 2 samples. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.107 | 1.077 | 12.735 | 116.675 | | | -| insertionSort() | 0.045 | 0.263 | 2.557 | 22.252 | | | -| selectionSort() | 0.088 | 0.560 | 5.600 | 48.892 | | | +| bubbleSort() | 0.099 | 1.044 | 12.305 | 118.589 | | | +| insertionSort() | 0.049 | 0.251 | 2.463 | 21.288 | | | +| selectionSort() | 0.087 | 0.553 | 5.365 | 46.275 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.074 | 0.310 | 1.706 | 6.865 | | | -| shellSortKnuth() | 0.101 | 0.330 | 1.450 | 5.665 | | | -| shellSortTokuda() | 0.075 | 0.327 | 1.614 | 6.540 | | | +| shellSortClassic() | 0.074 | 0.306 | 1.711 | 6.868 | | | +| shellSortKnuth() | 0.100 | 0.325 | 1.431 | 5.683 | | | +| shellSortTokuda() | 0.075 | 0.336 | 1.616 | 6.555 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.160 | 0.534 | 2.214 | 8.167 | | | -| combSort13m() | 0.165 | 0.550 | 2.219 | 8.181 | | | -| combSort133() | 0.086 | 0.396 | 1.944 | 7.702 | | | -| combSort133m() | 0.086 | 0.416 | 1.978 | 7.740 | | | +| combSort13() | 0.167 | 0.534 | 2.215 | 8.260 | | | +| combSort13m() | 0.164 | 0.557 | 2.233 | 8.176 | | | +| combSort133() | 0.084 | 0.400 | 1.968 | 7.730 | | | +| combSort133m() | 0.087 | 0.419 | 1.979 | 7.805 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.096 | 0.368 | 1.568 | 5.651 | | | -| quickSortMedian() | 0.117 | 0.431 | 1.717 | 5.905 | | | -| quickSortMdnSwppd() | 0.094 | 0.341 | 1.417 | 4.909 | | | +| quickSortMiddle() | 0.097 | 0.373 | 1.582 | 5.536 | | | +| quickSortMedian() | 0.117 | 0.423 | 1.717 | 5.905 | | | +| quickSortMdnSwppd() | 0.092 | 0.338 | 1.396 | 4.895 | | | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.204 | 0.855 | 3.629 | 13.021 | | | +| qsort() | 0.208 | 0.827 | 3.642 | 13.068 | | | +---------------------+-------+-------+--------+---------+---------+---------+ ``` @@ -494,24 +494,24 @@ Here are 2 samples. | \ N | 10 | 30 | 100 | 300 | 1000 | 3000 | | Function \ | | | | | | | |---------------------+-------+-------+--------+---------+---------+---------| -| bubbleSort() | 0.021 | 0.192 | 2.231 | 20.143 | 225.651 | | -| insertionSort() | 0.009 | 0.037 | 0.362 | 3.220 | 34.646 | | -| selectionSort() | 0.017 | 0.085 | 0.892 | 7.930 | 87.723 | | +| bubbleSort() | 0.022 | 0.181 | 2.116 | 19.118 | 213.942 | | +| insertionSort() | 0.011 | 0.037 | 0.361 | 3.222 | 34.652 | | +| selectionSort() | 0.017 | 0.092 | 0.961 | 8.500 | 93.980 | | |---------------------+-------+-------+--------+---------+---------+---------| -| shellSortClassic() | 0.011 | 0.039 | 0.215 | 0.878 | 3.609 | 13.789 | -| shellSortKnuth() | 0.010 | 0.036 | 0.172 | 0.690 | 3.022 | 11.304 | -| shellSortTokuda() | 0.009 | 0.039 | 0.183 | 0.735 | 3.140 | 11.366 | +| shellSortClassic() | 0.010 | 0.039 | 0.215 | 0.878 | 3.610 | 13.789 | +| shellSortKnuth() | 0.010 | 0.036 | 0.172 | 0.690 | 3.021 | 11.306 | +| shellSortTokuda() | 0.009 | 0.040 | 0.188 | 0.756 | 3.227 | 11.678 | |---------------------+-------+-------+--------+---------+---------+---------| -| combSort13() | 0.013 | 0.048 | 0.219 | 0.846 | 3.711 | 13.689 | -| combSort13m() | 0.014 | 0.051 | 0.222 | 0.840 | 3.622 | 13.104 | +| combSort13() | 0.013 | 0.048 | 0.219 | 0.846 | 3.712 | 13.695 | +| combSort13m() | 0.013 | 0.051 | 0.223 | 0.840 | 3.625 | 13.102 | | combSort133() | 0.010 | 0.040 | 0.208 | 0.796 | 3.571 | 12.430 | -| combSort133m() | 0.010 | 0.044 | 0.206 | 0.793 | 3.465 | 12.387 | +| combSort133m() | 0.010 | 0.045 | 0.206 | 0.793 | 3.466 | 12.387 | |---------------------+-------+-------+--------+---------+---------+---------| -| quickSortMiddle() | 0.013 | 0.045 | 0.185 | 0.651 | 2.519 | 8.307 | -| quickSortMedian() | 0.016 | 0.052 | 0.200 | 0.677 | 2.551 | 8.403 | -| quickSortMdnSwppd() | 0.012 | 0.039 | 0.159 | 0.558 | 2.122 | 7.109 | +| quickSortMiddle() | 0.013 | 0.045 | 0.185 | 0.650 | 2.518 | 8.303 | +| quickSortMedian() | 0.016 | 0.052 | 0.203 | 0.684 | 2.574 | 8.470 | +| quickSortMdnSwppd() | 0.012 | 0.039 | 0.160 | 0.560 | 2.128 | 7.129 | |---------------------+-------+-------+--------+---------+---------+---------| -| qsort() | 0.028 | 0.092 | 0.416 | 1.516 | 6.010 | 20.789 | +| qsort() | 0.027 | 0.092 | 0.417 | 1.515 | 6.009 | 20.782 | +---------------------+-------+-------+--------+---------+---------+---------+ ``` From d52da98ac04b2625f9db9cabade1aa17bfd3aab8 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 08:27:25 -0700 Subject: [PATCH 09/17] README.md: Add documentation of 3-argument sorting functions that accept a lambda expression or function pointer --- CHANGELOG.md | 15 ++++ README.md | 246 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 244 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 931601c..f15b1aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ # Changelog * Unreleased + * Add 3-argument versions of each sorting function which accepts a lambda + expression or function pointer that evalutes the general "less-than" + comparison between 2 elements in the array. + * Can be used to implement any sorting criteria, e.g. reverse sort, or + sorting using compound keys. + * Reimplement 2-argument versions of each sorting function to simply + call the 3-argument versions using a default "less-than" function + to give simple ascending order. + * The `quickSortXxx()` algorithms do not optimize well, probably due + to the recursive function call, so the 2-argument version is + duplicated from the 3-argument version. + * Add `examples/CompoundSortingDemo` to illustrate the 3-argument + sorting functions to sort by (name, score) pair. + * No changes observed to flash memory consumption or CPU execution + times. * v0.2 (2021-08-06) * Add Selection Sort, mostly for completeness. It's another `O(N^2)` sort but is slower than Insertion Sort, and is not a stable sort. diff --git a/README.md b/README.md index 762b30c..e1af621 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,6 @@ Supports the following algorithms: **Version**: 0.2 (2021-08-06) -**Status**: Simple versions are working and stable. Versions accepting custom -comparators coming soon. - **Changelog**: [CHANGELOG.md](CHANGELOG.md) ## Table of Contents @@ -67,6 +64,10 @@ comparators coming soon. * [Comb Sort](#CombSort) * [Quick Sort](#QuickSort) * [C Library Qsort](#CLibraryQsort) +* [Advanced Usage](#AdvancedUsage) + * [Function Pointer](#FunctionPointer) + * [Lambda Expression](#LambdaExpression) + * [Compiler Optimizations](#CompilerOptimizations) * [Resource Consumption](#ResourceConsumption) * [Flash And Static Memory](#FlashAndStaticMemory) * [CPU Cycles](#CpuCycles) @@ -180,6 +181,8 @@ Some of the examples may depend on: * [examples/HelloSort](examples/HelloSort) * A demo of one of the sorting functions. +* [examples/CompoundSortingDemo](examples/CompoundSortingDemo) + * Sorting by `name`, then break any ties by sorting by `score`. * Benchmarks * [examples/MemoryBenchmark](examples/MemoryBenchmark) * Determine flash and static RAM consumption of various algorithms. @@ -213,8 +216,12 @@ using ace_sorting::shellSortKnuth; See https://en.wikipedia.org/wiki/Bubble_sort. ```C++ +namespace ace_sorting { + template void bubbleSort(T data[], uint16_t n); + +} ``` * Flash consumption: 44 bytes on AVR @@ -229,8 +236,12 @@ void bubbleSort(T data[], uint16_t n); See https://en.wikipedia.org/wiki/Insertion_sort. ```C++ +namespace ace_sorting { + template void insertionSort(T data[], uint16_t n); + +} ``` * Flash consumption, 60 bytes on AVR @@ -246,8 +257,12 @@ void insertionSort(T data[], uint16_t n); See https://en.wikipedia.org/wiki/Selection_sort. ```C++ +namespace ace_sorting { + template void selectionSort(T data[], uint16_t n); + +} ``` * Flash consumption, 100 bytes on AVR @@ -267,6 +282,8 @@ See https://en.wikipedia.org/wiki/Shellsort. Three versions are provided in this library: ```C++ +namespace ace_sorting { + template void shellSortClassic(T data[], uint16_t n); @@ -275,6 +292,8 @@ void shellSortKnuth(T data[], uint16_t n); template void shellSortTokuda(T data[], uint16_t n); + +} ``` * Flash consumption: 100-180 bytes of flash on AVR @@ -293,6 +312,8 @@ and https://rosettacode.org/wiki/Sorting_algorithms/Comb_sort. Four versions are provided in this library: ```C++ +namespace ace_sorting { + template void combSort13(T data[], uint16_t n); @@ -304,12 +325,19 @@ void combSort133(T data[], uint16_t n); template void combSort133m(T data[], uint16_t n); + +} ``` * Flash consumption: 106-172 bytes on AVR * Additional ram consumption: none * Runtime complexity: `O(N^k)` where k seems similar to Shell Sort * Stable sort: No +* Upper limits: + * `combSort13()` and `combSort13m()`: `n = 6553` on 8-bit AVR processors + due to integer overflow. + * `combSort133()` and `combSort133m()`: `n = 21845` on 8-bit AVR processors + due to integer overflow. * **Recommendation**: * Use `combSort133()` on 8-bit processors. * Use `combSort13m()` on 32-bit processors. @@ -319,23 +347,25 @@ The `combSort13()` and `combSort13m()` functions use a gap factor of `10/13 = or 10. That apparently make the algorithm faster for reasons that I have not been able to find on the internet. -The `combSort133()` and `combSort133m()` use a gap factor of `4/3 = 1.33`. The -`4/3` ratio allows the compiler to replace an integer division with a left bit -shift, so that code is smaller and faster on 8-bit processors without hardware -integer division. The `combSort133m()` function modifies the gap sequence when -the gap is 9 or 10. +The `combSort133()` and `combSort133m()` functions use a gap factor of `4/3 = +1.33`. The `4/3` ratio allows the compiler to replace an integer division with a +left bit shift, so that code is smaller and faster on 8-bit processors without +hardware integer division. The `combSort133m()` function modifies the gap +sequence when the gap is 9 or 10. -Overall, [examples/AutoBenchmark](examples/AutoBenchmark) shows that Comb Sort -is consistently slower than Shell Sort so it is difficult to recommend it over -Shell Sort. +In terms of performance, [examples/AutoBenchmark](examples/AutoBenchmark) shows +that Comb Sort is consistently slower than Shell Sort so it is difficult to +recommend it over Shell Sort. ### Quick Sort -https://en.wikipedia.org/wiki/Quicksort. Three versions are provided in this +See https://en.wikipedia.org/wiki/Quicksort. Three versions are provided in this library: ```C++ +namespace ace_sorting { + template void quickSortMiddle(T data[], uint16_t n); @@ -344,8 +374,20 @@ void quickSortMedian(T data[], uint16_t n); template void quickSortMedianSwapped(T data[], uint16_t n); + +} ``` +* `quickSortMiddle()` + * The pivot is the middle element in each partition, regardless of its + value. +* `quickSortMedian()` + * The pivot is the median element among the 3 elements on the left, middle, + and right slots of each partition. +* `quickSortMedianSwapped()` + * The pivot is the median element among the 3 elements on the left, middle, + and right slots of each partition. + * The 3 elements are swapped so that they are sorted. * Flash consumption: 178-278 bytes on AVR * Additional ram consumption: `O(log(N))` bytes on stack due to recursion * Runtime complexity: `O(N log(N))` @@ -379,11 +421,173 @@ It has the following characteristics: * Stable sort: No * **Not recommended** due to excessive flash consumption and slowness. -According to benchmarks, `qsort()` is 2-3X slower than the C++ `quickSortXxx()`, -and consumes 4-5X more flash memory. The `qsort()` function is probably more -sophisticated in the handling of edge cases, but it suffers from being a general -function that uses pointer to a comparator call-back function. That makes it -2-3X slower than the C++ template functions in this library. Not recommended. +According to benchmarks, `qsort()` is 2-3X slower than the C++ `quickSortXxx()` +functions provided by this library, and consumes 4-5X more flash memory. The +`qsort()` function is probably more sophisticated in the handling of edge cases, +but it suffers from being a general function that uses a call-back function. The +overhead of that function call makes it 2-3X slower than the C++ template +functions in this library where the comparison function call is usually inlined +by the compiler. For these reasons, it is difficult to recommend the C-library +`qsort()` function. + + +## Advanced Usage + +Each sorting algorithm comes in another variant that takes 3 arguments instead +of 2 arguments. For completeness, here are the signatures of the 3-argument +variants: + +```C++ +namespace ace_sorting { + +template +void bubbleSort(T data[], uint16_t n, F&& lessThan); + +template +void insertionSort(T data[], uint16_t n, F&& lessThan); + +template +void selectionSort(T data[], uint16_t n, F&& lessThan); + +template +void shellSortClassic(T data[], uint16_t n, F&& lessThan); + +template +void shellSortKnuth(T data[], uint16_t n, F&& lessThan); + +template +void shellSortTokuda(T data[], uint16_t n, F&& lessThan); + +template +void combSort13(T data[], uint16_t n, F&& lessThan); + +template +void combSort13m(T data[], uint16_t n, F&& lessThan); + +template +void combSort133(T data[], uint16_t n, F&& lessThan); + +template +void combSort133m(T data[], uint16_t n, F&& lessThan); + +template +void quickSortMiddle(T data[], uint16_t n, F&& lessThan); + +template +void quickSortMedian(T data[], uint16_t n, F&& lessThan); + +template +void quickSortMedianSwapped(T data[], uint16_t n, F&& lessThan); + +} +``` + +The 3rd argument `lessThan` is a user-defined function pointer or a lambda +expression that implements the "less than" comparison operator between 2 +elements in the `data[]` array. (The `F&&` is a C++11 syntax that means "rvalue +reference to a templatized type of `F`".) In the context of this library, the +`lessThan` parameter can be thought of as a function-like thing that accepts 2 +elements of type `T` and returns a `bool`. Two types of this `lessThan` +parameter is explained below. + + +### Function Pointer + +If `lessThan` is a function pointer, then its signature should look something +like one of these: + +```C++ +bool lessThan(const T& a, const T& b); + +bool lessThan(T a, T b); +``` + +The [examples/CompoundSortingDemo](examples/CompoundSortingDemo) example shows +what this looks like to sort an array of pointers to `Record` entries by +`score`, then by `name`, to break any ties: + +```C++ +struct Record { + const char* name; + int score; +}; + +bool sortByScoreThenName(const Record* a, const Record* b) { + if (a->score < b->score) { + return true; + } else if (a->score > b->score) { + return false; + } else { + return strcmp(a->name, b->name) < 0; + } +} + +const uint16_t ARRAY_SIZE = 10; +const Record RECORDS[ARRAY_SIZE] = { + ... +}; + +const Record* recordPtrs[ARRAY_SIZE]; + +void doSorting() { + shellSortKnuth(recordPtrs, ARRAY_SIZE, sortByScoreThenName); + ... +} +``` + + +### Lambda Expression + +Through the magic of C++ templates, the `lessThan` parameter can also be a +lambda expression. When the comparison operator is simple and short, this +feature can save us the hassle of creating a separate function that is used only +once. + +The [examples/HelloSort](examples/HelloSort) example shows how to sort an array +of integers in reverse order using an inlined lambda expression that reverses +the comparison operator: + +```C++ +const uint16_t ARRAY_SIZE = 20; +int array[ARRAY_SIZE]; + +void doSorting() { + shellSortKnuth(array, ARRAY_SIZE, [](int a, int b) { return a > b; }); + ... +} +``` + + +### Compiler Optimizations + +All 2-argument variants of the sorting functions (except for the Quick Sort +functions `quickSortXxx()`, see below) are implemented by simply calling the +3-argument sorting functions using a default lambda expression using the `<` +operator like this: + +```C++ +template +void shellSortKnuth(T data[], uint16_t n) { + auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; }; + shellSortKnuth(data, n, lessThan); +} +``` + +The benchmarks in [examples/MemoryBenchmark](examples/MemoryBenchmark) show that +the compiler is able to completely optimize away the overhead of the inlined +lambda expression and produce code that is equivalent to inserting the `<` +binary operator directly into the code that implements the 3-argument variant. +No additional flash memory is consumed. + +The only exception to this compiler optimization occurs with the Quick Sort +algorithms. The compiler seems unable to optimize away the extra layer of +indirection, probably due to the recursive function calls in the Quick Sort +algorithms. Therefore, the 2-argument variants of `quickSortXxx()` algorithms +are duplicated from the 3-argument variants with the simple `<` operator +hardcoded, so that the simple case of ascending sorting consumes as little flash +memory as possible. (In the source code, the `ACE_SORTING_DIRECT_QUICK_SORT` +macro is set to `1` by default to achieve this, in contrast to all other sorting +functions where the equivalent macro is set to `0`.) ## Resource Consumption @@ -586,6 +790,14 @@ them. processors, and 8 bytes on 64-bit processors. However, I did not want to worry about edge case behavior of some of these algorithms for extremely large values of `n`. +* The behavior of the sorting algorithms with a `data` size of exactly `n = + 65535` has not been validated. + * Some algorithms may be buggy in this edge case due to integer overflows. + * The actual maximum value of `n` may actually be `65534` for + some algorithms. +* Some of the Comb Sort algorithms have even lower limits of `n` due to integer + overflows. + * See remarks above and in the source code. * No hybrid sorting algorithms. * Different sorting algorithms are more efficient at different ranges of `N`. So hybrid algorithms will use different sorting algorithms at From b7c33cb0f58517ded80ccb7533dcf7d7b69324d3 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 08:52:23 -0700 Subject: [PATCH 10/17] library.properties: Expand short description with list of sorting algorithms --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 9d185a2..0f49b01 100644 --- a/library.properties +++ b/library.properties @@ -2,8 +2,8 @@ name=AceSorting version=0.2.0 author=Brian T. Park maintainer=Brian T. Park -sentence=Various sorting algorithms for Arduino. -paragraph=Bubble Sort, Insertion Sort, Selection Sort, Shell Sort, Comb Sort, Quick Sort. +sentence=Various sorting algorithms for Arduino, including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions). +paragraph=Provides 2 variants of each algorithm: a simple variant which sorts in ascending order using the implicit less-than operator, and a three-argument variant that accepts a function pointer or lambda expression to sort using a user-defined sorting function. category=Data Processing url=https://github.com/bxparks/AceSorting architectures=* From 82f4736c076eba2031348c30b3470ad1b98cd4d4 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 09:17:39 -0700 Subject: [PATCH 11/17] examples/HelloSorting: Renamed from HelloSort to prevent confusion that HelloSort is a type of sorting algorithm --- CHANGELOG.md | 2 +- README.md | 41 ++++++++++--------- .../HelloSorting.ino} | 0 examples/{HelloSort => HelloSorting}/Makefile | 2 +- 4 files changed, 24 insertions(+), 21 deletions(-) rename examples/{HelloSort/HelloSort.ino => HelloSorting/HelloSorting.ino} (100%) rename examples/{HelloSort => HelloSorting}/Makefile (89%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f15b1aa..d0cd49a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ * v0.2 (2021-08-06) * Add Selection Sort, mostly for completeness. It's another `O(N^2)` sort but is slower than Insertion Sort, and is not a stable sort. - * Add [examples/HelloSort](examples/HelloSort). + * Add [examples/HelloSorting](examples/HelloSorting). * Add **tl;dr** section in README.md to summarize my recommendations. * v0.1 (2021-08-04) * Add `combSort133()` which uses a gap factor of 4/3, which eliminates diff --git a/README.md b/README.md index e1af621..cad6ef5 100644 --- a/README.md +++ b/README.md @@ -31,17 +31,20 @@ Supports the following algorithms: **tl;dr** -* In most cases, use `shellSortKnuth()`, costing only 142 bytes on an AVR and - 80-112 bytes on 32-bit processors. It is faster than any `O(N^2)` algorithm - while consuming only 34-82 extra bytes of flash over `insertionSort()`. -* If `N > ~100`, and you need faster sorting, and you have sufficient memory for - recursive functions, use `quickSortMiddle()` on 8-bit AVR processors, and - `quickSortMedianSwapped()` on 32-bit processors. -* Use `insertionSort()` if you need a stable sort. +* In most cases, use `shellSortKnuth()`. + * It costs only 142 bytes on an AVR and 80-112 bytes on 32-bit processors. + * It is faster than any `O(N^2)` algorithm while consuming only 34-82 extra + bytes of flash over `insertionSort()`. +* If `N > ~100`, *and* you have sufficient static memory for recursive + functions, *and* `shellSortKnuth()` is not fast enough, use + `quickSortMiddle()` on 8-bit AVR processors, and `quickSortMedianSwapped()` on + 32-bit processors. * Use `combSort133()` or `shellSortClassic()` to get the smallest sorting function faster than `O(N^2)`. -* Don't use the C library `qsort()`. It is 2-3X slower than the `quickSortXxx()` - functions in this library, and consumes 4-5X more in flash bytes. +* Use `insertionSort()` if you need a stable sort. +* Don't use the C library `qsort()`. + * It is 2-3X slower than the `quickSortXxx()` functions in this library, and + consumes 4-5X more in flash bytes. **Version**: 0.2 (2021-08-06) @@ -49,7 +52,7 @@ Supports the following algorithms: ## Table of Contents -* [Hello Sort](#HelloSort) +* [Hello Sorting](#HelloSorting) * [Installation](#Installation) * [Source Code](#SourceCode) * [Dependencies](#Dependencies) @@ -81,11 +84,11 @@ Supports the following algorithms: * [Feedback and Support](#FeedbackAndSupport) * [Authors](#Authors) - -## Hello Sort + +## Hello Sorting -This is a simplified version of the [examples/HelloSort](examples/HelloSort) -demo: +This is a simplified version of the +[examples/HelloSorting](examples/HelloSorting) demo: ```C++ #include @@ -93,7 +96,7 @@ demo: using ace_sorting::shellSortKnuth; -const uint16_t ARRAY_SIZE = 50; +const uint16_t ARRAY_SIZE = 20; int array[ARRAY_SIZE]; void printArray(int* array, uint16_t arraySize) { @@ -179,7 +182,7 @@ Some of the examples may depend on: ### Examples -* [examples/HelloSort](examples/HelloSort) +* [examples/HelloSorting](examples/HelloSorting) * A demo of one of the sorting functions. * [examples/CompoundSortingDemo](examples/CompoundSortingDemo) * Sorting by `name`, then break any ties by sorting by `score`. @@ -543,9 +546,9 @@ lambda expression. When the comparison operator is simple and short, this feature can save us the hassle of creating a separate function that is used only once. -The [examples/HelloSort](examples/HelloSort) example shows how to sort an array -of integers in reverse order using an inlined lambda expression that reverses -the comparison operator: +The [examples/HelloSorting](examples/HelloSorting) example shows how to sort an +array of integers in reverse order using an inlined lambda expression that +reverses the comparison operator: ```C++ const uint16_t ARRAY_SIZE = 20; diff --git a/examples/HelloSort/HelloSort.ino b/examples/HelloSorting/HelloSorting.ino similarity index 100% rename from examples/HelloSort/HelloSort.ino rename to examples/HelloSorting/HelloSorting.ino diff --git a/examples/HelloSort/Makefile b/examples/HelloSorting/Makefile similarity index 89% rename from examples/HelloSort/Makefile rename to examples/HelloSorting/Makefile index 10ae8dd..410bf65 100644 --- a/examples/HelloSort/Makefile +++ b/examples/HelloSorting/Makefile @@ -1,6 +1,6 @@ # See https://github.com/bxparks/EpoxyDuino for documentation about using # EpoxyDuino to compile and run AUnit tests natively on Linux or MacOS. -APP_NAME := HelloSort +APP_NAME := HelloSorting ARDUINO_LIBS := AceSorting include ../../../EpoxyDuino/EpoxyDuino.mk From 9861358577abc1b5a08e9287f229aa28574a6c19 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 09:30:56 -0700 Subject: [PATCH 12/17] README.md: Add note that sort() in Arduino_AVRSTL library is a bubble sort --- README.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index cad6ef5..d5f4816 100644 --- a/README.md +++ b/README.md @@ -783,19 +783,21 @@ them. * If you need bigger, copy the sorting algorithm that you want and change the `uint16_t n` to a `uint32_t n`. * Using a fixed `uint16_t` means that the edge case behavior of these - algorithms are consistency across all platforms. + algorithms are consistent across all platforms. * Certain implementation choices and optimizations can be made if we know - that `n` cannot exceed a bounded value. For example, the - `shellSortTokuda()` function can use a pre-generated sequence of gaps - which is a reasonable size because it only needs to go up to 65535. + that `n` cannot exceed a bounded value. + * For example, the `shellSortTokuda()` function can use a pre-generated + sequence of gaps which is a reasonable size because it only needs to + go up to 65535. * The alternative was to use the `size_t` type whose size is different on different platforms: 2 bytes on 8-bit processors, 4 bytes on 32-bit - processors, and 8 bytes on 64-bit processors. However, I did not want to - worry about edge case behavior of some of these algorithms for extremely - large values of `n`. + processors, and 8 bytes on 64-bit processors. + * However, I did not want to worry about edge case behavior of some of + these algorithms for extremely large values of `n`. * The behavior of the sorting algorithms with a `data` size of exactly `n = 65535` has not been validated. - * Some algorithms may be buggy in this edge case due to integer overflows. + * Some algorithms may be buggy because this edge case may trigger + an integer overflow. * The actual maximum value of `n` may actually be `65534` for some algorithms. * Some of the Comb Sort algorithms have even lower limits of `n` due to integer @@ -835,14 +837,13 @@ handful, but I found them unsuitable for me. `quickSortMiddle()` provided by this library. * No unit tests provided. * https://github.com/arduino-libraries/Arduino_AVRSTL - * Provides a template `sort()` function. - * Often STL library functions are too general, therefore, too bloated for - many resource constrained environments. I suspect that the STL `sort()` - function falls into this category. + * Provides a template `sort()` function, which delegates to `stable_sort()`. + * But this implementation is a bubble sort which is `O(N^2)` and + is not even stable. + * In fairness, there is a "FIXME" note in the code which + implies that a better algorithm ought to be provided. * The library is configured to target only the `avr` and `megaavr` - platforms. Does it work on other processors? I don't know, and I don't - want to spend the time to figure that out, because working with the STL - code is too painful. + platforms. * No unit tests provided. Here are some of the reasons that I created my own library: @@ -856,10 +857,10 @@ Here are some of the reasons that I created my own library: algorithms. I wanted to know these numbers precisely so that I could make informed trade off decisions. * I did not want to deal with the complexity of the C++ STL library. It is just - too painful in an embedded environment. + too painful in small embedded programming projects. * Lastly, I wanted to implement my own sorting routines to make sure that I had - a complete understanding of each algorithm. I had forgotten so much since my - undergraduate years. + a complete understanding of each algorithm. I had forgotten so much since + learning many of these in my undergraduate years. ## License From d47d1c700263bab248d8d10585eb6dc0d1850774 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 09:34:47 -0700 Subject: [PATCH 13/17] README.md: Update Tool Chain versions to ArduinoCLI 0.15.2 and Teensyduino 1.54 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5f4816..5474030 100644 --- a/README.md +++ b/README.md @@ -757,7 +757,7 @@ The following boards are **not** supported: ### Tool Chain * [Arduino IDE 1.8.13](https://www.arduino.cc/en/Main/Software) -* [Arduino CLI 0.14.0](https://arduino.github.io/arduino-cli) +* [Arduino CLI 0.15.2](https://arduino.github.io/arduino-cli) * [SpenceKonde ATTinyCore 1.5.2](https://github.com/SpenceKonde/ATTinyCore) * [Arduino AVR Boards 1.8.3](https://github.com/arduino/ArduinoCore-avr) * [Arduino SAMD Boards 1.8.9](https://github.com/arduino/ArduinoCore-samd) @@ -766,7 +766,7 @@ The following boards are **not** supported: * [STM32duino 2.0.0](https://github.com/stm32duino/Arduino_Core_STM32) * [ESP8266 Arduino 2.7.4](https://github.com/esp8266/Arduino) * [ESP32 Arduino 1.0.6](https://github.com/espressif/arduino-esp32) -* [Teensyduino 1.53](https://www.pjrc.com/teensy/td_download.html) +* [Teensyduino 1.54](https://www.pjrc.com/teensy/td_download.html) ### Operating System From 13f8c17cafeec517797e6ce294adeb539bf6c436 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 10:37:57 -0700 Subject: [PATCH 14/17] Bump version to v0.3 --- CHANGELOG.md | 1 + README.md | 51 ++++++++++++++----- docs/doxygen.cfg | 4 +- examples/AutoBenchmark/README.md | 4 +- examples/AutoBenchmark/generate_readme.py | 4 +- examples/MemoryBenchmark/README.md | 6 +-- examples/MemoryBenchmark/generate_readme.py | 6 +-- examples/WorstCaseBenchmark/README.md | 2 +- .../WorstCaseBenchmark/generate_readme.py | 2 +- library.properties | 2 +- src/AceSorting.h | 4 +- 11 files changed, 55 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cd49a..03412fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog * Unreleased +* v0.3 (2021-08-23) * Add 3-argument versions of each sorting function which accepts a lambda expression or function pointer that evalutes the general "less-than" comparison between 2 elements in the array. diff --git a/README.md b/README.md index 5474030..fa23189 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Supports the following algorithms: * It is 2-3X slower than the `quickSortXxx()` functions in this library, and consumes 4-5X more in flash bytes. -**Version**: 0.2 (2021-08-06) +**Version**: 0.3 (2021-08-23) **Changelog**: [CHANGELOG.md](CHANGELOG.md) @@ -138,17 +138,16 @@ void loop() {} ## Installation -The latest stable release will eventually be available in the Arduino IDE -Library Manager. Search for "AceSorting". Click install. (It is not there -yet.) +The latest stable release is available in the Arduino IDE Library Manager. +Search for "AceSorting". Click install. The development version can be installed by cloning the [GitHub repository](https://github.com/bxparks/AceSorting), checking out the -`develop` branch, then manually copying over the contents to the `./libraries` -directory used by the Arduino IDE. (The result is a directory named -`./libraries/AceSorting`.) +`develop` branch, then manually copying over to or creating a symlink from the +`./libraries` directory used by the Arduino IDE. (The result is a directory +or link named `./libraries/AceSorting`.) -The `master` branch contains the stable release. +The `master` branch contains the stable releases. ### Source Code @@ -183,9 +182,10 @@ Some of the examples may depend on: ### Examples * [examples/HelloSorting](examples/HelloSorting) - * A demo of one of the sorting functions. + * A simple demo of one of the sorting functions. * [examples/CompoundSortingDemo](examples/CompoundSortingDemo) - * Sorting by `name`, then break any ties by sorting by `score`. + * A more complex example of sorting by a compound key, first by + `score`, then breaking any ties by `name`. * Benchmarks * [examples/MemoryBenchmark](examples/MemoryBenchmark) * Determine flash and static RAM consumption of various algorithms. @@ -193,7 +193,7 @@ Some of the examples may depend on: * Determine CPU runtime of various algorithms. * [examples/WorstCaseBenchmark](examples/WorstCaseBenchmark) * Determine CPU runtime of worst case input data (e.g. sorted, reverse - sorted). + sorted). ## Usage @@ -205,7 +205,8 @@ Only a single header file `AceSorting.h` is required to use this library. To prevent name clashes with other libraries that the calling code may use, all classes are defined in the `ace_sorting` namespace. To use the code without prepending the `ace_sorting::` prefix, use the `using` directive to select the -specific algorithm: +specific algorithm. For example, to use the `shellSortKnut()` function, use +something like this: ```C++ #include @@ -231,6 +232,9 @@ void bubbleSort(T data[], uint16_t n); * Additional ram consumption: none * Runtime complexity: `O(N^2)` * Stable sort: Yes +* Performance Notes: + * If `data[]` is already sorted, this is `O(N)`. + * Worst performance `O(N^2)` when data is reverse sorted. * **Not recommended** @@ -251,6 +255,9 @@ void insertionSort(T data[], uint16_t n); * Additional ram consumption: none * Runtime complexity: `O(N^2)` but 5-6X faster than `bubbleSort()` * Stable sort: Yes +* Performance Notes: + * If `data[]` is already sorted, this algorithm is `O(N)`. + * Worst performance `O(N^2)` when data is reverse sorted. * **Recommendation**: Use for N smaller than about 100 and only if you need a stable sort @@ -272,6 +279,9 @@ void selectionSort(T data[], uint16_t n); * Additional ram consumption: none * Runtime complexity: `O(N^2)` but 2X slower than `insertionSort()` * Stable sort: No +* Performance Notes: + * Little change in performance when data is already sorted or reverse + sorted. * **Not recommended**: * Larger and slower than `insertionSort()` but is not a stable sort. * The only thing it has going for it is that it has the least number of @@ -303,6 +313,10 @@ void shellSortTokuda(T data[], uint16_t n); * Additional ram consumption: none * Runtime complexity: `O(N^k)` where `k=1.3 to 1.5` * Stable sort: No +* Performance Notes: + * As fast as Quick Sort for `N < ~100`. + * Little change in performance when data is already sorted or reverse + sorted. * **Recomendation**: Use `shellSortKnuth()`, which seems consistently faster than `shellSortClassic()`, just as fast as `shellSortTokuda()` but is simpler and takes less flash memory than `shellSortTokuda()`. @@ -336,12 +350,17 @@ void combSort133m(T data[], uint16_t n); * Additional ram consumption: none * Runtime complexity: `O(N^k)` where k seems similar to Shell Sort * Stable sort: No +* Performance Notes: + * Slightly slower than Shell Sort over similar data sets. + * Little change in performance when data is already sorted or reverse + sorted. * Upper limits: * `combSort13()` and `combSort13m()`: `n = 6553` on 8-bit AVR processors due to integer overflow. * `combSort133()` and `combSort133m()`: `n = 21845` on 8-bit AVR processors due to integer overflow. * **Recommendation**: + * Prefer Shell Sort over Comb Sort in most situations. * Use `combSort133()` on 8-bit processors. * Use `combSort13m()` on 32-bit processors. @@ -395,6 +414,10 @@ void quickSortMedianSwapped(T data[], uint16_t n); * Additional ram consumption: `O(log(N))` bytes on stack due to recursion * Runtime complexity: `O(N log(N))` * Stable sort: No +* Performance Notes: + * Fastest algorithm for large (`N > ~100`) data sets. + * Little change in performance when data is already sorted or reverse + sorted. * **Recommendation** * Avoid on 8-bit processors with limited ram due to extra stack usage by recursion. @@ -838,8 +861,8 @@ handful, but I found them unsuitable for me. * No unit tests provided. * https://github.com/arduino-libraries/Arduino_AVRSTL * Provides a template `sort()` function, which delegates to `stable_sort()`. - * But this implementation is a bubble sort which is `O(N^2)` and - is not even stable. + * But this implementation is a bubble sort which is `O(N^2)` and in practice + much slower than `insertionSort(). * In fairness, there is a "FIXME" note in the code which implies that a better algorithm ought to be provided. * The library is configured to target only the `avr` and `megaavr` diff --git a/docs/doxygen.cfg b/docs/doxygen.cfg index fa4b787..a1aaef4 100644 --- a/docs/doxygen.cfg +++ b/docs/doxygen.cfg @@ -38,13 +38,13 @@ PROJECT_NAME = "AceSorting" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.2 +PROJECT_NUMBER = 0.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "Sorting algorithms for Arduino (Bubble Sort, Insertion Sort, Shell Sort, Comb Sort, Quick Sort)" +PROJECT_BRIEF = "Sorting algorithms for Arduino including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions)" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 diff --git a/examples/AutoBenchmark/README.md b/examples/AutoBenchmark/README.md index c72b26f..02bd87b 100644 --- a/examples/AutoBenchmark/README.md +++ b/examples/AutoBenchmark/README.md @@ -2,7 +2,7 @@ Determine the speed of various AceSorting functions, for various array sizes. -**Version**: AceSorting v0.2 +**Version**: AceSorting v0.3 **DO NOT EDIT**: This file was auto-generated using `make README.md`. @@ -54,7 +54,7 @@ $ make README.md * The C-library `qsort()` is far slower than the C++ version because it uses a callback to a comparison function through a function pointer. -**v0.2+** +**v0.3** * No performance change after rerouting 2-argument sorting functions into the 3-argument versions using a default lambda expression. diff --git a/examples/AutoBenchmark/generate_readme.py b/examples/AutoBenchmark/generate_readme.py index 16ee0af..5ba16d4 100755 --- a/examples/AutoBenchmark/generate_readme.py +++ b/examples/AutoBenchmark/generate_readme.py @@ -27,7 +27,7 @@ Determine the speed of various AceSorting functions, for various array sizes. -**Version**: AceSorting v0.2 +**Version**: AceSorting v0.3 **DO NOT EDIT**: This file was auto-generated using `make README.md`. @@ -79,7 +79,7 @@ * The C-library `qsort()` is far slower than the C++ version because it uses a callback to a comparison function through a function pointer. -**v0.2+** +**v0.3** * No performance change after rerouting 2-argument sorting functions into the 3-argument versions using a default lambda expression. diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 8248437..53c89f9 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -5,7 +5,7 @@ memory and static RAM sizes were recorded. The `FEATURE_BASELINE` selection is the baseline, and its memory usage numbers are subtracted from the subsequent `FEATURE_*` memory usage. -**Version**: AceSorting v0.2 +**Version**: AceSorting v0.3 **DO NOT EDIT**: This file was auto-generated using `make README.md`. @@ -31,7 +31,7 @@ ASCII table. ## Library Size Changes -**v0.1.0** +**v0.1** * Initial version. * The memory usage for C-library `qsort()` is suspiciously low on the ESP32, @@ -39,7 +39,7 @@ ASCII table. indicates that the `qsort()` function is already compiled into the ESP32 runtime library. -**v0.2+** +**v0.3** * Add 3-argument version of sorting functions to pass in a comparison predicate, and route the 2-argument version into the 3-argument version. diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index 043c483..d369a19 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -29,7 +29,7 @@ the baseline, and its memory usage numbers are subtracted from the subsequent `FEATURE_*` memory usage. -**Version**: AceSorting v0.2 +**Version**: AceSorting v0.3 **DO NOT EDIT**: This file was auto-generated using `make README.md`. @@ -55,7 +55,7 @@ ## Library Size Changes -**v0.1.0** +**v0.1** * Initial version. * The memory usage for C-library `qsort()` is suspiciously low on the ESP32, @@ -63,7 +63,7 @@ indicates that the `qsort()` function is already compiled into the ESP32 runtime library. -**v0.2+** +**v0.3** * Add 3-argument version of sorting functions to pass in a comparison predicate, and route the 2-argument version into the 3-argument version. diff --git a/examples/WorstCaseBenchmark/README.md b/examples/WorstCaseBenchmark/README.md index e5a1461..5e3af6b 100644 --- a/examples/WorstCaseBenchmark/README.md +++ b/examples/WorstCaseBenchmark/README.md @@ -7,7 +7,7 @@ could trigger worst case runtime. Three types of arrays are tested: * already sorted array * reverse sorted array -**Version**: AceSorting v0.2 +**Version**: AceSorting v0.3 **DO NOT EDIT**: This file was auto-generated using `make README.md`. diff --git a/examples/WorstCaseBenchmark/generate_readme.py b/examples/WorstCaseBenchmark/generate_readme.py index 6f99678..1e53a6b 100755 --- a/examples/WorstCaseBenchmark/generate_readme.py +++ b/examples/WorstCaseBenchmark/generate_readme.py @@ -32,7 +32,7 @@ * already sorted array * reverse sorted array -**Version**: AceSorting v0.2 +**Version**: AceSorting v0.3 **DO NOT EDIT**: This file was auto-generated using `make README.md`. diff --git a/library.properties b/library.properties index 0f49b01..e5b9fab 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AceSorting -version=0.2.0 +version=0.3.0 author=Brian T. Park maintainer=Brian T. Park sentence=Various sorting algorithms for Arduino, including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions). diff --git a/src/AceSorting.h b/src/AceSorting.h index 522fd1a..4f64fe4 100644 --- a/src/AceSorting.h +++ b/src/AceSorting.h @@ -43,8 +43,8 @@ SOFTWARE. #endif // Version format: xxyyzz == "xx.yy.zz" -#define ACE_SORTING_VERSION 200 -#define ACE_SORTING_VERSION_STRING "0.2.0" +#define ACE_SORTING_VERSION 300 +#define ACE_SORTING_VERSION_STRING "0.3.0" #include "ace_sorting/swap.h" #include "ace_sorting/bubbleSort.h" From bf4b994b546ccf2bff83a6bb03fa9487af6a736c Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 10:46:43 -0700 Subject: [PATCH 15/17] src/*.h: Convert comments for ACE_SORTING_DIRECT_{xxx} into doxygen docstrings to silence warnings --- src/ace_sorting/bubbleSort.h | 10 ++++++---- src/ace_sorting/combSort.h | 10 ++++++---- src/ace_sorting/insertionSort.h | 10 ++++++---- src/ace_sorting/quickSort.h | 16 ++++++++++------ src/ace_sorting/selectionSort.h | 10 ++++++---- src/ace_sorting/shellSort.h | 10 ++++++---- 6 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/ace_sorting/bubbleSort.h b/src/ace_sorting/bubbleSort.h index 5af6225..616b6ca 100644 --- a/src/ace_sorting/bubbleSort.h +++ b/src/ace_sorting/bubbleSort.h @@ -33,11 +33,13 @@ SOFTWARE. #include "swap.h" -// If set to 1, use the direct inlined implementation of the 2-argument -// bubbleSort(). Otherwise, use the 3-argument bubbleSort() to implement -// 2-argument bubbleSort(). For bubbleSort, the compiler will optimize both -// versions to be identical. #if ! defined(ACE_SORTING_DIRECT_BUBBLE_SORT) + /** + * If set to 1, use the direct inlined implementation of the 2-argument + * bubbleSort(). Otherwise, use the 3-argument bubbleSort() to implement + * 2-argument bubbleSort(). For bubbleSort, the compiler will optimize both + * versions to be identical. + */ #define ACE_SORTING_DIRECT_BUBBLE_SORT 0 #endif diff --git a/src/ace_sorting/combSort.h b/src/ace_sorting/combSort.h index 56237b8..e3da961 100644 --- a/src/ace_sorting/combSort.h +++ b/src/ace_sorting/combSort.h @@ -33,11 +33,13 @@ SOFTWARE. #include "swap.h" -// If set to 1, use the direct inlined implementation of the 2-argument -// combSortXxx(). Otherwise, use the 3-argument combSortXxx() to implement -// 2-argument combSortXxx(). For combSortXxx(), the compiler will optimize both -// versions to be identical. #if ! defined(ACE_SORTING_DIRECT_COMB_SORT) + /** + * If set to 1, use the direct inlined implementation of the 2-argument + * combSortXxx(). Otherwise, use the 3-argument combSortXxx() to implement + * 2-argument combSortXxx(). For combSortXxx(), the compiler will optimize + * both versions to be identical. + */ #define ACE_SORTING_DIRECT_COMB_SORT 0 #endif diff --git a/src/ace_sorting/insertionSort.h b/src/ace_sorting/insertionSort.h index 659dcea..7117b71 100644 --- a/src/ace_sorting/insertionSort.h +++ b/src/ace_sorting/insertionSort.h @@ -32,11 +32,13 @@ SOFTWARE. #ifndef ACE_SORTING_INSERTION_SORT_H #define ACE_SORTING_INSERTION_SORT_H -// If set to 1, use the direct inlined implementation of the 2-argument -// insertionSort(). Otherwise, use the 3-argument insertionSort() to implement -// 2-argument insertionSort(). For insertionSort(), the compiler will optimize -// both versions to be identical. #if ! defined(ACE_SORTING_DIRECT_INSERTION_SORT) + /** + * If set to 1, use the direct inlined implementation of the 2-argument + * insertionSort(). Otherwise, use the 3-argument insertionSort() to implement + * 2-argument insertionSort(). For insertionSort(), the compiler will optimize + * both versions to be identical. + */ #define ACE_SORTING_DIRECT_INSERTION_SORT 0 #endif diff --git a/src/ace_sorting/quickSort.h b/src/ace_sorting/quickSort.h index 78006e5..7ffa9b4 100644 --- a/src/ace_sorting/quickSort.h +++ b/src/ace_sorting/quickSort.h @@ -34,13 +34,17 @@ SOFTWARE. #include "swap.h" -// If set to 1, use the direct inlined implementation of the 2-argument -// quickSortXxx(). Otherwise, use the 3-argument quickSortXxx() to implement -// 2-argument quickSortXxx(). Unlike other sorting algorithms, the compiler -// cannot seem to optimize away the extra level of indirection, probably due to -// the recursive calls. We save 40 bytes of flash (out of 200-300 bytes) if we -// use the direct inlined version for the 2-argument variant. Set this to 1. #if ! defined(ACE_SORTING_DIRECT_QUICK_SORT) + /** + * If set to 1, use the direct inlined implementation of the 2-argument + * quickSortXxx(). Otherwise, use the 3-argument quickSortXxx() to implement + * 2-argument quickSortXxx(). + * + * Unlike other sorting algorithms, the compiler cannot seem to optimize away + * the extra level of indirection, probably due to the recursive calls. We + * save 40 bytes of flash (out of 200-300 bytes) by setting this to 1 so that + * the 2-argument variant is manually inlined. + */ #define ACE_SORTING_DIRECT_QUICK_SORT 1 #endif diff --git a/src/ace_sorting/selectionSort.h b/src/ace_sorting/selectionSort.h index c283736..c09eadf 100644 --- a/src/ace_sorting/selectionSort.h +++ b/src/ace_sorting/selectionSort.h @@ -36,11 +36,13 @@ SOFTWARE. namespace ace_sorting { -// If set to 1, use the direct inlined implementation of the 2-argument -// selectionSort(). Otherwise, use the 3-argument selectionSort() to implement -// 2-argument selectionSort(). For selectionSort(), the compiler will optimize -// both versions to be identical. #if ! defined(ACE_SORTING_DIRECT_SELECTION_SORT) + /** + * If set to 1, use the direct inlined implementation of the 2-argument + * selectionSort(). Otherwise, use the 3-argument selectionSort() to implement + * 2-argument selectionSort(). For selectionSort(), the compiler will optimize + * both versions to be identical. + */ #define ACE_SORTING_DIRECT_SELECTION_SORT 0 #endif diff --git a/src/ace_sorting/shellSort.h b/src/ace_sorting/shellSort.h index c976219..cc8bf5f 100644 --- a/src/ace_sorting/shellSort.h +++ b/src/ace_sorting/shellSort.h @@ -32,11 +32,13 @@ SOFTWARE. #ifndef ACE_SORTING_SHELL_SORT_H #define ACE_SORTING_SHELL_SORT_H -// If set to 1, use the direct inlined implementation of the 2-argument -// shellSortXxx(). Otherwise, use the 3-argument shellSortXxx() to implement -// 2-argument shellSortXxx(). For shellSortXxx(), the compiler will optimize -// both versions to be identical. #if ! defined(ACE_SORTING_DIRECT_SHELL_SORT) + /** + * If set to 1, use the direct inlined implementation of the 2-argument + * shellSortXxx(). Otherwise, use the 3-argument shellSortXxx() to implement + * 2-argument shellSortXxx(). For shellSortXxx(), the compiler will optimize + * both versions to be identical. + */ #define ACE_SORTING_DIRECT_SHELL_SORT 0 #endif From f7447d4cc4ad6281699ae42eaaf3985b728e595b Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 23 Aug 2021 10:47:00 -0700 Subject: [PATCH 16/17] docs: Regenerate doxygen --- docs/html/AceSorting_8h_source.html | 8 +- docs/html/bubbleSort_8h.html | 88 ++++- docs/html/bubbleSort_8h_source.html | 69 +++- docs/html/combSort_8h.html | 267 ++++++++++++- docs/html/combSort_8h_source.html | 341 +++++++++++----- docs/html/dir_000000_000001.html | 4 +- .../dir_54c88fbaa58defb9f1b2842cb9ef0a89.html | 4 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 4 +- docs/html/files.html | 4 +- docs/html/globals.html | 94 +++++ docs/html/globals_defs.html | 94 +++++ docs/html/graph_legend.html | 4 +- docs/html/index.html | 4 +- docs/html/insertionSort_8h.html | 104 ++++- docs/html/insertionSort_8h__incl.map | 4 - docs/html/insertionSort_8h__incl.md5 | 1 - docs/html/insertionSort_8h__incl.png | Bin 5022 -> 0 bytes docs/html/insertionSort_8h_source.html | 101 +++-- docs/html/menudata.js | 5 +- docs/html/quickSort_8h.html | 207 +++++++++- docs/html/quickSort_8h_source.html | 360 ++++++++++++----- docs/html/search/all_0.js | 8 +- docs/html/search/all_1.js | 4 +- docs/html/search/all_2.js | 10 +- docs/html/search/all_3.js | 4 +- docs/html/search/all_4.js | 8 +- docs/html/search/all_5.js | 16 +- docs/html/search/defines_0.html | 30 ++ docs/html/search/defines_0.js | 9 + docs/html/search/files_0.js | 2 +- docs/html/search/files_1.js | 2 +- docs/html/search/files_2.js | 2 +- docs/html/search/files_3.js | 2 +- docs/html/search/files_4.js | 6 +- docs/html/search/functions_0.js | 2 +- docs/html/search/functions_1.js | 8 +- docs/html/search/functions_2.js | 2 +- docs/html/search/functions_3.js | 6 +- docs/html/search/functions_4.js | 10 +- docs/html/search/pages_0.js | 2 +- docs/html/search/searchdata.js | 9 +- docs/html/selectionSort_8h.html | 92 ++++- docs/html/selectionSort_8h_source.html | 134 ++++--- docs/html/shellSort_8h.html | 227 +++++++++-- docs/html/shellSort_8h__incl.map | 4 - docs/html/shellSort_8h__incl.md5 | 1 - docs/html/shellSort_8h__incl.png | Bin 4934 -> 0 bytes docs/html/shellSort_8h_source.html | 373 ++++++++++++------ docs/html/swap_8h.html | 14 +- docs/html/swap_8h__dep__incl.map | 10 +- docs/html/swap_8h__dep__incl.md5 | 2 +- docs/html/swap_8h__dep__incl.png | Bin 41777 -> 30006 bytes docs/html/swap_8h_source.html | 4 +- 53 files changed, 2166 insertions(+), 604 deletions(-) create mode 100644 docs/html/globals.html create mode 100644 docs/html/globals_defs.html delete mode 100644 docs/html/insertionSort_8h__incl.map delete mode 100644 docs/html/insertionSort_8h__incl.md5 delete mode 100644 docs/html/insertionSort_8h__incl.png create mode 100644 docs/html/search/defines_0.html create mode 100644 docs/html/search/defines_0.js delete mode 100644 docs/html/shellSort_8h__incl.map delete mode 100644 docs/html/shellSort_8h__incl.md5 delete mode 100644 docs/html/shellSort_8h__incl.png diff --git a/docs/html/AceSorting_8h_source.html b/docs/html/AceSorting_8h_source.html index 8f8b7f4..07d70c8 100644 --- a/docs/html/AceSorting_8h_source.html +++ b/docs/html/AceSorting_8h_source.html @@ -22,9 +22,9 @@
AceSorting -  0.2 +  0.3
-
Sorting algorithms for Arduino (Bubble Sort, Insertion Sort, Shell Sort, Comb Sort, Quick Sort)
+
Sorting algorithms for Arduino including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions)
@@ -105,8 +105,8 @@
43 #endif
44 
45 // Version format: xxyyzz == "xx.yy.zz"
-
46 #define ACE_SORTING_VERSION 200
-
47 #define ACE_SORTING_VERSION_STRING "0.2.0"
+
46 #define ACE_SORTING_VERSION 300
+
47 #define ACE_SORTING_VERSION_STRING "0.3.0"
48 
49 #include "ace_sorting/swap.h"
50 #include "ace_sorting/bubbleSort.h"
diff --git a/docs/html/bubbleSort_8h.html b/docs/html/bubbleSort_8h.html index c7db59b..0c60971 100644 --- a/docs/html/bubbleSort_8h.html +++ b/docs/html/bubbleSort_8h.html @@ -22,9 +22,9 @@
AceSorting -  0.2 +  0.3
-
Sorting algorithms for Arduino (Bubble Sort, Insertion Sort, Shell Sort, Comb Sort, Quick Sort)
+
Sorting algorithms for Arduino including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions)
@@ -68,6 +68,7 @@
bubbleSort.h File Reference
@@ -95,20 +96,50 @@

Go to the source code of this file.

+ + + + +

+Macros

#define ACE_SORTING_DIRECT_BUBBLE_SORT   0
 If set to 1, use the direct inlined implementation of the 2-argument bubbleSort(). More...
 
+ + + +

Functions

template<typename T >
void ace_sorting::bubbleSort (T data[], uint16_t n)
 Bubble sort. More...
 
template<typename T , typename F >
void ace_sorting::bubbleSort (T data[], uint16_t n, F &&lessThan)
 Same as the 2-argument bubbleSort() with the addition of a lessThan lambda expression or function. More...
 

Detailed Description

Bubble sort.

Definition in file bubbleSort.h.

-

Function Documentation

+

Macro Definition Documentation

+ +

◆ ACE_SORTING_DIRECT_BUBBLE_SORT

+ +
+
+ + + + +
#define ACE_SORTING_DIRECT_BUBBLE_SORT   0
+
+ +

If set to 1, use the direct inlined implementation of the 2-argument bubbleSort().

+

Otherwise, use the 3-argument bubbleSort() to implement 2-argument bubbleSort(). For bubbleSort, the compiler will optimize both versions to be identical.

+ +

Definition at line 43 of file bubbleSort.h.

+ +
+
+

Function Documentation

-

◆ bubbleSort()

+

◆ bubbleSort() [1/2]

@@ -144,7 +175,54 @@

Definition at line 45 of file bubbleSort.h.

+

Definition at line 70 of file bubbleSort.h.

+ +

+
+ +

◆ bubbleSort() [2/2]

+ +
+
+
+template<typename T , typename F >
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ace_sorting::bubbleSort (data[],
uint16_t n,
F && lessThan 
)
+
+ +

Same as the 2-argument bubbleSort() with the addition of a lessThan lambda expression or function.

+
Template Parameters
+ + + +
Ttype of data to sort
Ftype of lambda expression or function that returns true if a < b
+
+
+ +

Definition at line 84 of file bubbleSort.h.

diff --git a/docs/html/bubbleSort_8h_source.html b/docs/html/bubbleSort_8h_source.html index 7bb4d5f..cc1f828 100644 --- a/docs/html/bubbleSort_8h_source.html +++ b/docs/html/bubbleSort_8h_source.html @@ -22,9 +22,9 @@
AceSorting -  0.2 +  0.3
-
Sorting algorithms for Arduino (Bubble Sort, Insertion Sort, Shell Sort, Comb Sort, Quick Sort)
+
Sorting algorithms for Arduino including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions)
@@ -100,29 +100,56 @@
33 
34 #include "swap.h"
35 
-
36 namespace ace_sorting {
+
36 #if ! defined(ACE_SORTING_DIRECT_BUBBLE_SORT)
37 
-
44 template <typename T>
-
45 void bubbleSort(T data[], uint16_t n) {
-
46  bool swapped;
-
47  do {
-
48  swapped = false;
-
49  for (uint16_t i = 1; i < n; i++) {
-
50  if (data[i - 1] > data[i]) {
-
51  swap(data[i - 1], data[i]);
-
52  swapped = true;
-
53  }
-
54  }
-
55  } while (swapped);
-
56 }
-
57 
-
58 }
-
59 
-
60 #endif
+
43  #define ACE_SORTING_DIRECT_BUBBLE_SORT 0
+
44 #endif
+
45 
+
46 namespace ace_sorting {
+
47 
+
54 #if ACE_SORTING_DIRECT_BUBBLE_SORT
+
55 template <typename T>
+
56 void bubbleSort(T data[], uint16_t n) {
+
57  bool swapped;
+
58  do {
+
59  swapped = false;
+
60  for (uint16_t i = 1; i < n; i++) {
+
61  if (data[i] < data[i - 1]) {
+
62  swap(data[i - 1], data[i]);
+
63  swapped = true;
+
64  }
+
65  }
+
66  } while (swapped);
+
67 }
+
68 #else
+
69 template <typename T>
+
70 void bubbleSort(T data[], uint16_t n) {
+
71  auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; };
+
72  bubbleSort(data, n, lessThan);
+
73 }
+
74 #endif
+
75 
+
83 template <typename T, typename F>
+
84 void bubbleSort(T data[], uint16_t n, F&& lessThan) {
+
85  bool swapped;
+
86  do {
+
87  swapped = false;
+
88  for (uint16_t i = 1; i < n; i++) {
+
89  if (lessThan(data[i], data[i - 1])) {
+
90  swap(data[i - 1], data[i]);
+
91  swapped = true;
+
92  }
+
93  }
+
94  } while (swapped);
+
95 }
+
96 
+
97 }
+
98 
+
99 #endif
void swap(T &a, T &b)
Swap the parameters.
Definition: swap.h:41
-
void bubbleSort(T data[], uint16_t n)
Bubble sort.
Definition: bubbleSort.h:45
+
void bubbleSort(T data[], uint16_t n)
Bubble sort.
Definition: bubbleSort.h:70