MIT 6006 Lecture 7——计数排序,基数排序,排序的时间复杂度下界

AVL树——一种平衡的BST

课程内容

  • 比较模型
  • 时间复杂度下界
    • 搜索:$\Omega(\lg n)$
    • 排序:$\Omega(n\lg n)$
  • $O(n)$时间复杂度的排序
    • 计数排序
    • 基数排序

比较模型

定义

  • 所有输入对象均为黑盒(抽象数据结构)
  • 唯一允许的操作是比较操作($<,\le,>,\ge,=$)
  • 时间损耗只和比较操作的次数有关

决策树

任何的比较操作,实际上都可以视为一棵树,这棵树由可能的路径和结果构成。例如,二分查找可以被视为一颗二分查找树。下面给出了一个二分查找的过程,在长度$n=3$的数组里进行二分查找:

算法和树的对应关系如下:

决策树 算法
内部节点 二分决策(比较)
叶节点 结果
根到叶的路径 一次算法的执行
路径长度 算法的执行时间
树高 最坏执行时间

时间复杂度下界

搜索的时间复杂度下界

在$n$个经过处理(排序或其他操作)的对象中,根据比较模型找到一个指定的目标,最坏情况下时间复杂度下界为$\Omega(\lg n)$。

证明

  • 首先,我们的决策树是一个二叉树,同时,这棵树至少有$n$个节点,每个节点对应一个解
  • 所以树的高度$h\ge \lg n$,证明完毕

排序的时间复杂度下界

在搜索算法中,我们证明了$\Omega = \lg n$,即从$n$个对象中找到一个解的时间复杂度下界为$\lg n$,那么直观来看,如果我们要排序,就是从$n$个元素中找到$n$个解,这$n$个解分别为第一大元素、第二大元素、…、第$n$大元素,所以时间复杂度应为$n\lg n$。

证明

首先,对于这个排序问题,我们的决策树依旧是一个二叉树,所以我们要看一下这个树有多少个节点。对于排序问题,我们的一个节点也是一个解,这个解是一个排序序列,例如:

那么有多少个节点呢,根据排列组合,所有可能的情况为$A_n^n=n!$($n$ factorial),则树高$h$满足

我们现在要证明$\lg(n!)\ge n\lg n$,证明过程如下:

线性时间排序

假设我们的待排序的对象是整数,那么我们可以制造出一些整数排序的结果,我们先进行一些假设:

  • 假设key是整数,且$key\in{0,1,2,…,k-1}$,同时一个key的长度小于计算机的一个字
  • 不止可以进行比较操作,还可以进行别的操作
  • 对于$k$,可以在$O(n)$时间复杂度下进行排序

目前来说,最好的排序算法能够达到的时间复杂度为$O(n\sqrt{(\lg n\lg n)})$

计数排序

配置一个计数器,然后遍历数组,每遇到一个元素,就将对应的$key$所在的位置+1,然后遍历计数器,进行排序。计数排序中一个比较重要的问题是考虑排序的稳定性,如果我们要保证相同元素排序后位次不变,那么可以使用如下算法:

1
2
3
4
5
6
L = array of k empty lists      O(k)
for i in range(n): O(n)
L[key(A[j])].append(A[j]) O(1)
output = []
for i in range(k) O(n+k)
output.extend(L[i]) O(|li|)

所以计数排序的时间复杂度为$O(n+k)$,如果$k$很大,那么性能很差。

基数排序

基数排序基于计数排序,其基本原理是使用对数缩小数的范围,然后再利用计数排序进行排序

  • 同样假设key为整数,令其表示为以$b$为底的对数,即$d=\log_bk$
  • 然后我们的key的范围变成了$0-d$

实际上是进行了一次分组操作,对于一组进行计数排序,需要$O(n+b)$次操作;而对于全部,则需要$O((n+b)d)=O((n+b)\log_bk)$

可以证明,当$b=n$时,时间复杂度最小,为$O(n\log_nk)=O(nc)$

参考文献

0%