快排逻辑
快速排序是编程常用的排序方式,下面是快速排序的核心逻辑
static void QuicksortSequential<T>(T[] arr, int left, int right) where T : IComparable<T>
{
if(right > left)
{
//pivot 左边的值小于arr[pivot].右边的值大于arr[pivot]
int pivot = Partition(arr, left, right);
//排序左边
QuicksortSequential(arr, left, pivot - 1);
//排序右边
QuicksortSequential(arr, pivot + 1, right);
}
}
这里的快速排序使用了递归的方式,可以发现排序左边和排序右边是互不影响的,这给并行运算提供了可行性,
并行快排逻辑
static void QuicksortParallel<T>(T[] arr,int left,int right)where T:IComparable<T>
{
if (right > left)
{
//防止线程开设过多反而速度变慢
if (right - left < SEQUENTIAL_THRESHOLD)
{
QuicksortSequential(arr, left, right);
}
else
{
int pivot = Partition(arr, left, right);
//并行运算
Parallel.Invoke(new Action[] {
() => QuicksortParallel(arr,left,pivot - 1),
() => QuicksortParallel(arr,pivot + 1,right)
});
}
}
}
每开一个线程同样会造成性能的消耗,由于CPU核心数的限制,线程数超过一定数量反而会照成性能下降,所以加了一个SEQUENTIAL_THRESHOLD参数。使得要排序的单位小于他使,自动使用非并行的快速排序
附上所有代码
public class ParalleSort
{
const int SEQUENTIAL_THRESHOLD = 2048;
//快速排序
public static void QuicksortSequential<T>(T[] arr)where T:IComparable<T>
{
QuicksortSequential(arr, 0, arr.Length - 1);
}
//并行快速排序
public static void QuicksortParallel<T>(T[] arr)where T : IComparable<T>
{
QuicksortParallel(arr, 0, arr.Length - 1);
}
/// <summary>
/// 快排逻辑
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="left"></param>
/// <param name="right"></param>
static void QuicksortSequential<T>(T[] arr, int left, int right) where T : IComparable<T>
{
if(right > left)
{
//pivot 左边的值小于arr[pivot].右边的值大于arr[pivot]
int pivot = Partition(arr, left, right);
//排序左边
QuicksortSequential(arr, left, pivot - 1);
//排序右边
QuicksortSequential(arr, pivot + 1, right);
}
}
/// <summary>
/// 并行排序逻辑
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="left"></param>
/// <param name="right"></param>
static void QuicksortParallel<T>(T[] arr,int left,int right)where T:IComparable<T>
{
if (right > left)
{
//防止线程开设过多反而速度变慢
if (right - left < SEQUENTIAL_THRESHOLD)
{
QuicksortSequential(arr, left, right);
}
else
{
int pivot = Partition(arr, left, right);
//并行运算
Parallel.Invoke(new Action[] {
() => QuicksortParallel(arr,left,pivot - 1),
() => QuicksortParallel(arr,pivot + 1,right)
});
}
}
}
/// <summary>
/// 区分数组大小值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="low"></param>
/// <param name="high"></param>
/// <returns></returns>
static int Partition<T>(T[] arr,int low,int high)where T:IComparable<T>
{
int pivotPos = (high + low) / 2;
T pivot = arr[pivotPos];
Swap(arr, low, pivotPos);
int left = low;
for(int i = low + 1; i <= high; i++)
{
if (arr[i].CompareTo(pivot) < 0)
{
left++;
Swap(arr, i, left);
}
}
Swap(arr, low, left);
return left;
}
/// <summary>
/// 交换
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="i"></param>
/// <param name="j"></param>
static void Swap<T>(T[] arr,int i,int j)
{
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
测试性能
使用10000000个随机大小的数,分别使用快速排序,和并行快速排序,输出其消耗时间
const int arrayNum = 10000000;
int[] arr = new int[arrayNum];
Random random = new Random();
for(int i = 0; i < arrayNum; i++)
{
arr[i] = random.Next(0, arrayNum);
}
var arr2 = (int[])arr.Clone();
Stopwatch w = new Stopwatch();
w.Start();
ParalleSort.QuicksortSequential(arr2);
w.Stop();
Console.WriteLine("快排序:{0}mm", w.ElapsedMilliseconds);
w.Reset();
w.Start();
ParalleSort.QuicksortParallel(arr);
w.Stop();
Console.WriteLine("并行排序:{0}mm", w.ElapsedMilliseconds);
输出如下
可以看到并行快排比普通快排快了4倍多