笔者近期在写一个需要计算中位数的功能,然后需要调用数组的排序功能。于是笔者自带的排序功能十分好奇,查了下发现自带的排序实际上是应用的快速排序,为了能更好的理解快速排序以及认识其比较合适的使用场景,故手动实现并记录下来:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static int[] test = new int[] {6,1,4,3,5,8 };
/// <summary>
/// 一遍 快速排序
/// </summary>
/// <param name="a">待排数组</param>
/// <param name="low">排序起始值</param>
/// <param name="high">排序最高值</param>
/// <returns>中枢值位置</returns>
public static int Partition(ref int[] a,int low,int high) {
// 设置中枢值
int pivotkey = a[low];
// 确保不进入死循环,当low指针大于high叫停
while (low < high) {
// 如果high哨兵的值小于中枢值,则将high的值与中枢值调换(中枢值保存了副本pivotkey!)
while (low < high && a[high] >= pivotkey)
high--;
a[low] += a[high];
a[high] = a[low] - a[high];
a[low] -= a[high];
// 如果low哨兵的值大于中枢值,则将low与中枢值调换
while (low < high && a[low] <= pivotkey)
low++;
a[low] += a[high];
a[high] = a[low] - a[high];
a[low] -= a[high];
}
// 结束比对,low和high会碰在一起,此时将中枢值副本值插入low的位置
a[low] = pivotkey;
return low;
}
/// <summary>
/// 快速排序
/// </summary>
/// <param name="a">待排数组</param>
/// <param name="low">排序起始值</param>
/// <param name="high">排序最高值</param>
public static void QuickSort(ref int[] a, int low, int high) {
// 加入这个low<high ,一个是确保数组的长度大于1,二是确定递归结束的条件,防止进入死循环,栈溢出
if (low < high) {
// 每次获取中枢值的位置
int pivotloc = Partition(ref a, low, high);
// 利用中枢值将每遍排好序的数组分割成两份,接着从low到pivotkey-1 以及 pivotkey+1 到 high两个区域进行排序
// 这里加入比较两端的长度,旨在降低栈的最大深度(降低至logn)
if ((pivotloc - low) <= (high - pivotloc))
{
QuickSort(ref a, low, pivotloc - 1);
QuickSort(ref a, pivotloc + 1, high);
}
else {
QuickSort(ref a, pivotloc + 1, high);
QuickSort(ref a, low, pivotloc - 1);
}
}
}
static void Main(string[] args)
{
QuickSort(ref test,0,test.Length-1);
foreach (var item in test)
{
Console.Write(item + " ");
}
Console.ReadKey();
}
}
}
资料上显示,快速排序就平均时间而言是目前被认为最好的一种内部排序算法!