我花了一些时间在C#中实现快速排序算法。 完成后,我比较了我的实现速度和C#的Array.Sort-Method。
我只是比较了随机int数组的速度。
这是我的实施:
static void QuickSort(int[] data, int left, int right)
{
int i = left - 1,
j = right;
while (true)
{
int d = data[left];
do i++; while (data[i] < d);
do j--; while (data[j] > d);
if (i < j)
{
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
else
{
if (left < j) QuickSort(data, left, j);
if (++j < right) QuickSort(data, j, right);
return;
}
}
}
性能(当排序长度为100000000的随机int []时):
- 我的算法:14.21秒
- .Net Array&lt; int&gt; .Sort:14.84秒
有谁知道如何更快地实现我的算法? 或者任何人都可以提供更快的实施(不一定是快速排序!),我跑得更快?
注意:
- 请不要使用多核/处理器来提高性能的算法
- 只有有效的C#源代码
如果我在线,我会在几分钟内测试所提算法的性能。
编辑:
您认为对于包含少于8个值的零件使用理想的分拣网络会提高性能吗?
答案 0 :(得分:8)
二进制插入排序几乎总是赢得短期运行(~10项)。由于简化的分支结构,它通常比理想的分拣网络更好。
Dual pivot quicksort比quicksort快。链接的文章包含一个您可能适应的Java实现。
如果您只对整数进行排序,那么radix sort在长数组上的速度可能会更快。
答案 1 :(得分:7)
有谁知道如何实施我的 算法更快?
通过将代码转换为使用指针,我能够节省10%的执行时间。
public unsafe static void UnsafeQuickSort(int[] data)
{
fixed (int* pdata = data)
{
UnsafeQuickSortRecursive(pdata, 0, data.Length - 1);
}
}
private unsafe static void UnsafeQuickSortRecursive(int* data, int left, int right)
{
int i = left - 1;
int j = right;
while (true)
{
int d = data[left];
do i++; while (data[i] < d);
do j--; while (data[j] > d);
if (i < j)
{
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
else
{
if (left < j) UnsafeQuickSortRecursive(data, left, j);
if (++j < right) UnsafeQuickSortRecursive(data, j, right);
return;
}
}
}
答案 2 :(得分:1)
对随机整数数组的更快排序算法是LSD Radix Sort:
public static int[] SortRadix(this int[] inputArray)
{
const int bitsPerDigit = 8;
const uint numberOfBins = 1 << bitsPerDigit;
uint numberOfDigits = (sizeof(uint) * 8 + bitsPerDigit - 1) / bitsPerDigit;
int d;
var outputArray = new int[inputArray.Length];
int[][] startOfBin = new int[numberOfDigits][];
for (int i = 0; i < numberOfDigits; i++)
startOfBin[i] = new int[numberOfBins];
bool outputArrayHasResult = false;
const uint bitMask = numberOfBins - 1;
const uint halfOfPowerOfTwoRadix = PowerOfTwoRadix / 2;
int shiftRightAmount = 0;
uint[][] count = HistogramByteComponents(inputArray, 0, inputArray.Length - 1);
for (d = 0; d < numberOfDigits; d++)
{
startOfBin[d][0] = 0;
for (uint i = 1; i < numberOfBins; i++)
startOfBin[d][i] = startOfBin[d][i - 1] + (int)count[d][i - 1];
}
d = 0;
while (d < numberOfDigits)
{
int[] startOfBinLoc = startOfBin[d];
if (d != 3)
for (uint current = 0; current < inputArray.Length; current++)
outputArray[startOfBinLoc[((uint)inputArray[current] >> shiftRightAmount) & bitMask]++] = inputArray[current];
else
for (uint current = 0; current < inputArray.Length; current++)
outputArray[startOfBinLoc[((uint)inputArray[current] >> shiftRightAmount) ^ halfOfPowerOfTwoRadix]++] = inputArray[current];
shiftRightAmount += bitsPerDigit;
outputArrayHasResult = !outputArrayHasResult;
d++;
int[] tmp = inputArray; // swap input and output arrays
inputArray = outputArray;
outputArray = tmp;
}
return outputArrayHasResult ? outputArray : inputArray;
}
[StructLayout(LayoutKind.Explicit)]
internal struct Int32ByteUnion
{
[FieldOffset(0)]
public byte byte0;
[FieldOffset(1)]
public byte byte1;
[FieldOffset(2)]
public byte byte2;
[FieldOffset(3)]
public byte byte3;
[FieldOffset(0)]
public Int32 integer;
}
public static uint[][] HistogramByteComponents(int[] inArray, Int32 l, Int32 r)
{
const int numberOfBins = 256;
const int numberOfDigits = sizeof(ulong);
uint[][] count = new uint[numberOfDigits][];
for (int i = 0; i < numberOfDigits; i++)
count[i] = new uint[numberOfBins];
var union = new Int32ByteUnion();
for (int current = l; current <= r; current++) // Scan the array and count the number of times each digit value appears - i.e. size of each bin
{
union.integer = inArray[current];
count[0][union.byte0]++;
count[1][union.byte1]++;
count[2][union.byte2]++;
count[3][((uint)inArray[current] >> 24) ^ 128]++;
}
return count;
}
它在单核上的运行速度接近100 MegaInt32s /秒-比Array.Sort()快7倍,比Linq.OrderBy()快25倍,比Linq.AsParallel()。OrderBy(6倍)快)在6个内核上。
此实现来自nuget.org上的HPCsharp nuget程序包,该程序包还具有用于对uint [],long []和ulong []数组进行排序的版本,以及MSD Radix Sort,它添加了float []。和double []数组,并且就位。
答案 3 :(得分:0)
看一下Shear Sort和Odd-Event Transposition排序:http://www.cs.rit.edu/~atk/Java/Sorting/sorting.html和http://home.westman.wave.ca/~rhenry/sort/。
这里有剪切排序的C#实现:http://www.codeproject.com/KB/recipes/cssorters.aspx。
这些示例都是Java,但它非常接近C#。它们是并行的,因为它们在多个内核上运行得更快,但仍然应该非常快。
答案 4 :(得分:0)
当对具有重复项的数组进行排序时,第一个(可能是第二个)快速排序算法会中断。我使用this一个,效果很好。
答案 5 :(得分:0)
这对我来说更快,更简单。
unsafe static void Sort(int* a, int length)
{
int negLength = length - 1;
for (int i = 0; i < negLength; ++i)
for (int n = i + 1; n < length; ++n)
{
int value = a[i];
int next = a[n];
if (value > next)
{
a[i] = next;
a[n] = value;
}
}
}