#数据结构 #算法 #C
快速排序(英语:Quicksort),又称分区交换排序(partition-exchange sort),交换排序的另一种。是一种排序算法,最早由东尼·霍尔提出。
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。 步骤为:
- 挑选基准值:从数列中挑出一个元素,称为“基准”(pivot),
- 分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成,
- 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。
- 递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。
换种数学公式表达:
在待排序表 pivot
作为枢轴(或基准,通常取⾸元素),通过⼀趟排序将待排序表划分为独立的两部分:
-
$L[1,…k-1]$ 中的所有元素小于pivot
, -
$L[k+1,…n]$ 中的所有元素大于等于pivot
,
则pivot
放在了其最终位置$L(k)$ 上,这个过程称为⼀次“划分”。 然后分别递归地对两个⼦表重复上述过程,直⾄每部分内只有⼀个元素或空为止,即所有元素放在了其最终位置上。
以数组A{49,38,65,97,76,13,27,49}
为例,以递归工作栈的方式来实现快速排序。
把最起初的数字array[0]
的值49作为中枢,即基准。小于pivot的放于左侧,大于pivot的放于右侧。
第一轮排序完成,继续以pivot为中枢,对其他元素按照大小值,小于pivot的放于左侧,大于pivot的放于右侧。然后将pivot填入其中。 进入下一层递归:
左子表排序完成,退出递归。对右子表执行排序。
排序完成。
// 用第一个元素将待排序序列划分分为左右两个部分
int Partition(int array[], int low, int high)
{
// 把第一个元素当作枢轴
int pivot = array[low];
// 用low、high搜索枢轴的最终位置,
// 当low 与 high 相碰的时候和或者 low 溢出 high 的时候结束
while (low < high)
{
// 比枢轴小的元素移动到左端
while (low < high && array[high] >= pivot)
{
high--;
}
array[low] = array[high];
// 比枢轴大的元素移动到右端
while (low < high && array[low] <= pivot)
{
low++;
}
array[high] = array[low];
}
array[low] = pivot;
return low;
}
// 快速排序
void QuickSort(int array[], int low, int high)
{
if (low < high)
{
int pivot = Partition(array, low, high);
QuickSort(array, low, pivot - 1);
QuickSort(array, pivot + 1, high);
}
}
每⼀层的QuickSort
只需要处理剩余的待排序元素,时间复杂度不超过 {49,38,65,97,76,13,27,49}
为例,以递归方式,从代码角度演示:
初始状态,进入第34行代码:int pivot = Partition(array, low, high);
,调用Partition
函数。
当顺次移动low
、high
指针所对应的值与pivot
比较,如果较小,放到low
处,较大放到high
处,再顺次移动指针。
当low
与high
指针重合,本轮排序结束,跳出循环,找到pivot
的位次,代码进入第35行,继续调用QuickSort
。
第二层调用,指针重合调用结束,进入第三层调用。
第三层调用,结束,左子表轮次排列完整。右子表的排列和左子表类似,会直至调用第四层,第四层结束才会返回。
把n个元素组织成⼆叉树,⼆叉树的层数就是递归调⽤的层数:
- n个结点的⼆叉树最⼩⾼度 =
$⌊log_2{n}⌋ + 1$ 。 - 最⼤⾼度 =
$n$
若每⼀次选中的“枢轴”将待排序序列划分为很不均匀的两个部分,则会导致递归深度增加,算法效率变低。 比如,初始序列有序或逆序,则快速排序的性能最差(因为每次选择的都是最靠边的元素)。
尽量选择可以把数据中分的枢轴元素,而不是从头开始。 例如:
- 选头、中、尾三个位置的元素,取中间值作为枢轴元素;
- 随机选⼀个元素作为枢轴元素。
快速排序是所有内部排序算法中平均性能最优的排序算法。
时间复杂度 =
快速排序是不稳定的排序。