[数据结构笔记]分析排序算法的性能

笔记来源王争老师的数据结构与算法之美
逆序度 = 满有序度 - 有序度
冒泡排序
[数据结构笔记]分析排序算法的性能_第1张图片

冒泡排序 分析
是否原地排序算法
是否稳定的排序算法
最好情况时间复杂度 O(n) 逆序度为0,只需要进行一次冒泡操作,就可以结束
最坏情况时间复杂度 O(n2) 要排序的数据刚好是倒序排列的,需要进行 n 次冒泡操作
平均情况下的时间复杂度 O(n2) 平均情况下,需要 n*(n-1)/4 次交换操作,比较操作肯定要比交换操作多,而复杂度的上限是 O(n2),所以平均情况下的时间复杂度就是 O(n2)

插入排序
[数据结构笔记]分析排序算法的性能_第2张图片

插入排序 分析
是否原地排序算法
是否稳定的排序算法
最好情况时间复杂度 O(n) 从尾到头遍历已经有序的数据
最坏情况时间复杂度 O(n2) 从头到尾遍历倒序的数据
平均情况下的时间复杂度 O(n2) 在数组中插入一个数据的平均时间复杂度为O(n),对于插入排序来说,每次插入操作都相当于在数组中插入一个数据,循环执行 n 次插入操作,所以平均时间复杂度为 O(n2)

比较排序
[数据结构笔记]分析排序算法的性能_第3张图片

比较排序 分析
是否原地排序算法
是否稳定的排序算法
最好情况时间复杂度 O(n2) 不需要移动,比较次数为n2/2
最坏情况时间复杂度 O(n2) 移动3(n-1)次,比较次数n2/2
平均情况下的时间复杂度 O(n2)

思考:冒泡排序和插入排序的时间复杂度都是 O(n2),都是原地排序算法,为什么插入排序要比冒泡排序更受欢迎呢?
从代码实现上来看,冒泡排序的数据交换要比插入排序的数据移动要复杂,冒泡排序需要 3 个赋值操作,而插入排序只需要 1 个。

插入排序的优化:希尔排序

归并排序
归并排序使用的是分治思想
[数据结构笔记]分析排序算法的性能_第4张图片

归并排序 分析
是否原地排序算法 合并两个有序数组时需要额外的存储空间
是否稳定的排序算法
最好情况时间复杂度 O(nlogn) 归并排序的执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,时间复杂度O(nlogn)可以通过递归公式求解
最坏情况时间复杂度 O(nlogn)
平均情况下的时间复杂度 O(nlogn)
空间复杂度 O(n) 在任意时刻,CPU 只会有一个函数在执行,也就只会有一个临时的内存空间在使用。临时内存空间最大也不会超过 n 个数据的大小,所以空间复杂度是 O(n)

快速排序
快排同样利用分治思想
[数据结构笔记]分析排序算法的性能_第5张图片

快速排序 分析
是否原地排序算法
是否稳定的排序算法 分区的过程涉及交换操作,如果数组中有两个相同的元素,比如序列 6,8,7,6,3,5,9,4,在经过第一次分区操作之后,两个 6 的相对先后顺序就会改变
最好情况时间复杂度 O(nlogn) 每次分区操作,都能正好把数组分成大小接近相等的两个小区间,那快排的时间复杂度递推求解公式跟归并是相同的
最坏情况时间复杂度 O(n2) 如果数组中的数据原来已经是有序的了,比如 1,3,5,6,8。如果我们每次选择最后一个元素作为 pivot,那每次分区得到的两个区间都是不均等的。
平均情况下的时间复杂度 O(nlogn) T(n) 在大部分情况下的时间复杂度都可以做到 O(nlogn),只有在极端情况下,才会退化到 O(n2)

归并排序的处理过程是由下到上的,先处理子问题,然后再合并。而快排正好相反,它的处理过程是由上到下的,先分区,然后再处理子问题。归并排序虽然是稳定的、时间复杂度为 O(nlogn) 的排序算法,但是它是非原地排序算法。我们前面讲过,归并之所以是非原地排序算法,主要原因是合并函数无法在原地执行。快速排序通过设计巧妙的原地分区函数,可以实现原地排序,解决了归并排序占用太多内存的问题。

思考:
·如何在O(n) 时间复杂度内求无序数组中的第 K 大元素?
·现在你有 10 个接口访问日志文件,每个日志文件大小约 300MB,每个文件里的日志都是按照时间戳从小到大排序的。你希望将这 10 个较小的日志文件,合并为 1 个日志文件,合并之后的日志仍然按照时间戳从小到大排列。如果处理上述排序任务的机器内存只有 1GB,你有什么好的解决思路,能“快速”地将这 10 个日志文件合并吗?

桶排序
[数据结构笔记]分析排序算法的性能_第6张图片

时间复杂度是 O(n)
首先,要排序的数据需要很容易就能划分成 m 个桶,并且,桶与桶之间有着天然的大小顺序。其次,数据在各个桶之间的分布是比较均匀的。桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。

计数排序
[数据结构笔记]分析排序算法的性能_第7张图片
时间复杂度是 O(n)
计数排序只能用在数据范围不大的场景中,如果数据范围 k 比要排序的数据 n 大很多,就不适合用计数排序了。而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大小的情况下,转化为非负整数。

基数排序
[数据结构笔记]分析排序算法的性能_第8张图片

时间复杂度为 O(n)
基数排序对要排序的数据是有要求的,需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果 a 数据的高位比 b 数据大,那剩下的低位就不用比较了。除此之外,每一位的数据范围不能太大,要可以用线性排序算法来排序,否则,基数排序的时间复杂度就无法做到 O(n) 了

思考:
假设我们现在需要对 D,a,F,B,c,A,z 这个字符串进行排序,要求将其中所有小写字母都排在大写字母的前面,但小写字母内部和大写字母内部不要求有序。比如经过排序之后为 a,c,z,D,F,B,A,这个如何来实现呢?如果字符串中存储的不仅有大小写字母,还有数字。要将小写字母的放到前面,大写字母放在最后,数字放在中间,不用排序算法,又该怎么解决呢?

总结
[数据结构笔记]分析排序算法的性能_第9张图片

你可能感兴趣的:(数据结构,排序算法)