diff --git a/src/Numerics/Sorting.cs b/src/Numerics/Sorting.cs
index b9a813b2..be9acaf2 100644
--- a/src/Numerics/Sorting.cs
+++ b/src/Numerics/Sorting.cs
@@ -38,18 +38,6 @@ namespace MathNet.Numerics
///
public static class Sorting
{
- ///
- /// Sort a range of a list of keys, in place 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, in place using the quick sort algorithm using the quick sort algorithm.
///
@@ -58,32 +46,40 @@ namespace MathNet.Numerics
/// Comparison, defining the sort order.
public static void Sort(IList keys, IComparer comparer = null)
{
- if (null == comparer)
+ int count = keys.Count;
+ if (count <= 1)
{
- comparer = Comparer.Default;
+ return;
}
- // basic cases
- if (keys.Count <= 1)
+ if (null == comparer)
{
- return;
+ comparer = Comparer.Default;
}
- if (keys.Count == 2)
+ if (count == 2)
{
if (comparer.Compare(keys[0], keys[1]) > 0)
{
Swap(keys, 0, 1);
}
-
return;
}
- // generic list case
- var keysList = keys as List;
- if (null != keysList)
+ // insertion sort
+ if (count <= 10)
{
- keysList.Sort(comparer);
+ for (int i = 1; i < count; i++)
+ {
+ var key = keys[i];
+ int j = i - 1;
+ while (j >= 0 && comparer.Compare(keys[j], key) > 0)
+ {
+ keys[j + 1] = keys[j];
+ j--;
+ }
+ keys[j + 1] = key;
+ }
return;
}
@@ -95,8 +91,16 @@ namespace MathNet.Numerics
return;
}
+ // generic list case
+ var keysList = keys as List;
+ if (null != keysList)
+ {
+ keysList.Sort(comparer);
+ return;
+ }
+
// local sort implementation
- QuickSort(keys, comparer, 0, keys.Count - 1);
+ QuickSort(keys, comparer, 0, count - 1);
}
///
@@ -109,11 +113,47 @@ namespace MathNet.Numerics
/// Comparison, defining the sort order.
public static void Sort(IList keys, IList items, 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(items, 0, 1);
+ }
+ return;
+ }
+
+ // insertion sort
+ if (count <= 10)
+ {
+ for (int i = 1; i < count; i++)
+ {
+ var key = keys[i];
+ var item = items[i];
+ int j = i - 1;
+ while (j >= 0 && 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;
+ }
+
#if !PORTABLE
// array case
var keysArray = keys as TKey[];
@@ -126,7 +166,7 @@ namespace MathNet.Numerics
#endif
// local sort implementation
- QuickSort(keys, items, comparer, 0, keys.Count - 1);
+ QuickSort(keys, items, comparer, 0, count - 1);
}
///
@@ -141,38 +181,53 @@ namespace MathNet.Numerics
/// Comparison, defining the sort order.
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;
}
- // local sort implementation
- QuickSort(keys, items1, items2, comparer, 0, keys.Count - 1);
- }
-
- ///
- /// Sort a list of keys and items with respect to the keys, in place using the quick sort algorithm.
- ///
- /// The type of elements in the primary list.
- /// The type of elements in the secondary list.
- /// List to sort.
- /// List to to sort on duplicate primaty items, and permute the same way as the key list.
- /// Comparison, defining the primary sort order.
- /// Comparison, defining the secondary sort order.
- public static void SortAll(IList primary, IList secondary, IComparer primaryComparer = null, IComparer secondaryComparer = null)
- {
- if (null == primaryComparer)
+ if (count == 2)
{
- primaryComparer = Comparer.Default;
+ if (comparer.Compare(keys[0], keys[1]) > 0)
+ {
+ Swap(keys, 0, 1);
+ Swap(items1, 0, 1);
+ Swap(items2, 0, 1);
+ }
+ return;
}
- if (null == secondaryComparer)
+ // insertion sort
+ if (count <= 10)
{
- secondaryComparer = Comparer.Default;
+ 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
- QuickSortAll(primary, secondary, primaryComparer, secondaryComparer, 0, primary.Count - 1);
+ QuickSort(keys, items1, items2, comparer, 0, count - 1);
}
///
@@ -185,7 +240,7 @@ namespace MathNet.Numerics
/// Comparison, defining the sort order.
public static void Sort(IList keys, int index, int count, IComparer comparer = null)
{
- if (index < 0 || index >= keys.Count)
+ if (index < 0)
{
throw new ArgumentOutOfRangeException("index");
}
@@ -195,15 +250,14 @@ namespace MathNet.Numerics
throw new ArgumentOutOfRangeException("count");
}
- if (null == comparer)
+ if (count <= 1)
{
- comparer = Comparer.Default;
+ return;
}
- // basic cases
- if (count <= 1)
+ if (null == comparer)
{
- return;
+ comparer = Comparer.Default;
}
if (count == 2)
@@ -212,7 +266,32 @@ namespace MathNet.Numerics
{
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
+ var keysArray = keys as T[];
+ if (null != keysArray)
+ {
+ Array.Sort(keysArray, index, count, comparer);
return;
}
@@ -224,18 +303,187 @@ namespace MathNet.Numerics
return;
}
+ // fall back: local sort implementation
+ QuickSort(keys, comparer, index, count - 1);
+ }
+
+ ///
+ /// Sort a list of keys and items with respect to the keys, in place 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 permute the same way as the key list.
+ /// 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, IList items, int index, int count, IComparer comparer = null)
+ {
+ if (index < 0)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+
+ if (count < 0 || index + count > keys.Count)
+ {
+ throw new ArgumentOutOfRangeException("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;
+ }
+
+#if !PORTABLE
// array case
- var keysArray = keys as T[];
- if (null != keysArray)
+ var keysArray = keys as TKey[];
+ var itemsArray = items as TItem[];
+ if ((null != keysArray) && (null != itemsArray))
{
- Array.Sort(keysArray, index, count, comparer);
+ Array.Sort(keysArray, itemsArray, index, count, comparer);
return;
}
+#endif
+
+ // fall back: local sort implementation
+ QuickSort(keys, items, comparer, index, count - 1);
+ }
+
+ ///
+ /// Sort a list of keys, items1 and items2 with respect to the keys, in place 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 permute the same way as the key list.
+ /// Second list to permute the same way as the key list.
+ /// 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, IList items1, IList items2, int index, int count, IComparer comparer = null)
+ {
+ if (index < 0)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+
+ if (count < 0 || index + count > keys.Count)
+ {
+ throw new ArgumentOutOfRangeException("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);
+ }
+
+ ///
+ /// Sort a list of keys and items with respect to the keys, in place using the quick sort algorithm.
+ ///
+ /// The type of elements in the primary list.
+ /// The type of elements in the secondary list.
+ /// List to sort.
+ /// List to to sort on duplicate primaty items, and permute the same way as the key list.
+ /// Comparison, defining the primary sort order.
+ /// Comparison, defining the secondary sort order.
+ public static void SortAll(IList primary, IList secondary, IComparer primaryComparer = null, IComparer secondaryComparer = null)
+ {
+ if (null == primaryComparer)
+ {
+ primaryComparer = Comparer.Default;
+ }
+
+ if (null == secondaryComparer)
+ {
+ secondaryComparer = Comparer.Default;
+ }
// local sort implementation
- QuickSort(keys, comparer, index, count - 1);
+ QuickSortAll(primary, secondary, primaryComparer, secondaryComparer, 0, primary.Count - 1);
}
+
///
/// Recursive implementation for an in place quick sort on a list.
///
@@ -616,7 +864,7 @@ namespace MathNet.Numerics
/// 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)
+ static void Swap(IList keys, int a, int b)
{
if (a == b)
{
diff --git a/src/UnitTests/SortingTests.cs b/src/UnitTests/SortingTests.cs
index e42c69cc..ec02434e 100644
--- a/src/UnitTests/SortingTests.cs
+++ b/src/UnitTests/SortingTests.cs
@@ -39,15 +39,18 @@ namespace MathNet.Numerics.UnitTests
///
/// Test random tuple array sorting.
///
- [Test]
- public void TestRandomTupleArraySorting()
+ [TestCase(0)]
+ [TestCase(2)]
+ [TestCase(7)]
+ [TestCase(24)]
+ [TestCase(1024)]
+ public void TestRandomTupleArraySorting(int length)
{
- const int Len = 0x1 << 10;
var random = new System.Random(0);
- var keys = new int[Len];
- var items = new int[Len];
- var keysCopy = new int[Len];
+ var keys = new int[length];
+ var items = new int[length];
+ var keysCopy = new int[length];
for (var i = 0; i < keys.Length; i++)
{
@@ -73,17 +76,20 @@ namespace MathNet.Numerics.UnitTests
///
/// Test random tuple list sorting.
///
- [Test]
- public void TestRandomTupleListSorting()
+ [TestCase(0)]
+ [TestCase(2)]
+ [TestCase(7)]
+ [TestCase(24)]
+ [TestCase(1024)]
+ public void TestRandomTupleListSorting(int length)
{
- const int Len = 0x1 << 10;
var random = new System.Random(0);
- var keys = new List(Len);
- var items = new List(Len);
- var keysCopy = new int[Len];
+ var keys = new List(length);
+ var items = new List(length);
+ var keysCopy = new int[length];
- for (var i = 0; i < Len; i++)
+ for (var i = 0; i < length; i++)
{
var value = random.Next();
keys.Add(value);
@@ -93,7 +99,7 @@ namespace MathNet.Numerics.UnitTests
Sorting.Sort(keys, items);
- for (var i = 1; i < Len; i++)
+ for (var i = 1; i < length; i++)
{
Assert.IsTrue(keys[i] >= keys[i - 1], "Sort Order - " + i);
Assert.AreEqual(items[i], -keys[i], "Items Permutation - " + i);
@@ -108,16 +114,19 @@ namespace MathNet.Numerics.UnitTests
///
/// Test random triple array sorting.
///
- [Test]
- public void TestRandomTripleArraySorting()
+ [TestCase(0)]
+ [TestCase(2)]
+ [TestCase(7)]
+ [TestCase(24)]
+ [TestCase(1024)]
+ public void TestRandomTripleArraySorting(int length)
{
- const int Len = 0x1 << 10;
var random = new System.Random(0);
- var keys = new int[Len];
- var items1 = new int[Len];
- var items2 = new int[Len];
- var keysCopy = new int[Len];
+ var keys = new int[length];
+ var items1 = new int[length];
+ var items2 = new int[length];
+ var keysCopy = new int[length];
for (var i = 0; i < keys.Length; i++)
{
@@ -145,15 +154,18 @@ namespace MathNet.Numerics.UnitTests
///
/// Test applied list sorting.
///
- [Test]
- public void TestAppliedListSorting()
+ [TestCase(0)]
+ [TestCase(2)]
+ [TestCase(7)]
+ [TestCase(24)]
+ [TestCase(1024)]
+ public void TestAppliedListSorting(int length)
{
- const int Len = 0x1 << 10;
var random = new System.Random(0);
var list = new List();
- for (var i = 0; i < Len; i++)
+ for (var i = 0; i < length; i++)
{
list.Add(random.Next());
}