1
0
mirror of https://github.com/OmegaZhou/408-notes.git synced 2026-02-02 18:28:58 +08:00
Files
408-notes/数据结构/排序.md
2020-10-25 09:39:48 +08:00

5.1 KiB
Raw Blame History

排序

插入类排序

直接插入排序

时间复杂度

  • 平均时间复杂度O(n^2^)
  • 最好时间复杂度O(n)

空间复杂度

  • O(1)

折半插入排序

时间复杂度

  • 最好时间复杂度O(n*log(n))
  • 平均时间复杂度O(n^2^)

空间复杂度

  • O(1)

希尔排序

增量选取

  • \lfloor \frac {n}{2^k} \rfloor...2,1
  • 2^k+1...3,1

空间复杂度

  • O(1)

交换类排序

冒泡排序

时间复杂度

  • 平均时间复杂度O(n^2^)
  • 最好时间复杂度O(n)

空间复杂度

  • O(1)

快速排序

时间复杂度

  • 平均时间复杂度O(n*log(n))
  • 最好时间复杂度O(n*log(n))
  • 最坏时间复杂度O(n^2^)

空间复杂度

  • O(n*log(n))(需要递归栈)

选择类排序

直接选择排序

时间复杂度

  • O(n^2^)

空间复杂度

  • O(1)

堆排序

初始化堆
  1. 从底向上,找到第一个非叶子节点开始,向下浮动
  2. 直至到堆顶,初始化结束
插入节点
  1. 节点在堆底,进行上浮
删除节点
  1. 将尾节点位于栈顶,进行下浮操作

排序过程

  1. 初始化堆
  2. 将堆顶节点与尾节点交换,进行下浮操作
  3. 重复第二步,直至堆空

时间复杂度

  • O(n*log(n))

空间复杂度

  • O(1)

归并排序

二路归并排序

时间复杂度

  • O(n*log(n))

空间复杂度

  • O(n)

基数排序

步骤

  1. 按位遍历
  2. 第i趟遍历令第i位有序
  3. 循环主体:
    • 分成若干个桶,代表某一位的所有取值
    • 按顺序遍历数据时,将按位装桶
    • 最后按顺序依次桶中将数据提出

时间复杂度

  • O(d*(n+r))

空间复杂度

  • O(r)

内部排序比较

算法 最好时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度 稳定性
直接插入排序 O(n) O(n^2^`) O(n^2^) O(1) 稳定
冒泡排序 O(n) O(n^2^`) O(n^2^) O(1) 稳定
简单选择排序 O(n^2^) O(n^2^`) O(n^2^) O(1) 不稳定
希尔排序 O(1) 不稳定
快速排序 O(n*log2(n)) O(n*log2(n)) O(n^2^) O(log2(n)) 不稳定
堆排序 O(n*log2(n)) O(n*log2(n)) O(n*log2(n)) O(1) 不稳定
二路归并排序 O(n*log2(n)) O(n*log2(n)) O(n*log2(n)) O(n) 稳定
基数排序 O(d*(n+r)) O(d*(n+r)) O(d*(n+r)) O(r) 稳定

外部排序

主要思想

  1. 将待排序的数据段分成若干个小数据段(初始归并段),各段长度可能不同
  2. 对这些小数据段进行内排序(使用置换选择算法得到的初始归并段已经排好序了)
  3. 选出k组小数据段进行归并排序排序各段队首其余部分留在外存
  4. 排序完成后形成一条大归并段接着对之后k条数据段进行排序以此类推
  5. 再对大归并段进行归并排序,形成新的归并段,以此类推,直至所有数据排序完成

置换选择排序

  • 用于生成初始归并段

步骤

  1. 先将输入记录充满缓冲区(可用于排序的主存)
  2. 输出此时缓冲区最小的可输出的数,再从输入记录中填充一个新数至缓冲区,若新数小于之前输出的数,则打上不可输出的标签
  3. 重复第二步,直至缓冲区内数都是不可输出数,得到一条初始归并段
  4. 清空缓冲区内不可输出的标签,回到第二步,以此类推,生成剩余归并段

最佳归并树

  • 用于整个归并过程其中包括若干次k路归并

  • 使用归并树进行归并,每一个叶子节点代表一个初始归并段

  • 每一个非叶节点代表由子节点归并得到的新的归并树

  • 以归并段条数为权值构造k路霍夫曼树

    • 构造方法当归并段不足时虚设若干个权值为0的叶子节点补足
  • 归并树$IO次数=2*WPL$,每条数据需要读写各一次

  • 使用最佳归并树可使IO次数最少

败者树

  • 用于k路归并
  • 构造一个二叉树,其中叶子节点为归并段,父节点为子节点所代表归并段比较结果中的败者
  • 比较结果中的胜者不断上浮直至输出
  • 重新装入胜者所在归并段新的数据,进行上浮比较,构成新的败者树
  • 优点每次比较只需log2(k)次

时间复杂度

初始归并段进行k路归并

  • 归并总趟数:\lceil log_k(m) \rceil
  • 每一次归并所有记录进行两次I/O操作
  • 置换选择排序中所有记录需要进行两次I/O操作
  • 置换选择排序中,选最值的复杂度视具体算法而定
  • k路归并败者树高度=$\lceil log_2(k) \rceil+1$,选出最值需要比较$\lceil log_2(k) \rceil$次
  • 建立k路归并败者树复杂度为O(k*log2(k))