印象
图2 快速排序过程
思想
通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
分析
- 稳定: 否
- 时间复杂度:
- 最优时间: O(nlog(n))
- 最坏时间: O(n^2)
- 平均时间: O(nlog(n))
理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n)。
最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。
为改善最坏情况下的时间性能,可采用其他方法选取中间数。通常采用“三者值取中”方法,即比较H->r[low].key、H->r[high].key与H->r[(10w+high)/2].key,取三者中关键字为中值的元素为中间数。
示例代码
C#
static void Main(string[] args)
{
// 定义待排序数组
int[] a = { 12, 312, 32, 82, 21 };
// 显示待排序数组
Console.WriteLine("待排序数组:");
foreach (var item in a)
{
Console.Write(item);
Console.Write(" ");
}
Console.WriteLine("");
// 排序
QSort(a);
// 显示已排序数组
Console.WriteLine("已排序数组:");
foreach (var item in a)
{
Console.Write(item);
Console.Write(" ");
}
// 等待
Console.ReadKey();
}
/// <summary>
/// 快速排序
/// </summary>
/// <param name="a"></param>
static void QSort(int[] a)
{
QSort(a, 0, a.Length - 1);
}
/// <summary>
/// 快速排序
/// </summary>
/// <param name="a">排序数组</param>
/// <param name="left">数组左侧索引</param>
/// <param name="right">数组右侧索引</param>
static void QSort(int[] a, int left, int right)
{
if (left < right)
{
int i = left - 1;
int j = right + 1;
int key = a[(left + right) / 2];
while (true)
{
// 寻找满足交换条件的两个索引
while (a[++i] < key) ;
while (a[--j] > key) ;
// 结束
if (i >= j)
{
break;
}
// 交换
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// 递归
QSort(a, left, i - 1);
QSort(a, j + 1, right);
}
}