diff --git a/src/Numerics/Sorting.cs b/src/Numerics/Sorting.cs index bebaeada..ba223ae5 100644 --- a/src/Numerics/Sorting.cs +++ b/src/Numerics/Sorting.cs @@ -67,7 +67,7 @@ namespace MathNet.Numerics } // local sort implementation - IntroSort(keys, null, comparer, 0, count - 1); + IntroSort(keys, comparer, 0, count - 1, (int a, int b) => Swap(keys, a, b)); } /// @@ -95,7 +95,12 @@ namespace MathNet.Numerics } // local sort implementation - IntroSort(keys, items, comparer, 0, count - 1); + Action swap = (int a, int b) => + { + Swap(keys, a, b); + Swap(items, a, b); + }; + IntroSort(keys, comparer, 0, count - 1, swap); } /// @@ -111,52 +116,20 @@ namespace MathNet.Numerics public static void Sort(IList keys, IList items1, IList items2, IComparer comparer = null) { int count = keys.Count; - if (count <= 1) - { - return; - } if (null == comparer) { comparer = Comparer.Default; } - if (count == 2) - { - if (comparer.Compare(keys[0], keys[1]) > 0) - { - Swap(keys, 0, 1); - Swap(items1, 0, 1); - Swap(items2, 0, 1); - } - return; - } - - // insertion sort - if (count <= 10) - { - for (int i = 1; i < count; i++) - { - var key = keys[i]; - var item1 = items1[i]; - var item2 = items2[i]; - int j = i - 1; - while (j >= 0 && comparer.Compare(keys[j], key) > 0) - { - keys[j + 1] = keys[j]; - items1[j + 1] = items1[j]; - items2[j + 1] = items2[j]; - j--; - } - keys[j + 1] = key; - items1[j + 1] = item1; - items2[j + 1] = item2; - } - return; - } - // local sort implementation - QuickSort(keys, items1, items2, comparer, 0, count - 1); + Action swap = (int a, int b) => + { + Swap(keys, a, b); + Swap(items1, a, b); + Swap(items2, a, b); + }; + IntroSort(keys, comparer, 0, count - 1, swap); } /// @@ -179,43 +152,11 @@ namespace MathNet.Numerics throw new ArgumentOutOfRangeException(nameof(count)); } - if (count <= 1) - { - return; - } - if (null == comparer) { comparer = Comparer.Default; } - if (count == 2) - { - if (comparer.Compare(keys[index], keys[index + 1]) > 0) - { - Swap(keys, index, index + 1); - } - return; - } - - // insertion sort - if (count <= 10) - { - int to = index + count; - for (int i = index + 1; i < to; i++) - { - var key = keys[i]; - int j = i - 1; - while (j >= index && comparer.Compare(keys[j], key) > 0) - { - keys[j + 1] = keys[j]; - j--; - } - keys[j + 1] = key; - } - return; - } - // array case if (keys is T[] keysArray) { @@ -231,7 +172,7 @@ namespace MathNet.Numerics } // fall back: local sort implementation - QuickSort(keys, comparer, index, count - 1); + IntroSort(keys, comparer, index, index + count, (int a, int b) => Swap(keys, a, b)); } /// @@ -256,56 +197,18 @@ namespace MathNet.Numerics throw new ArgumentOutOfRangeException(nameof(count)); } - if (count <= 1) - { - return; - } - if (null == comparer) { comparer = Comparer.Default; } - if (count == 2) - { - if (comparer.Compare(keys[index], keys[index + 1]) > 0) - { - Swap(keys, index, index + 1); - Swap(items, index, index + 1); - } - return; - } - - // insertion sort - if (count <= 10) - { - int to = index + count; - for (int i = index + 1; i < to; i++) - { - var key = keys[i]; - var item = items[i]; - int j = i - 1; - while (j >= index && comparer.Compare(keys[j], key) > 0) - { - keys[j + 1] = keys[j]; - items[j + 1] = items[j]; - j--; - } - keys[j + 1] = key; - items[j + 1] = item; - } - return; - } - - // array case - if (keys is TKey[] keysArray && items is TItem[] itemsArray) - { - Array.Sort(keysArray, itemsArray, index, count, comparer); - return; - } - // fall back: local sort implementation - QuickSort(keys, items, comparer, index, count - 1); + Action swap = (int a, int b) => + { + Swap(keys, a, b); + Swap(items, a, b); + }; + IntroSort(keys, comparer, index, index + count, swap); } /// @@ -332,53 +235,19 @@ namespace MathNet.Numerics throw new ArgumentOutOfRangeException(nameof(count)); } - if (count <= 1) - { - return; - } - if (null == comparer) { comparer = Comparer.Default; } - if (count == 2) - { - if (comparer.Compare(keys[index], keys[index + 1]) > 0) - { - Swap(keys, index, index + 1); - Swap(items1, index, index + 1); - Swap(items2, index, index + 1); - } - return; - } - - // insertion sort - if (count <= 10) - { - int to = index + count; - for (int i = index + 1; i < to; i++) - { - var key = keys[i]; - var item1 = items1[i]; - var item2 = items2[i]; - int j = i - 1; - while (j >= index && comparer.Compare(keys[j], key) > 0) - { - keys[j + 1] = keys[j]; - items1[j + 1] = items1[j]; - items2[j + 1] = items2[j]; - j--; - } - keys[j + 1] = key; - items1[j + 1] = item1; - items2[j + 1] = item2; - } - return; - } - // fall back: local sort implementation - QuickSort(keys, items1, items2, comparer, index, count - 1); + Action swap = (int a, int b) => + { + Swap(keys, a, b); + Swap(items1, a, b); + Swap(items2, a, b); + }; + IntroSort(keys, comparer, index, index + count, swap); } /// @@ -410,14 +279,13 @@ namespace MathNet.Numerics /// Recursively reorders the given list to satisfy the max heap property. /// /// The type of elements in the key list. - /// The type of elements in the item list. /// The list which is turned into a heap. - /// List of sattelliteData to "drag along" with the keys. Set to null to indicate no such data. /// The method with which to compare two elements of the heap. /// The index of the heap to heapify. /// The left boundary of the heapify. /// The right boundary of the heapify. - static void MaxHeapify(IList keys, IList satelliteData, IComparer comparer, int i, int left, int right) + /// An Action which takes the given indexes and swaps the key and satellite data. + static void MaxHeapify(IList keys, IComparer comparer, int i, int left, int right, Action swapper) { i -= left; int leftChild = 2 * i + 1; @@ -437,8 +305,8 @@ namespace MathNet.Numerics if (largest != i) { - Swap(keys, satelliteData, largest + left, i + left); - MaxHeapify(keys, satelliteData, comparer, largest + left, left, right); + swapper(largest + left, i + left); + MaxHeapify(keys, comparer, largest + left, left, right, swapper); } } @@ -446,18 +314,17 @@ namespace MathNet.Numerics /// /// /// The type of elements in the key list. - /// The type of elements in the item list. /// The list which is turned into a heap. - /// List of sattelliteData to "drag along" with the keys. Set to null to indicate no such data. /// The method with which to compare two elements of the heap. /// The left boundary of the heap. /// The right boundary of the heap. + /// An Action which takes the given indexes and swaps the key and satellite data. - static void BuildMaxHeap(IList keys, IList satelliteData, IComparer comparer, int left, int right) + static void BuildMaxHeap(IList keys, IComparer comparer, int left, int right, Action swapper) { for (int i = (right - left) / 2; i >= 0; i--) { - MaxHeapify(keys, satelliteData, comparer, i + left, left, right); + MaxHeapify(keys, comparer, i + left, left, right, swapper); } } @@ -465,14 +332,13 @@ namespace MathNet.Numerics /// Recursive implementation for an in place introspective sort on a list. /// /// The type of elements in the key list. - /// The type of elements in the item list. /// The list which is sorted using intro sort. - /// List of sattelliteData to "drag along" with the keys. Set to null to indicate no such data. /// The method with which to compare two elements of the intro sort. /// The left boundary of the intro sort. /// The right boundary of the intro sort. + /// An Action which takes the given indexes and swaps the key and satellite data. /// Tracks the number of recursions entered. - static void IntroSort(IList keys, IList satelliteData, IComparer comparer, int left, int right, int recursions = 0) + static void IntroSort(IList keys, IComparer comparer, int left, int right, Action swapper, int recursions = 0) { const double ln2 = 0.69314718056; // Natural Logarithm of 2 if (left >= right) @@ -490,27 +356,27 @@ namespace MathNet.Numerics int j = i; while (j > 0 && comparer.Compare(keys[j - 1], keys[j]) > 0) { - Swap(keys, satelliteData, j, j - 1); + swapper(j, j - 1); j--; } } } else if (recursions > max_recursion_depth) // Heapsort is guaranteed O(n log n) { - BuildMaxHeap(keys, satelliteData, comparer, left, right); + BuildMaxHeap(keys, comparer, left, right, swapper); int heapBoundary = right; for (int i = right - left; i > 0; i--) { - Swap(keys, satelliteData, left, left + i); - MaxHeapify(keys, satelliteData, comparer, left, left, --heapBoundary); + swapper(left, left + i); + MaxHeapify(keys, comparer, left, left, --heapBoundary, swapper); } } else // Quicksort { int pivot_index = (rand.Next() % (right - left)) + left; // Don't need to worry about negatives because rand.Next() returns a non-negative number - Swap(keys, satelliteData, pivot_index, right); + swapper(pivot_index, right); TKey pivot = keys[right]; @@ -520,16 +386,16 @@ namespace MathNet.Numerics if (comparer.Compare(keys[j], pivot) <= 0) { i++; - Swap(keys, satelliteData, i, j); + swapper(i, j); } } i++; - Swap(keys, satelliteData, i, right); + swapper(i, right); recursions++; - IntroSort(keys, satelliteData, comparer, left, i - 1, recursions); - IntroSort(keys, satelliteData, comparer, i + 1, right, recursions); + IntroSort(keys, comparer, left, i - 1, swapper, recursions); + IntroSort(keys, comparer, i + 1, right, swapper, recursions); } } @@ -925,33 +791,5 @@ namespace MathNet.Numerics keys[a] = keys[b]; keys[b] = local; } - - /// - /// Performs an in place swap of two elements in a list. - /// - /// The type of elements in the key list. - /// The type of elements in the item list. - /// The list in which the elements are stored. - /// List of sattelliteData to "drag along" with the keys. Set to null to indicate no such data. - /// The index of the first element of the swap. - /// The index of the second element of the swap. - static void Swap(IList keys, IList satelliteData, int a, int b) - { - if (a == b) - { - return; - } - - TKey local = keys[a]; - keys[a] = keys[b]; - keys[b] = local; - - if (satelliteData != null) - { - TItem tmp = satelliteData[a]; - satelliteData[a] = satelliteData[b]; - satelliteData[b] = tmp; - } - } } }