对于一个 n n n个元素的数组,必须要确定两两之间的相对顺序,假设每次都抓取不同的二元组,需要 log ⁡ 2 n ! \log_2n! log2​n!次比较,由于 log ⁡ 2 n ! ≈ n log ⁡ 2 n \log_2n!\approx n\log_2n log2​n!≈nlog2​n, O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2​n)就是排序算法的下界。

前面几周写过一篇散文:
https://zhuanlan.zhihu.com/p/429710417
但紧接着问题就来了,到底为什么归并排序,快速排序快呢?

这里有必要澄清一下两个问题的区别:

  • 归并排序,快速排序节省了哪些比较操作?
  • 归并排序,快速排序为什么能节省这些操作?

上面那篇文章里,似乎回答了第一个问题,但仔细一想,发现还差点(我已经做了批注)。

虽然可以看出具体省略了哪些比较操作,但背后的原因是什么?或者换一个问题,冒泡排序到底为什么慢?

冒泡排序实际上将数组中任意两个数字都进行了一次比较,问题在于,这些比较中,有一些是没有必要的。比如:

  • 比较1: a 2 < a 8 a_2<a_8 a2​<a8​
  • 比较2: a 8 < a 19 a_8<a_{19} a8​<a19​
  • 比较3: a 2 < a 19 a_2<a_{19} a2​<a19​

比较3还有意义吗?毫无意义!然而冒泡排序无法识别,它只是逐数字顺序比较。

对于 log ⁡ 2 n ! \log_2n! log2​n!的分析,比较3是隐含在比较1和比较2两个比较中的,事实上当完成比较1和比较2后,在上面的比较结果下,比较3就没有必要了,除非比较1得出 a 2 > a 8 a_2>a_8 a2​>a8​或者比较2得出 a 8 > a 19 a_8>a_{19} a8​>a19​的结论,才需要比较3。

按照排列组合分析,可天然剔除掉可传递的关联比较, log ⁡ 2 n ! ≈ n log ⁡ 2 n \log_2n!\approx n\log_2n log2​n!≈nlog2​n次比较是不包括可传递的关联比较的。

接下来只要说明归并排序和快速排序的每次比较都是无关联即可,这个是显然的:

  • 归并排序:实际合并之前,两个子数组从没遇见过,不可能有任何关联。
  • 快速排序:左右两个子数组均按原始相对顺序和锚点比较,内部彼此无关联。

无论如何,归并排序均可达 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2​n)的时间复杂度,对于快速排序,在最理想情况下,也可达到,即便是平均情况,离最理想情况也不远。

冒泡排序的算法本身就如此定义,随排序进行,未排序序列趋于有序,但排序过程无法识别哪些比较是不必要的,从信息论的角度,大概率的非必要比较依然要进行,这些比较带来的信息量无疑很小,这就是低效的根源,反过来,归并排序和快速排序依偎着比较排序的下界,这就是它们快的根源。

log ⁡ n ! ≈ n log ⁡ n \log n!\approx n\log n logn!≈nlogn事实上就是排序的最大熵,自然就是排序操作的下界。在没有预假设的情况下, n n n个数组的序列一共有 n ! n! n!种,升序(或者降序)只是其中一种,它的概率为 1 n ! \dfrac{1}{n!} n!1​,排序信息熵为:

H = − ∑ i − 1 n ! 1 n ! log ⁡ 2 1 n ! = log ⁡ 2 n ! ≈ n log ⁡ n H=-\sum\limits_{i-1}^{n!}\dfrac{1}{n!}\log_2\dfrac{1}{n!}=\log_2n!\approx n\log n H=−i−1∑n!​n!1​log2​n!1​=log2​n!≈nlogn

时间复杂度就是信息熵的度量,引入新的预设,信息熵必然减小,冒泡排序随着排序的进行,将引入新的预设,而归并排序和快速排序在排序过程中一直保持最开始的预设,保持比较操作的无关联性。

浙江温州皮鞋湿,下雨进水不会胖。

归并排序,快速排序为什么快相关推荐

  1. C语言——十四种内部排序算法【直接插入排序-冒泡排序-选择排序-插入排序-希尔排序-归并排序-快速排序-堆排序-折半插入排序-二分查找-路插入排序-表插入排序-简单选择排序-直接选择排序-树形选择】

    目录: 一:插入排序 A:直接插入排序 1.定义: 2.算法演示 实例1: 3.基本思想 4.排序流程图 实例1: B:希尔排序 1.定义: 2.算法演示 实例2: C:其他插入排序 a:折半插入排序 ...

  2. 快排和归并排序哪个更快

    在看算法图解的过程中,看到书中说时间复杂度同为O(nlogn),快排比归并排序快的原因是快排查找的常量要比归并小. 看完还不是很理解,去网上查了下资料,看了几种回答,还是<数据结构与算法分析:C ...

  3. 非递归快速排序php,快排序的非递归实现(原创)

    本文简要介绍快排序的非递归实现方式并给出了C语言版本的源代码,非递归实现由于没有函数调用的消耗,相对于递归方式有一定的优势. 在快排序的递归实现中,函数quicksort(int nlow, int ...

  4. 选择排序-冒泡排序-归并排序-快速排序-插入排序

    选择排序 基本思想: 设所排序序列个数为N,i取1,2,3-n-1,从N-i+1个记录(Ri,Ri+1-.Rn)中找出排序码最小的记录,与第i个记录交换,执行N-1次后完成序列的排序. //选择排序 ...

  5. 快速排序—三路快排 vs 双基准

    快速排序被公认为是本世纪最重要的算法之一,这已经不是什么新闻了.对很多语言来说是实际系统排序,包括在Java中的Arrays.sort. 那么快速排序有什么新进展呢? 好吧,就像我刚才提到的那样(Ja ...

  6. 快速排序、快排的优化 及Java实现

    一.快速排序的思想 选取一个比较的基准,将待排序数据分为独立的两个部分,左侧都是小于或等于基准,右侧都是大于或等于基准,然后分别对左侧部分和右侧部分重复前面的过程,也就是左侧部分又选择一个基准,又分为 ...

  7. 八大排序算法之快速排序(下篇)(快排的优化+非递归快排的实现)

    目录 一.前言 1.快速排序的实现: 快速排序的单趟排序(排升序)(快慢指针法实现):​ 2.未经优化的快排的缺陷 二.快速排序的优化 1.三数取中优化 优化思路: 2. 小区间插入排序优化 小区间插 ...

  8. 快速排序 改进快排的方法

    快速排序法事应用最广泛的排序算法之一,最佳情况下时间复杂度是 O(nlogn).但是最坏情况下可能达到O(n^2).说明快速排序达到最坏情况的原因.并提出改善方案并实现之. 答: 改进方案:改进选取枢 ...

  9. 归并排序 快速排序 时间复杂度分析 (基本递归时间复杂度分析)

    归并排序 归并排序:利用分治的思想,先排左边一半,再排右边一半,最后再将两边有序的合并起来. 时间复杂度: 用T(n)T(n)T(n)表示排大小为nnn的数组的时间:T(n)=2T(n/2)+nT(1 ...

最新文章

  1. 浅析COM的思想及原理
  2. Tensorflow遇到的问题InvalidArgumentError: Graph execution error:2 root error(s) found.解决方法
  3. SSM-网站后台管理系统制作(2)---SSM基本工作原理
  4. Google开源的AR/VR开发库Lullaby
  5. Tkinter Helloword !
  6. java不用析构函数,堆栈分配的类--C发生不需要的析构函数调用
  7. VS2017编译UE4.19.2报错
  8. C 语言实例 - 判断三边能否构成三角形
  9. python基础--自定义模块、import、from......import......
  10. 返回值 包装类_(九)Java常用类
  11. iPhone 之后,苹果还会带来什么?
  12. 2022-01-09总结
  13. Scipy教程 - 距离计算库scipy.spatial.distance
  14. Java随机数的创建
  15. 15个免费好用的抓包工具
  16. DOSBox 0.74 汇编 out of memery test.asm(2):out of memory
  17. 2020-10-31
  18. 怎样利用关键词查排名的工具找到行业相关网站
  19. python用保留字while实现无限循环_Python中无限循环需要什么条件
  20. Windows系统自带的DOS窗口

热门文章

  1. 盘点中国顶级黑客Top10,雷军也名列其中!
  2. 怎么在html画出爱心,使用CSS绘制桃心
  3. 防止后缀aol.com}AOL勒索病毒*** .com}AOL勒索病毒解密工具处理方法
  4. Linux下ps命令
  5. AcWing 188. 武士风度的牛
  6. oracle12c密码登录失败,【译】解决Oracle12c Cloud Control登录验证出错问题
  7. 16.光照(平行光)
  8. 第四章 智能合约 [20]
  9. 7月第3周回顾:裁员潮袭卷IT人 雅虎服“软”愿被收购
  10. 脑科学研究中常用的神经电信号记录电极介绍