mirror of
https://github.com/OmegaZhou/408-notes.git
synced 2026-02-02 18:28:58 +08:00
5.1 KiB
5.1 KiB
排序
插入类排序
直接插入排序
时间复杂度
- 平均时间复杂度O(n^2^)
- 最好时间复杂度O(n)
空间复杂度
- O(1)
折半插入排序
时间复杂度
- 最好时间复杂度O(n*log(n))
- 平均时间复杂度O(n^2^)
空间复杂度
- O(1)
希尔排序
增量选取
\lfloor \frac {n}{2^k} \rfloor...2,12^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)
堆排序
堆
初始化堆
- 从底向上,找到第一个非叶子节点开始,向下浮动
- 直至到堆顶,初始化结束
插入节点
- 节点在堆底,进行上浮
删除节点
- 将尾节点位于栈顶,进行下浮操作
排序过程
- 初始化堆
- 将堆顶节点与尾节点交换,进行下浮操作
- 重复第二步,直至堆空
时间复杂度
- O(n*log(n))
空间复杂度
- O(1)
归并排序
二路归并排序
时间复杂度
- O(n*log(n))
空间复杂度
- O(n)
基数排序
步骤
- 按位遍历
- 第i趟遍历令第i位有序
- 循环主体:
- 分成若干个桶,代表某一位的所有取值
- 按顺序遍历数据时,将按位装桶
- 最后按顺序依次桶中将数据提出
时间复杂度
- 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*log |
O(n*log |
O(n^2^) | O(log |
不稳定 |
| 堆排序 | O(n*log |
O(n*log |
O(n*log |
O(1) | 不稳定 |
| 二路归并排序 | O(n*log |
O(n*log |
O(n*log |
O(n) | 稳定 |
| 基数排序 | O(d*(n+r)) | O(d*(n+r)) | O(d*(n+r)) | O(r) | 稳定 |
外部排序
主要思想
- 将待排序的数据段分成若干个小数据段(初始归并段),各段长度可能不同
- 对这些小数据段进行内排序(使用置换选择算法得到的初始归并段已经排好序了)
- 选出k组小数据段,进行归并排序(排序各段队首,其余部分留在外存)
- 排序完成后形成一条大归并段,接着对之后k条数据段进行排序,以此类推
- 再对大归并段进行归并排序,形成新的归并段,以此类推,直至所有数据排序完成
置换选择排序
- 用于生成初始归并段
步骤
- 先将输入记录充满缓冲区(可用于排序的主存)
- 输出此时缓冲区最小的可输出的数,再从输入记录中填充一个新数至缓冲区,若新数小于之前输出的数,则打上不可输出的标签
- 重复第二步,直至缓冲区内数都是不可输出数,得到一条初始归并段
- 清空缓冲区内不可输出的标签,回到第二步,以此类推,生成剩余归并段
最佳归并树
-
用于整个归并过程,其中包括若干次k路归并
-
使用归并树进行归并,每一个叶子节点代表一个初始归并段
-
每一个非叶节点代表由子节点归并得到的新的归并树
-
以归并段条数为权值,构造k路霍夫曼树
- 构造方法:当归并段不足时,虚设若干个权值为0的叶子节点补足
-
归并树$IO次数=2*WPL$,每条数据需要读写各一次
-
使用最佳归并树可使IO次数最少
败者树
- 用于k路归并
- 构造一个二叉树,其中叶子节点为归并段,父节点为子节点所代表归并段比较结果中的败者
- 比较结果中的胜者不断上浮直至输出
- 重新装入胜者所在归并段新的数据,进行上浮比较,构成新的败者树
- 优点:每次比较只需log
2(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*log
2(k))