前言
最近学习了算法导论上的快速排序部分,有不少体会。
今天就来分享一下。在此欢迎大家批评指正文中的错误。
目录索引
快速排序
正文
1.快速排序的优点
说起快速排序,它的名字就显现出快排最大的优点————快。到底有多快呢?咱们用数据说话:
综合一般情况来说,快排确实有(亿点快)。特别是对较大数据量的排序。
快速排序的综合时间复杂度是O(nlgn),但在极端最坏情况下,时间复杂度会到O(n^2)。
很多人在看到O(n^2)会产生疑问?为什么我们还要在实际生活中使用快排呢。
尽管快排的最坏时间复杂度很差,但是它的平均性能好,通常是实际排序中最好的选择。它的期望时间复杂度是O(nlgn),(绝大多数是这样,在下文快排的性能分析中会有说明),在排序中很少遇到最坏情况。并且O(nlgn)中隐含的常数因子非常小。
在C++库函数中sort()函数底层大部分用快排实现的(可以参照下文的小区间优化)。
所以:快排,yyds!!!
2.快排的原理及实现
我们来理解快排的原理。快排运用了分治的思想。
在每一次排序中,选取一个数据作为主元x,在将数据的每个值与主元x进行比较,使每趟排序结束时,小于或等于x的在x数据的左边,大于或等于x的在x的右边。(和x相等的数可以在x的两侧,这就造成了快排的不稳定性)。
左子区间都是不大于x的数,右子区间都是不小于x的数。以x为界限,递归左右子区间。从大致有序到全部有序。
下面我们来简单实现快速排序。
void quick_sort(int *a, int l, int r)
{
if (l >= r)
return;
int x = a[l]; // 取最左边的值作为主元x
int i = l, j = r;
while (i < j)
{
while (a[i] <= x && i<r) ++i; // 循环结束时a[i]比x大
while (a[j] >= x && j>l) --j; // 循环结束时a[j]比x小
if (i < j)
swap(a[i], a[j]); // 交换a[i],a[j]
}
// j为分界点
swap(a[l], a[j]); // 将主元x放在正确的位置,作为分界点
// 递归左右子区间
quick_sort(a, l, j - 1);
quick_sort(a, j+1, r);
}