神的规范:排序算法(四):快速排序

写在前面:
排序又称为分类,它是数据处理中经常用到的一种重要运算。
虽然并未列入世界最伟大的几大算法之一,但毫无疑问,在各行各业的各个时期排序都是作为奠基者般的存在为程序所调用,也为编程者所敬仰。只是,也许正是因为它与我们息息相关,以至于我们竟然时常忽略它的存在。
事实上我们生活中无时无刻不在做排序:考试成绩排名,按身高、年龄、能力高低去评判他人,划分任务处理的优先级,等等·······
前面3篇博客我们讨论了简单插入排序、简单选择排序和冒泡排序算法,而今天我们进入排序小能手“快速排序”的学习,一步步去探索排序算法如何在反思中前进,在山重水复处柳暗花明。

我们已经认识到,无论是简单插入排序、简单选择排序还是冒泡排序,复杂度都是O[n^2],它们能力就算有高低,到底还是同一个维度的竞争对手。我说你比我慢,不过是五十步笑一百步。那么有没有一种新的算法可以直接将复杂度降下来呢?
有,它就是排序中的降维打击战略武器——快排。
那快排是什么又是怎么想出来的呢?
所谓快排,又叫做分区交换,它是目前已知平均速度较快的一种排序算法。值得注意的是,它是对冒泡排序算法的一种改进(纳尼!)。
快速排序的基本思想是:
从待排序的n个数据中选取一个元素Ri(可选第一个数据,也可选中间的数据)作为标准,调整序列中各个元素的位置,使得排在Ri前面的元素值都小于Ri,排在Ri后面的元素值都大于Ri,这样的过程叫做一次快速排序。第一次快排过程,确定了Ri最终在序列中的位置,同时把剩下的元素分为两个子序列。对于2个子序列再分别进行快排,又可以确定2个元素在序列中的最终位置,并将序列分为了4个子序列。依次类推,当各序列只有一个数据元素时,则整个序列已然有序,排序完毕。

我们将算法用规范的C语言代码描述如下(假设数据类型为double):

void quicksort(double a[],int low,int high) {
    int i = low,j = high;
    double mid = a[(low+high)/2]; //choose the middle as standard
    while (i < j) {  //Loop condition every time
        while (a[i] < mid)
            i++;
        while (a[j] > mid)
            j--;
        if (i < j) { //Occurs:a[i] > mid or a[j] < mid
            double temp = a[i];    //swap data
            a[i] = a[j];
            a[j] = temp;
            i++;
            j--;
        }
    }
    if (i < high)              //Distributed strategy
        quicksort(a,i+1,high);
    if (j > low)
        quicksort(a,low,j-1);
}

验证其功能性,结果图如下:
quicksort

接下来,像前几篇一样我们来做个比较,看看快排比起前面三个算法,究竟可以快到什么地步。答曰:快到不可思议!
我们用结果图来显示一样快排的实力:
10000个数据时:
这里写图片描述
20000个数据时:
这里写图片描述
30000个数据时:
这里写图片描述

第一项列出的时间即为快排的战绩,根本是遥遥领先,独孤求败!
我们要问了,你个快排凭什么这么快?
不不妨稍作分析:
我们注意到,快排里使用了递归,从而实现分治策略。简单估算一下快排的效率:在第一次扫描中大概需要n-1次比较,然后待排数据元素序列会分为两个大小大致为n/2的子序列,这两个子序列每个大致需要n/2次比较,然后生成4个大小大致为n/4的子子序列。依次分解,进行了log2n次分解后,生成了n个大小为1的序列。这样的话排序所需的总比较次数为:
(n-1) + 2*(n-1)/2 + 4*(n-1)/4+…+(n-1)*1 = (n-1)log2n
也就是说,算法效率为O[nlogn]。
这虽是n到logn的一小步,却是排序算法的一大步,因为时间效率是呈几何级数增长的。
那么说了这么多,快排有没有什么缺点呢?
有的,首先,它是一种不稳定的算法,排序码的相对位置会变化;其次,因为递归会占用栈,所以大数据量处理时,会出现栈空间不足的风险,需人为设置栈空间容量。

好了,快排的分享也该到此结束了。下一篇我们再看排序界的另一高手——归并排序,它的算法复杂度与快排基本相当。

To be continued…

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值