Browse Source

Sorting: key-value and key-item1-item2 sub-range sorting; insertion sort on very small sets

pull/222/head
Christoph Ruegg 12 years ago
parent
commit
d0e1fc4c14
  1. 360
      src/Numerics/Sorting.cs
  2. 62
      src/UnitTests/SortingTests.cs

360
src/Numerics/Sorting.cs

@ -38,18 +38,6 @@ namespace MathNet.Numerics
/// </summary>
public static class Sorting
{
/// <summary>
/// Sort a range of a list of keys, in place using the quick sort algorithm.
/// </summary>
/// <typeparam name="T">The type of elements in the key list.</typeparam>
/// <param name="keys">List to sort.</param>
/// <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>
public static void Sort<T>(IList<T> keys, int index, int count)
{
Sort(keys, index, count, Comparer<T>.Default);
}
/// <summary>
/// Sort a list of keys, in place using the quick sort algorithm using the quick sort algorithm.
/// </summary>
@ -58,32 +46,40 @@ namespace MathNet.Numerics
/// <param name="comparer">Comparison, defining the sort order.</param>
public static void Sort<T>(IList<T> keys, IComparer<T> comparer = null)
{
if (null == comparer)
int count = keys.Count;
if (count <= 1)
{
comparer = Comparer<T>.Default;
return;
}
// basic cases
if (keys.Count <= 1)
if (null == comparer)
{
return;
comparer = Comparer<T>.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<T>;
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<T>;
if (null != keysList)
{
keysList.Sort(comparer);
return;
}
// local sort implementation
QuickSort(keys, comparer, 0, keys.Count - 1);
QuickSort(keys, comparer, 0, count - 1);
}
/// <summary>
@ -109,11 +113,47 @@ namespace MathNet.Numerics
/// <param name="comparer">Comparison, defining the sort order.</param>
public static void Sort<TKey, TItem>(IList<TKey> keys, IList<TItem> items, IComparer<TKey> comparer = null)
{
int count = keys.Count;
if (count <= 1)
{
return;
}
if (null == comparer)
{
comparer = Comparer<TKey>.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);
}
/// <summary>
@ -141,38 +181,53 @@ namespace MathNet.Numerics
/// <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 = null)
{
int count = keys.Count;
if (count <= 1)
{
return;
}
if (null == comparer)
{
comparer = Comparer<TKey>.Default;
}
// local sort implementation
QuickSort(keys, items1, items2, comparer, 0, keys.Count - 1);
}
/// <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)
if (count == 2)
{
primaryComparer = Comparer<T1>.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<T2>.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);
}
/// <summary>
@ -185,7 +240,7 @@ namespace MathNet.Numerics
/// <param name="comparer">Comparison, defining the sort order.</param>
public static void Sort<T>(IList<T> keys, int index, int count, IComparer<T> 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<T>.Default;
return;
}
// basic cases
if (count <= 1)
if (null == comparer)
{
return;
comparer = Comparer<T>.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);
}
/// <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 in the key list.</typeparam>
/// <typeparam name="TItem">The type of elements 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>
/// <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<TKey, TItem>(IList<TKey> keys, IList<TItem> items, int index, int count, IComparer<TKey> 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<TKey>.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);
}
/// <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 in the key list.</typeparam>
/// <typeparam name="TItem1">The type of elements in the first item list.</typeparam>
/// <typeparam name="TItem2">The type of elements 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>
/// <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<TKey, TItem1, TItem2>(IList<TKey> keys, IList<TItem1> items1, IList<TItem2> items2, int index, int count, IComparer<TKey> 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<TKey>.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);
}
/// <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)
{
primaryComparer = Comparer<T1>.Default;
}
if (null == secondaryComparer)
{
secondaryComparer = Comparer<T2>.Default;
}
// local sort implementation
QuickSort(keys, comparer, index, count - 1);
QuickSortAll(primary, secondary, primaryComparer, secondaryComparer, 0, primary.Count - 1);
}
/// <summary>
/// Recursive implementation for an in place quick sort on a list.
/// </summary>
@ -616,7 +864,7 @@ namespace MathNet.Numerics
/// <param name="keys">The list in which the elements are stored.</param>
/// <param name="a">The index of the first element of the swap.</param>
/// <param name="b">The index of the second element of the swap.</param>
internal static void Swap<T>(IList<T> keys, int a, int b)
static void Swap<T>(IList<T> keys, int a, int b)
{
if (a == b)
{

62
src/UnitTests/SortingTests.cs

@ -39,15 +39,18 @@ namespace MathNet.Numerics.UnitTests
/// <summary>
/// Test random tuple array sorting.
/// </summary>
[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
/// <summary>
/// Test random tuple list sorting.
/// </summary>
[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<int>(Len);
var items = new List<int>(Len);
var keysCopy = new int[Len];
var keys = new List<int>(length);
var items = new List<int>(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
/// <summary>
/// Test random triple array sorting.
/// </summary>
[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
/// <summary>
/// Test applied list sorting.
/// </summary>
[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<int>();
for (var i = 0; i < Len; i++)
for (var i = 0; i < length; i++)
{
list.Add(random.Next());
}

Loading…
Cancel
Save