目录
为什么排序如此重要?
8大排序算法全家福
一、经典排序算法详解
1. 冒泡排序(Bubble Sort)
2. 插入排序(Insertion Sort)
二、高效排序算法
3. 快速排序(Quick Sort)
4. 归并排序(Merge Sort)
三、进阶排序算法
5. 堆排序(Heap Sort)
6. 希尔排序(Shell Sort)
四、特殊场景排序
7. 计数排序(Counting Sort)
8. 基数排序(Radix Sort)
六、工程实践建议
数据处理核心:90%的算法面试必考知识点
效率差距巨大:不同排序算法性能相差千倍
应用无处不在:数据库索引、推荐系统、金融分析
算法 | 时间复杂度 | 空间复杂度 | 稳定性 | 适用场景 |
---|---|---|---|---|
冒泡排序 | O(n²) | O(1) | ✔️ | 教学演示 |
快速排序 | O(n log n) | O(log n) | ❌ | 通用大数据排序 |
归并排序 | O(n log n) | O(n) | ✔️ | 链表/外部排序 |
堆排序 | O(n log n) | O(1) | ❌ | Top K问题 |
插入排序 | O(n²) | O(1) | ✔️ | 小规模有序数据 |
希尔排序 | O(n^1.3) | O(1) | ❌ | 中等规模数据 |
计数排序 | O(n+k) | O(k) | ✔️ | 数据范围小的整数 |
基数排序 | O(n*k) | O(n+k) | ✔️ | 电话号码排序 |
算法思想:相邻元素两两比较,像气泡上浮
时间复杂度:O(n²)
C++实现:
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++) {
bool swapped = false;
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
swap(arr[j], arr[j+1]);
swapped = true;
}
}
if (!swapped) break; // 优化:提前终止
}
}
执行过程:
初始: [5,3,8,6,4]
第1轮:3 5 6 4 [8]
第2轮:3 5 4 [6 8]
第3轮:3 4 [5 6 8]
算法思想:将未排序元素逐个插入已排序序列的正确位置
C++实现:
void insertionSort(int arr[], int n) {
for(int i=1; i=0 && arr[j]>key){
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
}
执行过程:
初始: [12, 11, 13, 5, 6]
步骤1:11,12 |13,5,6
步骤2:11,12,13 |5,6
步骤3:5,11,12,13 |6
算法思想:分治策略,选取基准值将数组分为两个子数组
C++实现:
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
for(int j=low; j
执行过程:
基准值选6:[5,3,8,6,4]
▲
分区结果:[3,4,5] 6 [8]
算法思想:分治法+合并有序子序列
C++实现:
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for(int i=0; i= r) return;
int m = l + (r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
执行过程:
分割阶段:[8,3,5,1,7,4,2,6]
↓
合并阶段:[3,8] [1,5] [4,7] [2,6] → [1,3,5,8] [2,4,6,7] → [1,2,3,4,5,6,7,8]
算法思想:利用堆结构特性进行选择排序
C++实现:
void heapify(int arr[], int n, int i) {
int largest = i;
int l = 2*i + 1;
int r = 2*i + 2;
if(larr[largest]) largest = l;
if(rarr[largest]) largest = r;
if(largest != i) {
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n) {
// 构建大顶堆
for(int i=n/2-1; i>=0; i--)
heapify(arr, n, i);
// 逐个提取元素
for(int i=n-1; i>0; i--) {
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
堆结构变化:
初始数组: [4, 10, 3, 5, 1]
构建大顶堆: 10
/ \
5 3
/ \
4 1
算法思想:改进的插入排序,通过增量分组进行预处理
C++实现:
void shellSort(int arr[], int n) {
for(int gap=n/2; gap>0; gap/=2) {
for(int i=gap; i=gap && arr[j-gap]>temp; j-=gap)
arr[j] = arr[j-gap];
arr[j] = temp;
}
}
}
执行过程:
增量序列:4 → 2 → 1
初始数组: [12,34,54,2,3]
gap=2时分组:[12,54,3], [34,2]
排序后: [3,2,12,34,54]
算法思想:统计元素出现次数实现线性排序
C++实现:
void countingSort(int arr[], int n) {
int maxVal = *max_element(arr, arr+n);
int minVal = *min_element(arr, arr+n);
int range = maxVal - minVal + 1;
vector count(range), output(n);
for(int i=0; i=0; i--) {
output[count[arr[i]-minVal]-1] = arr[i];
count[arr[i]-minVal]--;
}
for(int i=0; i
计数过程:
输入数组: [1,4,1,2,7,5,2]
计数数组: [0,2,2,0,1,1,0,1]
输出数组: [1,1,2,2,4,5,7]
算法思想:按位数从低位到高位进行稳定排序
C++实现:
void radixSort(int arr[], int n) {
int maxVal = *max_element(arr, arr+n);
for(int exp=1; maxVal/exp>0; exp*=10) {
vector output(n);
int count[10] = {0};
for(int i=0; i=0; i--) {
output[count[(arr[i]/exp)%10]-1] = arr[i];
count[(arr[i]/exp)%10]--;
}
for(int i=0; i
执行过程:
输入: [170,45,75,90,802,24,2,66]
按个位排序: [170,90,802,2,24,45,75,66]
按十位排序: [802,2,24,45,66,170,75,90]
按百位排序: [2,24,45,66,75,90,170,802]
数据规模选择
n < 50:优先使用插入排序
50 ≤ n ≤ 1000:希尔排序
n > 1000:快速排序/归并排序
稳定性要求:需要稳定排序时选择归并排序/计数排序
内存限制
内存敏感场景使用堆排序(O(1)空间)
大数据量使用外部排序(归并排序变种)
关注我,持续解锁算法核心知识体系!