归并排序,快速排序为什么快
对于一个 n n n个元素的数组,必须要确定两两之间的相对顺序,假设每次都抓取不同的二元组,需要 log 2 n ! \log_2n! log2n!次比较,由于 log 2 n ! ≈ n log 2 n \log_2n!\approx n\log_2n log2n!≈nlog2n, O ( n log 2 n ) O(n\log_2n) O(nlog2n)就是排序算法的下界。
前面几周写过一篇散文:
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! log2n!的分析,比较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 log2n!≈nlog2n次比较是不包括可传递的关联比较的。
接下来只要说明归并排序和快速排序的每次比较都是无关联即可,这个是显然的:
- 归并排序:实际合并之前,两个子数组从没遇见过,不可能有任何关联。
- 快速排序:左右两个子数组均按原始相对顺序和锚点比较,内部彼此无关联。
无论如何,归并排序均可达 O ( n log 2 n ) O(n\log_2n) O(nlog2n)的时间复杂度,对于快速排序,在最理想情况下,也可达到,即便是平均情况,离最理想情况也不远。
冒泡排序的算法本身就如此定义,随排序进行,未排序序列趋于有序,但排序过程无法识别哪些比较是不必要的,从信息论的角度,大概率的非必要比较依然要进行,这些比较带来的信息量无疑很小,这就是低效的根源,反过来,归并排序和快速排序依偎着比较排序的下界,这就是它们快的根源。
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!1log2n!1=log2n!≈nlogn
时间复杂度就是信息熵的度量,引入新的预设,信息熵必然减小,冒泡排序随着排序的进行,将引入新的预设,而归并排序和快速排序在排序过程中一直保持最开始的预设,保持比较操作的无关联性。
浙江温州皮鞋湿,下雨进水不会胖。
归并排序,快速排序为什么快相关推荐
- C语言——十四种内部排序算法【直接插入排序-冒泡排序-选择排序-插入排序-希尔排序-归并排序-快速排序-堆排序-折半插入排序-二分查找-路插入排序-表插入排序-简单选择排序-直接选择排序-树形选择】
目录: 一:插入排序 A:直接插入排序 1.定义: 2.算法演示 实例1: 3.基本思想 4.排序流程图 实例1: B:希尔排序 1.定义: 2.算法演示 实例2: C:其他插入排序 a:折半插入排序 ...
- 快排和归并排序哪个更快
在看算法图解的过程中,看到书中说时间复杂度同为O(nlogn),快排比归并排序快的原因是快排查找的常量要比归并小. 看完还不是很理解,去网上查了下资料,看了几种回答,还是<数据结构与算法分析:C ...
- 非递归快速排序php,快排序的非递归实现(原创)
本文简要介绍快排序的非递归实现方式并给出了C语言版本的源代码,非递归实现由于没有函数调用的消耗,相对于递归方式有一定的优势. 在快排序的递归实现中,函数quicksort(int nlow, int ...
- 选择排序-冒泡排序-归并排序-快速排序-插入排序
选择排序 基本思想: 设所排序序列个数为N,i取1,2,3-n-1,从N-i+1个记录(Ri,Ri+1-.Rn)中找出排序码最小的记录,与第i个记录交换,执行N-1次后完成序列的排序. //选择排序 ...
- 快速排序—三路快排 vs 双基准
快速排序被公认为是本世纪最重要的算法之一,这已经不是什么新闻了.对很多语言来说是实际系统排序,包括在Java中的Arrays.sort. 那么快速排序有什么新进展呢? 好吧,就像我刚才提到的那样(Ja ...
- 快速排序、快排的优化 及Java实现
一.快速排序的思想 选取一个比较的基准,将待排序数据分为独立的两个部分,左侧都是小于或等于基准,右侧都是大于或等于基准,然后分别对左侧部分和右侧部分重复前面的过程,也就是左侧部分又选择一个基准,又分为 ...
- 八大排序算法之快速排序(下篇)(快排的优化+非递归快排的实现)
目录 一.前言 1.快速排序的实现: 快速排序的单趟排序(排升序)(快慢指针法实现): 2.未经优化的快排的缺陷 二.快速排序的优化 1.三数取中优化 优化思路: 2. 小区间插入排序优化 小区间插 ...
- 快速排序 改进快排的方法
快速排序法事应用最广泛的排序算法之一,最佳情况下时间复杂度是 O(nlogn).但是最坏情况下可能达到O(n^2).说明快速排序达到最坏情况的原因.并提出改善方案并实现之. 答: 改进方案:改进选取枢 ...
- 归并排序 快速排序 时间复杂度分析 (基本递归时间复杂度分析)
归并排序 归并排序:利用分治的思想,先排左边一半,再排右边一半,最后再将两边有序的合并起来. 时间复杂度: 用T(n)T(n)T(n)表示排大小为nnn的数组的时间:T(n)=2T(n/2)+nT(1 ...
最新文章
- 浅析COM的思想及原理
- Tensorflow遇到的问题InvalidArgumentError: Graph execution error:2 root error(s) found.解决方法
- SSM-网站后台管理系统制作(2)---SSM基本工作原理
- Google开源的AR/VR开发库Lullaby
- Tkinter Helloword !
- java不用析构函数,堆栈分配的类--C发生不需要的析构函数调用
- VS2017编译UE4.19.2报错
- C 语言实例 - 判断三边能否构成三角形
- python基础--自定义模块、import、from......import......
- 返回值 包装类_(九)Java常用类
- iPhone 之后,苹果还会带来什么?
- 2022-01-09总结
- Scipy教程 - 距离计算库scipy.spatial.distance
- Java随机数的创建
- 15个免费好用的抓包工具
- DOSBox 0.74 汇编 out of memery test.asm(2):out of memory
- 2020-10-31
- 怎样利用关键词查排名的工具找到行业相关网站
- python用保留字while实现无限循环_Python中无限循环需要什么条件
- Windows系统自带的DOS窗口
热门文章
- 盘点中国顶级黑客Top10,雷军也名列其中!
- 怎么在html画出爱心,使用CSS绘制桃心
- 防止后缀aol.com}AOL勒索病毒*** .com}AOL勒索病毒解密工具处理方法
- Linux下ps命令
- AcWing 188. 武士风度的牛
- oracle12c密码登录失败,【译】解决Oracle12c Cloud Control登录验证出错问题
- 16.光照(平行光)
- 第四章 智能合约 [20]
- 7月第3周回顾:裁员潮袭卷IT人 雅虎服“软”愿被收购
- 脑科学研究中常用的神经电信号记录电极介绍