比较排序算法概述
文章目录
排序
ref
排序的对象
- 排序对象是:记录(也叫元素)的序列 { R i } \set{R_i} {Ri}
- 每个记录
R
i
R_i
Ri都含有若干个字段,对于排序而言,最重要的是
R
i
R_i
Ri其中的关键字字段
k
e
y
i
key_i
keyi
- 当记录最简单化,就是数值排序(比如实数排序/整数排序)
排序分类
- 内部排序
- 排序元素全部载入内存进行排序
- 外部排序
- 被排序元素在排序过程中,需要在内,外存间移动
排序算法的稳定性SortAlgorithmStability
- 待排序列
R
i
,
.
.
.
R
j
R_i,...R_j
Ri,...Rj具有前后关系,且
k
e
y
i
=
=
k
e
y
j
key_i==key_j
keyi==keyj
- 如果排序算法排序后,仍然有 R i 在 R j R_i在R_j Ri在Rj前面,则该排序算法稳定
性能分析
比较排序算法的性能分析原则
- 比较排序算法性能(时空复杂度)主要是取决于比较和移动的次数
基于比较的排序算法的比较次数
决策树(desicion tree)
- 因为任何正确的排序算法都能够生成输入的每一个排列
- 所以对一个正确的比较排序算法来说:
- n n n个元素的 n ! n! n!种可能的排列都应该出现在决策树的叶结点上。
- 给定任意一个待排序序列,经过某一个比较排序算法处理,得到排序完的结果序列
- 假设这个排序过程中发生的元素间调整操作的序列SOS(sort operation serials)
- 含有n个元素的待排序序列可能有n!中序列
- 这些序列在同一个排序算法对应不同的操作序列(操作序列的长度也可能不等长)
- 有的序列规律性强(例如最好的情况),需要的操作步骤少,有的则相反(最坏的情况)
- 最坏的情况对应于排序树从根结点到叶子结点的最长的一条路径(主要研究最坏的情况)
- 不同的待排序序列对应到了不同叶结点
- 因此叶子结点至少有n!个
- 由这个约束,我们可以确定比较排序的决策树的高度下限
- 而且,(每一个叶结点都必须是可以从根结点经由某条路径到达的,该路径对应于比较排序的一次实际执行过程(我们称这种叶结点为“可达的”)。
- 因此,我们只考虑(每一种排列都是一个可达的叶结点的决策树)。
- 所以对一个正确的比较排序算法来说:
-
上述输入序列的元素序列:6,8,5
-
根据插入排序算法构建的插入排序决策树
-
排序目标时升序排列
-
最坏的情况下需要从根结点比较到最长路径的叶子结点
- 例如上例中的粗线路径(插入排序比较过程)
- 从 a 1 开始插入 a 2 , a 3 a_1开始插入a_2,a_3 a1开始插入a2,a3
- 例如上例中的粗线路径(插入排序比较过程)
-
最好的能够确定全序列有序情况是:
-
a 1 > a 2 a_1>a_2 a1>a2
-
a 1 < a 3 a_1<a_3 a1<a3
-
因为,上述两个比较足以确定下来 a 2 < a 1 < a 3 a_2<a_1<a_3 a2<a1<a3
-
对应于例图中的 < 2 , 1 , 3 > 叶子结点 对应于例图中的<2,1,3>叶子结点 对应于例图中的<2,1,3>叶子结点
-
决策树分析
- 在最坏情况下,任何比较排序算法都需要做
(
n
lg
n
)
(n\lg n)
(nlgn)次比较。
- 证明︰根据前面的讨论,对于一棵每个排列都是一个可达的叶结点的决策树来说,树的高度完全可以被确定。
- 考虑一棵高度为 h 、具有 l 个可达叶结点的决策树,它对应一个对 n 个元素所做的比较排序。 考虑一棵高度为h、具有l个可达叶结点的决策树,它对应一个对n个元素所做的比较排序。 考虑一棵高度为h、具有l个可达叶结点的决策树,它对应一个对n个元素所做的比较排序。
- 因为输入数据的 n ! n! n!种可能的排列都是叶结点,所以有 n ! ⩽ l n!\leqslant l n!⩽l。
- 由于在一棵高为h的二叉树中,叶结点的数目不多于 2 h − 1 2^{h-1} 2h−1,如果根结点所在高度为0,则叶结点数上限为 2 h 2^h 2h
- 我们得到
l
l
l的取值确界:
- n ! ⩽ l ⩽ 2 h n!\leqslant l\leqslant 2^{h} n!⩽l⩽2h
- 对该式两边取对数,有
- h ≥ lg ( n ! ) = Ω ( n lg n ) h≥\lg(n!)=\Omega(n\lg n) h≥lg(n!)=Ω(nlgn)
渐近最优的比较排序算法
- 堆排序和归并排序都是渐近最优的比较排序算法。
- 堆排序和归并排序的运行时间上界为O( n lg n n\lg n nlgn)
判断给定序列的有序性(数值序列)
- 有序序列包括顺序和逆序
- 一个简单的思路是,但发现任意三个元素中是无序的,则整个序列无序
- 对于无序序列往往不需要扫描完整个序列就可以判定无序
- 不超过n-1次
- 对于序列,则必须至少比较n-1次才可以确定是有序的
- 但也不超过n-1次
- 对于无序序列往往不需要扫描完整个序列就可以判定无序
def judgeOrder(l, i=0, order=0,log=0): len_l = len(l) asc_mark = 0 dsc_mark = 0 while (i < len_l - 1): # print(asc_mark, dsc_mark) if l[i] <= l[i + 1]: asc_mark += 1 else: dsc_mark += 1 if asc_mark and dsc_mark: if log: print(l, "disorder!!") return False else: i += 1 # if(log): print(l, "ascend👆" if asc_mark else "dscend⏬", "orderd!") if (not order): return True elif (order == 1 and asc_mark): return True elif (order == -1 and dsc_mark): return True return False # def judgeOrderRecursiveDescend(l, i=0): if __name__ == "__main__": n=40 print(ordered_list) # ordered_list=[42,311,111,110] judgeOrder(ordered_list) for i in range(n): rand.shuffle(ordered_list) judgeOrder(ordered_list,log=1) print("--------------------升序----------------") for i in range(n): rand.shuffle(ordered_list) if(judgeOrder(ordered_list,order=1)): print("True") print("-------------------降序-----------------") for i in range(n): rand.shuffle(ordered_list) if(judgeOrder(ordered_list,order=-1)): print("True")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了