|
|
|
@ -4,7 +4,7 @@ |
|
|
|
// http://github.com/mathnet/mathnet-numerics
|
|
|
|
// http://mathnetnumerics.codeplex.com
|
|
|
|
//
|
|
|
|
// Copyright (c) 2009-2010 Math.NET
|
|
|
|
// Copyright (c) 2009-2013 Math.NET
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person
|
|
|
|
// obtaining a copy of this software and associated documentation
|
|
|
|
@ -28,52 +28,16 @@ |
|
|
|
// OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
// </copyright>
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
|
|
namespace MathNet.Numerics |
|
|
|
{ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sorting algorithms for single, tuple and triple lists.
|
|
|
|
/// </summary>
|
|
|
|
public static class Sorting |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Sort a list of keys, in place using the quick sort algorithm.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">The type of elements stored in the list.</typeparam>
|
|
|
|
/// <param name="keys">List to sort.</param>
|
|
|
|
public static void Sort<T>(IList<T> keys) |
|
|
|
{ |
|
|
|
Sort(keys, Comparer<T>.Default); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sort a list of keys and items with respect to the keys, in place using the quick sort algorithm.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TKey">The type of elements stored in the key list.</typeparam>
|
|
|
|
/// <typeparam name="TItem">The type of elements stored in the item list.</typeparam>
|
|
|
|
/// <param name="keys">List to sort.</param>
|
|
|
|
/// <param name="items">List to permute the same way as the key list.</param>
|
|
|
|
public static void Sort<TKey, TItem>(IList<TKey> keys, IList<TItem> items) |
|
|
|
{ |
|
|
|
Sort(keys, items, Comparer<TKey>.Default); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sort a list of keys, items1 and items2 with respect to the keys, in place using the quick sort algorithm.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TKey">The type of elements stored in the key list.</typeparam>
|
|
|
|
/// <typeparam name="TItem1">The type of elements stored in the first item list.</typeparam>
|
|
|
|
/// <typeparam name="TItem2">The type of elements stored in the second item list.</typeparam>
|
|
|
|
/// <param name="keys">List to sort.</param>
|
|
|
|
/// <param name="items1">First list to permute the same way as the key list.</param>
|
|
|
|
/// <param name="items2">Second list to permute the same way as the key list.</param>
|
|
|
|
public static void Sort<TKey, TItem1, TItem2>(IList<TKey> keys, IList<TItem1> items1, IList<TItem2> items2) |
|
|
|
{ |
|
|
|
Sort(keys, items1, items2, Comparer<TKey>.Default); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sort a range of a list of keys, in place using the quick sort algorithm.
|
|
|
|
/// </summary>
|
|
|
|
@ -92,16 +56,11 @@ namespace MathNet.Numerics |
|
|
|
/// <typeparam name="T">The type of elements in the key list.</typeparam>
|
|
|
|
/// <param name="keys">List to sort.</param>
|
|
|
|
/// <param name="comparer">Comparison, defining the sort order.</param>
|
|
|
|
public static void Sort<T>(IList<T> keys, IComparer<T> comparer) |
|
|
|
public static void Sort<T>(IList<T> keys, IComparer<T> comparer = null) |
|
|
|
{ |
|
|
|
if (null == keys) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("keys"); |
|
|
|
} |
|
|
|
|
|
|
|
if (null == comparer) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("comparer"); |
|
|
|
comparer = Comparer<T>.Default; |
|
|
|
} |
|
|
|
|
|
|
|
// basic cases
|
|
|
|
@ -148,21 +107,11 @@ namespace MathNet.Numerics |
|
|
|
/// <param name="keys">List to sort.</param>
|
|
|
|
/// <param name="items">List to permute the same way as the key list.</param>
|
|
|
|
/// <param name="comparer">Comparison, defining the sort order.</param>
|
|
|
|
public static void Sort<TKey, TItem>(IList<TKey> keys, IList<TItem> items, IComparer<TKey> comparer) |
|
|
|
public static void Sort<TKey, TItem>(IList<TKey> keys, IList<TItem> items, IComparer<TKey> comparer = null) |
|
|
|
{ |
|
|
|
if (null == keys) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("keys"); |
|
|
|
} |
|
|
|
|
|
|
|
if (null == items) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("items"); |
|
|
|
} |
|
|
|
|
|
|
|
if (null == comparer) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("comparer"); |
|
|
|
comparer = Comparer<TKey>.Default; |
|
|
|
} |
|
|
|
|
|
|
|
#if !PORTABLE
|
|
|
|
@ -190,31 +139,40 @@ namespace MathNet.Numerics |
|
|
|
/// <param name="items1">First list to permute the same way as the key list.</param>
|
|
|
|
/// <param name="items2">Second list to permute the same way as the key list.</param>
|
|
|
|
/// <param name="comparer">Comparison, defining the sort order.</param>
|
|
|
|
public static void Sort<TKey, TItem1, TItem2>( |
|
|
|
IList<TKey> keys, IList<TItem1> items1, IList<TItem2> items2, IComparer<TKey> comparer) |
|
|
|
public static void Sort<TKey, TItem1, TItem2>(IList<TKey> keys, IList<TItem1> items1, IList<TItem2> items2, IComparer<TKey> comparer = null) |
|
|
|
{ |
|
|
|
if (null == keys) |
|
|
|
if (null == comparer) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("keys"); |
|
|
|
comparer = Comparer<TKey>.Default; |
|
|
|
} |
|
|
|
|
|
|
|
if (null == items1) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("items1"); |
|
|
|
} |
|
|
|
// local sort implementation
|
|
|
|
QuickSort(keys, items1, items2, comparer, 0, keys.Count - 1); |
|
|
|
} |
|
|
|
|
|
|
|
if (null == items2) |
|
|
|
/// <summary>
|
|
|
|
/// Sort a list of keys and items with respect to the keys, in place using the quick sort algorithm.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T1">The type of elements in the primary list.</typeparam>
|
|
|
|
/// <typeparam name="T2">The type of elements in the secondary list.</typeparam>
|
|
|
|
/// <param name="primary">List to sort.</param>
|
|
|
|
/// <param name="secondary">List to to sort on duplicate primaty items, and permute the same way as the key list.</param>
|
|
|
|
/// <param name="primaryComparer">Comparison, defining the primary sort order.</param>
|
|
|
|
/// <param name="secondaryComparer">Comparison, defining the secondary sort order.</param>
|
|
|
|
public static void SortAll<T1, T2>(IList<T1> primary, IList<T2> secondary, IComparer<T1> primaryComparer = null, IComparer<T2> secondaryComparer = null) |
|
|
|
{ |
|
|
|
if (null == primaryComparer) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("items2"); |
|
|
|
primaryComparer = Comparer<T1>.Default; |
|
|
|
} |
|
|
|
|
|
|
|
if (null == comparer) |
|
|
|
if (null == secondaryComparer) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("comparer"); |
|
|
|
secondaryComparer = Comparer<T2>.Default; |
|
|
|
} |
|
|
|
|
|
|
|
// local sort implementation
|
|
|
|
QuickSort(keys, items1, items2, comparer, 0, keys.Count - 1); |
|
|
|
QuickSortAll(primary, secondary, primaryComparer, secondaryComparer, 0, primary.Count - 1); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -225,18 +183,8 @@ namespace MathNet.Numerics |
|
|
|
/// <param name="index">The zero-based starting index of the range to sort.</param>
|
|
|
|
/// <param name="count">The length of the range to sort.</param>
|
|
|
|
/// <param name="comparer">Comparison, defining the sort order.</param>
|
|
|
|
public static void Sort<T>(IList<T> keys, int index, int count, IComparer<T> comparer) |
|
|
|
public static void Sort<T>(IList<T> keys, int index, int count, IComparer<T> comparer = null) |
|
|
|
{ |
|
|
|
if (null == keys) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("keys"); |
|
|
|
} |
|
|
|
|
|
|
|
if (null == comparer) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException("comparer"); |
|
|
|
} |
|
|
|
|
|
|
|
if (index < 0 || index >= keys.Count) |
|
|
|
{ |
|
|
|
throw new ArgumentOutOfRangeException("index"); |
|
|
|
@ -247,6 +195,11 @@ namespace MathNet.Numerics |
|
|
|
throw new ArgumentOutOfRangeException("count"); |
|
|
|
} |
|
|
|
|
|
|
|
if (null == comparer) |
|
|
|
{ |
|
|
|
comparer = Comparer<T>.Default; |
|
|
|
} |
|
|
|
|
|
|
|
// basic cases
|
|
|
|
if (count <= 1) |
|
|
|
{ |
|
|
|
@ -291,11 +244,7 @@ namespace MathNet.Numerics |
|
|
|
/// <param name="comparer">The method with which to compare two elements of the quick sort.</param>
|
|
|
|
/// <param name="left">The left boundary of the quick sort.</param>
|
|
|
|
/// <param name="right">The right boundary of the quick sort.</param>
|
|
|
|
private static void QuickSort<T>( |
|
|
|
IList<T> keys, |
|
|
|
IComparer<T> comparer, |
|
|
|
int left, |
|
|
|
int right) |
|
|
|
static void QuickSort<T>(IList<T> keys, IComparer<T> comparer, int left, int right) |
|
|
|
{ |
|
|
|
do |
|
|
|
{ |
|
|
|
@ -346,10 +295,9 @@ namespace MathNet.Numerics |
|
|
|
|
|
|
|
a++; |
|
|
|
b--; |
|
|
|
} |
|
|
|
while (a <= b); |
|
|
|
} while (a <= b); |
|
|
|
|
|
|
|
// In order to limit the recusion depth to log(n), we sort the
|
|
|
|
// 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)) |
|
|
|
{ |
|
|
|
@ -369,8 +317,7 @@ namespace MathNet.Numerics |
|
|
|
|
|
|
|
right = b; |
|
|
|
} |
|
|
|
} |
|
|
|
while (left < right); |
|
|
|
} while (left < right); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -383,12 +330,7 @@ namespace MathNet.Numerics |
|
|
|
/// <param name="comparer">The method with which to compare two elements of the quick sort.</param>
|
|
|
|
/// <param name="left">The left boundary of the quick sort.</param>
|
|
|
|
/// <param name="right">The right boundary of the quick sort.</param>
|
|
|
|
private static void QuickSort<T, TItems>( |
|
|
|
IList<T> keys, |
|
|
|
IList<TItems> items, |
|
|
|
IComparer<T> comparer, |
|
|
|
int left, |
|
|
|
int right) |
|
|
|
static void QuickSort<T, TItems>(IList<T> keys, IList<TItems> items, IComparer<T> comparer, int left, int right) |
|
|
|
{ |
|
|
|
do |
|
|
|
{ |
|
|
|
@ -443,10 +385,9 @@ namespace MathNet.Numerics |
|
|
|
|
|
|
|
a++; |
|
|
|
b--; |
|
|
|
} |
|
|
|
while (a <= b); |
|
|
|
} while (a <= b); |
|
|
|
|
|
|
|
// In order to limit the recusion depth to log(n), we sort the
|
|
|
|
// 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)) |
|
|
|
{ |
|
|
|
@ -466,8 +407,7 @@ namespace MathNet.Numerics |
|
|
|
|
|
|
|
right = b; |
|
|
|
} |
|
|
|
} |
|
|
|
while (left < right); |
|
|
|
} while (left < right); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -482,13 +422,10 @@ namespace MathNet.Numerics |
|
|
|
/// <param name="comparer">The method with which to compare two elements of the quick sort.</param>
|
|
|
|
/// <param name="left">The left boundary of the quick sort.</param>
|
|
|
|
/// <param name="right">The right boundary of the quick sort.</param>
|
|
|
|
private static void QuickSort<T, TItems1, TItems2>( |
|
|
|
IList<T> keys, |
|
|
|
IList<TItems1> items1, |
|
|
|
IList<TItems2> items2, |
|
|
|
static void QuickSort<T, TItems1, TItems2>( |
|
|
|
IList<T> keys, IList<TItems1> items1, IList<TItems2> items2, |
|
|
|
IComparer<T> comparer, |
|
|
|
int left, |
|
|
|
int right) |
|
|
|
int left, int right) |
|
|
|
{ |
|
|
|
do |
|
|
|
{ |
|
|
|
@ -547,10 +484,9 @@ namespace MathNet.Numerics |
|
|
|
|
|
|
|
a++; |
|
|
|
b--; |
|
|
|
} |
|
|
|
while (a <= b); |
|
|
|
} while (a <= b); |
|
|
|
|
|
|
|
// In order to limit the recusion depth to log(n), we sort the
|
|
|
|
// 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)) |
|
|
|
{ |
|
|
|
@ -570,8 +506,107 @@ namespace MathNet.Numerics |
|
|
|
|
|
|
|
right = b; |
|
|
|
} |
|
|
|
} |
|
|
|
while (left < right); |
|
|
|
} while (left < right); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Recursive implementation for an in place quick sort on the primary and then by the secondary list while reordering one secondary list accordingly.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T1">The type of the primary list.</typeparam>
|
|
|
|
/// <typeparam name="T2">The type of the secondary list.</typeparam>
|
|
|
|
/// <param name="primary">The list which is sorted using quick sort.</param>
|
|
|
|
/// <param name="secondary">The list which is sorted secondarily (on primary duplicates) and automatically reordered accordingly.</param>
|
|
|
|
/// <param name="primaryComparer">The method with which to compare two elements of the primary list.</param>
|
|
|
|
/// <param name="secondaryComparer">The method with which to compare two elements of the secondary list.</param>
|
|
|
|
/// <param name="left">The left boundary of the quick sort.</param>
|
|
|
|
/// <param name="right">The right boundary of the quick sort.</param>
|
|
|
|
static void QuickSortAll<T1, T2>( |
|
|
|
IList<T1> primary, IList<T2> secondary, |
|
|
|
IComparer<T1> primaryComparer, IComparer<T2> secondaryComparer, |
|
|
|
int left, int right) |
|
|
|
{ |
|
|
|
do |
|
|
|
{ |
|
|
|
// Pivoting
|
|
|
|
int a = left; |
|
|
|
int b = right; |
|
|
|
int p = a + ((b - a) >> 1); // midpoint
|
|
|
|
|
|
|
|
int ap = primaryComparer.Compare(primary[a], primary[p]); |
|
|
|
if (ap > 0 || ap == 0 && secondaryComparer.Compare(secondary[a], secondary[p]) > 0) |
|
|
|
{ |
|
|
|
Swap(primary, a, p); |
|
|
|
Swap(secondary, a, p); |
|
|
|
} |
|
|
|
|
|
|
|
int ab = primaryComparer.Compare(primary[a], primary[b]); |
|
|
|
if (ab > 0 || ab == 0 && secondaryComparer.Compare(secondary[a], secondary[b]) > 0) |
|
|
|
{ |
|
|
|
Swap(primary, a, b); |
|
|
|
Swap(secondary, a, b); |
|
|
|
} |
|
|
|
|
|
|
|
int pb = primaryComparer.Compare(primary[p], primary[b]); |
|
|
|
if (pb > 0 || pb == 0 && secondaryComparer.Compare(secondary[p], secondary[b]) > 0) |
|
|
|
{ |
|
|
|
Swap(primary, p, b); |
|
|
|
Swap(secondary, p, b); |
|
|
|
} |
|
|
|
|
|
|
|
T1 pivot1 = primary[p]; |
|
|
|
T2 pivot2 = secondary[p]; |
|
|
|
|
|
|
|
// Hoare Partitioning
|
|
|
|
do |
|
|
|
{ |
|
|
|
int ax; |
|
|
|
while ((ax = primaryComparer.Compare(primary[a], pivot1)) < 0 || ax == 0 && secondaryComparer.Compare(secondary[a], pivot2) < 0) |
|
|
|
{ |
|
|
|
a++; |
|
|
|
} |
|
|
|
|
|
|
|
int xb; |
|
|
|
while ((xb = primaryComparer.Compare(pivot1, primary[b])) < 0 || xb == 0 && secondaryComparer.Compare(pivot2, secondary[b]) < 0) |
|
|
|
{ |
|
|
|
b--; |
|
|
|
} |
|
|
|
|
|
|
|
if (a > b) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (a < b) |
|
|
|
{ |
|
|
|
Swap(primary, a, b); |
|
|
|
Swap(secondary, 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) |
|
|
|
{ |
|
|
|
QuickSortAll(primary, secondary, primaryComparer, secondaryComparer, left, b); |
|
|
|
} |
|
|
|
|
|
|
|
left = a; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (a < right) |
|
|
|
{ |
|
|
|
QuickSortAll(primary, secondary, primaryComparer, secondaryComparer, a, right); |
|
|
|
} |
|
|
|
|
|
|
|
right = b; |
|
|
|
} |
|
|
|
} while (left < right); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|