// // Math.NET Numerics, part of the Math.NET Project // http://mathnet.opensourcedotnet.info // // Copyright (c) 2009 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // namespace MathNet.Numerics { using System; using System.Collections.Generic; using System.Text; /// /// Sorting algorithms for single, tuple and triple lists. /// public static class Sorting { /// /// Sort a list of keys, inplace using the quick sort algorithm. /// /// The type of elements stored in the list. /// List to sort. public static void Sort(IList keys) { Sort(keys, Comparer.Default); } /// /// Sort a list of keys and items with respect to the keys, inplace using the quick sort algorithm. /// /// The type of elements stored in the key list. /// The type of elements stored in the item list. /// List to sort. /// List to permutate the same way as the key list. public static void Sort(IList keys, IList items) { Sort(keys, items, Comparer.Default); } /// /// Sort a list of keys, items1 and items2 with respect to the keys, inplace using the quick sort algorithm. /// /// The type of elements stored in the key list. /// The type of elements stored in the first item list. /// The type of elements stored in the second item list. /// List to sort. /// First list to permutate the same way as the key list. /// Second list to permutate the same way as the key list. public static void Sort(IList keys, IList items1, IList items2) { Sort(keys, items1, items2, Comparer.Default); } /// /// Sort a range of a list of keys, inplace using the quick sort algorithm. /// /// The type of elements in the key list. /// List to sort. /// The zero-based starting index of the range to sort. /// The length of the range to sort. public static void Sort(IList keys, int index, int count) { Sort(keys, index, count, Comparer.Default); } /// /// Sort a list of keys, inplace using the quick sort algorithm using the quick sort algorithm. /// /// The type of elements in the key list. /// List to sort. /// Comparison, defining the sort order. public static void Sort(IList keys, IComparer comparer) { if(null == keys) { throw new ArgumentNullException("keys"); } if(null == comparer) { throw new ArgumentNullException("comparer"); } // basic cases if(keys.Count <= 1) { return; } if(keys.Count == 2) { if(comparer.Compare(keys[0], keys[1]) > 0) { Swap(keys, 0, 1); } return; } // generic list case List list = keys as List; if(null != list) { list.Sort(comparer); return; } // array case T[] array = keys as T[]; if(null != array) { Array.Sort(array, comparer); return; } // local sort implementation QuickSort(keys, comparer, 0, keys.Count - 1); } /// /// Sort a list of keys and items with respect to the keys, inplace using the quick sort algorithm. /// /// The type of elements in the key list. /// The type of elements in the item list. /// List to sort. /// List to permutate the same way as the key list. /// Comparison, defining the sort order. public static void Sort(IList keys, IList items, IComparer comparer) { if(null == keys) { throw new ArgumentNullException("keys"); } if(null == items) { throw new ArgumentNullException("items"); } if(null == comparer) { throw new ArgumentNullException("comparer"); } // array case TKey[] keysArray = keys as TKey[]; TItem[] itemsArray = items as TItem[]; if((null != keysArray) && (null != itemsArray)) { Array.Sort(keysArray, itemsArray, comparer); return; } // local sort implementation QuickSort(keys, items, comparer, 0, keys.Count - 1); } /// /// Sort a list of keys, items1 and items2 with respect to the keys, inplace using the quick sort algorithm. /// /// The type of elements in the key list. /// The type of elements in the first item list. /// The type of elements in the second item list. /// List to sort. /// First list to permutate the same way as the key list. /// Second list to permutate the same way as the key list. /// Comparison, defining the sort order. public static void Sort( IList keys, IList items1, IList items2, IComparer comparer) { if(null == keys) { throw new ArgumentNullException("keys"); } if(null == items1) { throw new ArgumentNullException("items1"); } if(null == items2) { throw new ArgumentNullException("items2"); } if(null == comparer) { throw new ArgumentNullException("comparer"); } // local sort implementation QuickSort(keys, items1, items2, comparer, 0, keys.Count - 1); } /// /// Sort a range of a list of keys, inplace using the quick sort algorithm. /// /// The type of element in the list. /// List to sort. /// The zero-based starting index of the range to sort. /// The length of the range to sort. /// Comparison, defining the sort order. public static void Sort(IList keys, int index, int count, IComparer comparer) { if(null == keys) { throw new ArgumentNullException("keys"); } if(null == comparer) { throw new ArgumentNullException("comparer"); } if(index < 0 || index >= keys.Count) { throw new ArgumentOutOfRangeException("index"); } if(count < 0 || index + count > keys.Count) { throw new ArgumentOutOfRangeException("count"); } // basic cases if(count <= 1) { return; } if(count == 2) { if(comparer.Compare(keys[index], keys[index + 1]) > 0) { Swap(keys, index, index + 1); } return; } // generic list case List list = keys as List; if(null != list) { list.Sort(index, count, comparer); return; } // array case T[] array = keys as T[]; if(null != array) { Array.Sort(array, index, count, comparer); return; } // local sort implementation QuickSort(keys, comparer, index, count - 1); } /// /// Recursive implementation for an inplace quick sort on a list. /// /// The type of the list on which the quick sort is performed. /// The list which is sorted using quick sort. /// The method with which to compare two elements of the quick sort. /// The left boundary of the quick sort. /// The right boundary of the quick sort. private static void QuickSort(IList keys, IComparer comparer, int left, int right) { do { // Pivoting int a = left; int b = right; int p = a + ((b - a) >> 1); // midpoint if(comparer.Compare(keys[a], keys[p]) > 0) { Swap(keys, a, p); } if(comparer.Compare(keys[a], keys[b]) > 0) { Swap(keys, a, b); } if(comparer.Compare(keys[p], keys[b]) > 0) { Swap(keys, p, b); } T pivot = keys[p]; // Hoare Partitioning do { while(comparer.Compare(keys[a], pivot) < 0) { a++; } while(comparer.Compare(pivot, keys[b]) < 0) { b--; } if(a > b) { break; } if(a < b) { Swap(keys, a, b); } a++; b--; } while(a <= b); // In order to limit the recusion depth to log(n), we sort the // shorter partition recusively and the longer partition iteratively. if((b - left) <= (right - a)) { if(left < b) { QuickSort(keys, comparer, left, b); } left = a; } else { if(a < right) { QuickSort(keys, comparer, a, right); } right = b; } } while(left < right); } /// /// Recursive implementation for an inplace quick sort on a list while reordering one other list accordingly. /// /// The type of the list on which the quick sort is performed. /// The type of the list which is automatically reordered accordingly. /// The list which is sorted using quick sort. /// The list which is automatically reordered accordingly. /// The method with which to compare two elements of the quick sort. /// The left boundary of the quick sort. /// The right boundary of the quick sort. private static void QuickSort(IList keys, IList items, IComparer comparer, int left, int right) { do { // Pivoting int a = left; int b = right; int p = a + ((b - a) >> 1); // midpoint if(comparer.Compare(keys[a], keys[p]) > 0) { Swap(keys, a, p); Swap(items, a, p); } if(comparer.Compare(keys[a], keys[b]) > 0) { Swap(keys, a, b); Swap(items, a, b); } if(comparer.Compare(keys[p], keys[b]) > 0) { Swap(keys, p, b); Swap(items, p, b); } T pivot = keys[p]; // Hoare Partitioning do { while(comparer.Compare(keys[a], pivot) < 0) { a++; } while(comparer.Compare(pivot, keys[b]) < 0) { b--; } if(a > b) { break; } if(a < b) { Swap(keys, a, b); Swap(items, a, b); } a++; b--; } while(a <= b); // In order to limit the recusion depth to log(n), we sort the // shorter partition recusively and the longer partition iteratively. if((b - left) <= (right - a)) { if(left < b) { QuickSort(keys, items, comparer, left, b); } left = a; } else { if(a < right) { QuickSort(keys, items, comparer, a, right); } right = b; } } while(left < right); } /// /// Recursive implementation for an inplace quick sort on one list while reordering two other lists accordingly. /// /// The type of the list on which the quick sort is performed. /// The type of the first list which is automatically reordered accordingly. /// The type of the second list which is automatically reordered accordingly. /// The list which is sorted using quick sort. /// The first list which is automatically reordered accordingly. /// The second list which is automatically reordered accordingly. /// The method with which to compare two elements of the quick sort. /// The left boundary of the quick sort. /// The right boundary of the quick sort. private static void QuickSort( IList keys, IList items1, IList items2, IComparer comparer, int left, int right) { do { // Pivoting int a = left; int b = right; int p = a + ((b - a) >> 1); // midpoint if(comparer.Compare(keys[a], keys[p]) > 0) { Swap(keys, a, p); Swap(items1, a, p); Swap(items2, a, p); } if(comparer.Compare(keys[a], keys[b]) > 0) { Swap(keys, a, b); Swap(items1, a, b); Swap(items2, a, b); } if(comparer.Compare(keys[p], keys[b]) > 0) { Swap(keys, p, b); Swap(items1, p, b); Swap(items2, p, b); } T pivot = keys[p]; // Hoare Partitioning do { while(comparer.Compare(keys[a], pivot) < 0) { a++; } while(comparer.Compare(pivot, keys[b]) < 0) { b--; } if(a > b) { break; } if(a < b) { Swap(keys, a, b); Swap(items1, a, b); Swap(items2, a, b); } a++; b--; } while(a <= b); // In order to limit the recusion depth to log(n), we sort the // shorter partition recusively and the longer partition iteratively. if((b - left) <= (right - a)) { if(left < b) { QuickSort(keys, items1, items2, comparer, left, b); } left = a; } else { if(a < right) { QuickSort(keys, items1, items2, comparer, a, right); } right = b; } } while(left < right); } /// /// Performs an in place swap of two elements in a list. /// /// The type of elements stored in the list. /// The list in which the elements are stored. /// The index of the first element of the swap. /// The index of the second element of the swap. internal static void Swap(IList keys, int a, int b) { if(a != b) { T local = keys[a]; keys[a] = keys[b]; keys[b] = local; } } } }