选择排序虽然不是效率最高的排序算法,但是它是一种比较容易并行化的排序算法。
比如我们使用AVX2指令集(C#中以Vector<T>形式以及相关操作存在),就可以一次处理多个数据。现在假定我们使用256位并行计算,那么一次就可以处理8个整数。我们把输入的数据分成8列(如果模8有余数,先用其它算法计算出最后几个-7个之内-最大的数的排序),然后8列各自并行进行选择排序(选出最小的放在前面),最后对8列排序加以归并,这就可以实现基于SIMD的并行选择排序算法。这个并行排序算法的效率显然比串行高得多。具体实测情况,请参阅:
GitHub - yyl-20020115/DoubleSelectionSort: The improved selection sort algorithm
核心代码如下所示
/// <summary>
/// FastSingleSelectionSort
/// </summary>
int[] FastSingleSelectionSort(int[] data)
{
int width = Vector<int>.Count;
int N = data.Length;
int R = N % width;
if (R > 0) //Sort tail
{
int T = N - R;
for(int i = N-1; i >= T; i--)
{
int maxIndex = i;
int max = data[maxIndex];
for(int j = i - 1; i >= 0; j--)
{
if (data[j] > max)
{
max=data[j];
maxIndex = j;
}
}
if (maxIndex != i)
{
Swap(data, maxIndex, i);
}
}
N = T;
}
int[] buffer = new int[width];
int[] positions = new int[width];
for (int i = 0; i < N - width; i+= width)
{
for (int q = 0; q < width; q++)
{
positions[q] = i + q;
}
var min = new Vector<int>(data,i);
for (int j = i + width; j < N; j+=width)
{
min.CopyTo(buffer);
var dt = new Vector<int>(data, j);
var rt = Vector.LessThan(dt, min);
var any = false;
for(int s = 0; s < width; s++)
{
if (rt[s] != 0)
{
positions[s] = j + s;
buffer[s] = dt[s];
any = true;
}
}
if (any)
{
min = new Vector<int>(buffer);
}
}
for(int q = 0; q < width; q++)
{
int a = positions[q];
int b = i + q;
if (a != b)
{
Swap(data, a, b);
}
}
}
return DoCollect(data, width, true);
}
void Swap(int[] a, int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int[] DoCollect(int[] data, int width, bool copy_tail)
{
if (width <= 1) return data;
int N = data.Length;
int R = N % width;
int[] positions = new int[width];
int[] result = new int[N];
if (copy_tail && R > 0)
{
Array.Copy(data, N - R, result, N - R, R);
}
for (int i = 0; i < width; i++)
{
positions[i] = i;
}
int p = 0;
while (p < N)
{
int? minpos = null;
int? minval = null;
for (int i = 0; i < width; i++)
{
int index = positions[i];
if (index >= data.Length) continue;
int value = data[index];
if (minval == null || value < minval)
{
minval = value;
minpos = i;
}
}
if (minpos is int _minpos && minval is int _minval)
{
positions[_minpos] += width;
result[p++] = _minval;
}
}
return result;
}