8.1 排序的基本概念
排序
输入 n 个记录 R₁,R₂,…,Rₙ,对应关键字 k₁,k₂,…,kₙ,输出一个排列 R'₁,…,R'ₙ 使 k'₁ ≤ k'₂ ≤ … ≤ k'ₙ。- 稳定性:相等关键字的记录在排序后相对位置不变则稳定。
- 内部排序:数据全在内存中;外部排序:需借助外存(归并路数+败者树+置换-选择排序)。
- 排序算法评价:时间复杂度、空间复杂度、稳定性、比较/移动次数。
8.2 插入排序
1. 直接插入排序
将无序区首元素插入到有序区的正确位置。设哨兵 a[0],从 i=2..n:将 a[i] 暂存,有序区后移直到插入位。
- 时间:最好 O(n)(已有序),平均/最坏 O(n²);稳定;空间 O(1)。
void InsertSort(int a[],int n){
for(int i=2;i<=n;i++){
a[0]=a[i]; int j=i-1;
for(;a[0]
2. 折半插入排序
有序区内用折半查找定位插入位置,减少比较次数(仍为 O(log n) 定位+O(n) 移动);移动次数不变,总体仍 O(n²)。
3. 希尔排序(缩小增量排序)
按增量 d_k 将表分组,组内直接插入;逐步缩小 d(如 d₁=n/2, d_{k+1}=⌊d_k/2⌋)直至 d=1。时间约 O(n^1.3);不稳定。
8.3 交换排序
1. 冒泡排序
每趟两两比较相邻记录,将最大/最小者"冒泡"到一端。某趟无交换即可提前结束。
- 最好 O(n),平均/最坏 O(n²);稳定。
2. 快速排序(Hoare 划分)
选基准 pivot,一趟划分出两区间:左 ≤ pivot ≤ 右,递归子区间。
- 平均 O(n log n),最坏 O(n²)(基本有序时退化)。
- 空间 O(log n)~O(n)(递归栈);不稳定。
- 快速排序是内部排序中平均性能最优的算法。
int Partition(int a[],int low,int high){
int pivot=a[low];
while(lowwhile(low=pivot) high--;
a[low]=a[high];
while(lowreturn low;
}
void QuickSort(int a[],int low,int high){
if(lowint p=Partition(a,low,high);
QuickSort(a,low,p-1); QuickSort(a,p+1,high);
}
}
8.4 选择排序
1. 简单选择排序
每趟从无序区选出最小记录与无序区首元素交换。比较次数恒为 n(n-1)/2;移动次数少。O(n²),不稳定。
2. 堆排序
- 大根堆:a[i] ≥ a[2i] 且 a[i] ≥ a[2i+1](升序用大根堆;降序用小根堆)。
- 建堆:⌊n/2⌋ 的结点开始向下调整,O(n)。
- 每趟堆顶与末尾交换,堆规模 −1 再向下调整。总 O(n log n);不稳定;空间 O(1)。
- 适合选取"前 k 大/小"的题目。
8.5 归并排序
二路归并:将相邻两有序表合成一个;递归或迭代(非递归更省空间)实现。时间恒 O(n log n);稳定;空间 O(n)。
8.6 基数排序
基于多关键字分配-收集:按低位→高位(LSD)或高位→低位(MSD),每趟分配到 r 个队列再依次收集。O(d(n+r));稳定;空间 O(r)。
排序算法统一可视化(7 种算法 + 随机数据)
交互式
数据量
▸ 柱状图越高表示数值越大;颜色区分已排序/比较/交换/基准/桶状态
速度1x
8.7 外部排序简介
- 基本方法:归并路数 k 越大趟数越少;k 路平衡归并。
- 败者树:在 k 个归并段中取最小者仅需 ⌈log₂k⌉ 次比较,与 k 无关。
- 置换-选择排序:在内存工作区容量 m 时生成平均长度为 2m 的初始归并段。
- 最佳归并树(哈夫曼思想):k 叉哈夫曼树,使总 I/O 最少;空缺补"虚段"。
8.8 各类排序比较
| 算法 | 平均 | 最坏 | 最好 | 空间 | 稳定 |
|---|---|---|---|---|---|
| 直接插入 | O(n²) | O(n²) | O(n) | O(1) | |
| 冒泡 | O(n²) | O(n²) | O(n) | O(1) | |
| 简单选择 | O(n²) | O(n²) | O(n²) | O(1) | |
| 希尔 | O(n^1.3) | O(n²) | — | O(1) | |
| 快速 | O(nlogn) | O(n²) | O(nlogn) | O(logn) | |
| 堆 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | |
| 2路归并 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | |
| 基数 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(r) |
记忆口诀:稳定排序 = "插冒归基"(插入/冒泡/归并/基数),其余不稳定。
8.9 外部排序动画演示
当数据量超过内存容量时需要外部排序。核心是 多路归并 减少I/O次数, 用 败者树 选出最小关键字, 置换-选择排序 生成更长的初始归并段。
外部排序: 5路归并 + 败者树
交互式动画速度 1x
步骤 0/0