✅ 什么是排序的“稳定性”?
稳定排序:
如果两个元素在原数组中值相同,排序后它们的相对顺序不变,这种排序就叫稳定排序。
不稳定排序:
如果排序后,相等元素之间的顺序被打乱了,那就是不稳定排序。
好的,下面是最常用的排序算法总结,包括:
- 算法原理简述
- 时间复杂度(最优 / 平均 / 最差)
- 空间复杂度
- 是否稳定
- 简单实现(以 C++ 为例)
🧮 常用排序算法对比表
排序算法 | 时间复杂度(最优 / 平均 / 最差) | 空间复杂度 | 稳定性 | 备注 |
---|---|---|---|---|
冒泡排序 | 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 log n) / O(n log n) / O(n log n) | O(n) | ✅ 稳定 | 分治思想 |
快速排序 | O(n log n) / O(n log n) / O(n²) | O(log n) | ❌ 不稳定 | 实际中最快 |
堆排序 | O(n log n) / O(n log n) / O(n log n) | O(1) | ❌ 不稳定 | 基于堆结构 |
希尔排序 | O(n log n)(取决于增量序列) | O(1) | ❌ 不稳定 | 插入排序优化 |
计数排序 | O(n + k) | O(n + k) | ✅ 稳定 | 只适合整数且范围小 |
桶排序 | O(n + k) | O(n + k) | ✅ 稳定 | 倾向于均匀分布 |
基数排序 | O(n * d)(d为位数) | O(n + k) | ✅ 稳定 | 用于整数或字符串 |
🔧 典型排序算法实现(C++)
1. 冒泡排序(Bubble Sort)
void bubbleSort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i++)
for (int j = 0; j < n - 1 - i; j++)
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}
✅ 稳定,适合入门讲解。
2. 插入排序(Insertion Sort)
void insertionSort(vector<int>& arr) {
for (int i = 1; i < arr.size(); i++) {
int key = arr[i], j = i - 1;
while (j >= 0 && arr[j] > key)
arr[j + 1] = arr[j--];
arr[j + 1] = key;
}
}
✅ 稳定,适合“几乎有序”数组。
3. 归并排序(Merge Sort)
void merge(vector<int>& arr, int l, int m, int r) {
vector<int> left(arr.begin() + l, arr.begin() + m + 1);
vector<int> right(arr.begin() + m + 1, arr.begin() + r + 1);
int i = 0, j = 0, k = l;
while (i < left.size() && j < right.size())
arr[k++] = (left[i] <= right[j]) ? left[i++] : right[j++];
while (i < left.size()) arr[k++] = left[i++];
while (j < right.size()) arr[k++] = right[j++];
}
void mergeSort(vector<int>& arr, int l, int r) {
if (l >= r) return;
int m = (l + r) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
✅ 稳定,适合大数据排序。
4. 快速排序(Quick Sort)
int partition(vector<int>& arr, int l, int r) {
int pivot = arr[r]; // 选最后一个元素作为基准
int i = l; // i 指向第一个“大于等于 pivot”的位置
for (int j = l; j < r; j++) {
if (arr[j] < pivot) {
swap(arr[i], arr[j]);
i++; // i 往后移,为下一个小于 pivot 的位置
}
}
// 最后将 pivot 放到“中间”正确位置
swap(arr[i], arr[r]);
return i;
}
void quickSort(vector<int>& arr, int l, int r) {
if (l < r) {
int pi = partition(arr, l, r);
quickSort(arr, l, pi - 1);
quickSort(arr, pi + 1, r);
}
}
❌ 不稳定,但实际中最快,适合大多数通用情况。
5. 堆排序(Heap Sort)
void heapify(vector<int>& arr, int n, int i) {
int largest = i, l = 2 * i + 1, r = 2 * i + 2;
if (l < n && arr[l] > arr[largest]) largest = l;
if (r < n && arr[r] > arr[largest]) largest = r;
if (largest != i) {
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(vector<int>& arr) {
int n = arr.size();
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);
}
}
❌ 不稳定,常用于优先队列实现。
🧠 小总结:
你要排序的对象 | 推荐算法 |
---|---|
小数据、教学 | 冒泡 / 插入 |
大数据、稳定 | 归并排序 |
速度优先 | 快速排序 |
不要求稳定、原地 | 堆排序 |
整数范围小 | 计数 / 桶排序 |
整数位数不大 | 基数排序 |
当然可以!这里我给你列出 每个常用排序算法的示例,包括:
- 排序前数组
- 排序后数组
- 排序过程简单说明(便于理解)
为了统一说明,我们使用同一个例子数组:
原始数组:{5, 2, 9, 1, 5, 6}
✅ 1. 冒泡排序(Bubble Sort)
🔁 原理:
相邻两个元素比较,大的往后“冒泡”
示例过程(部分):
[5, 2, 9, 1, 5, 6]
→ [2, 5, 9, 1, 5, 6]
→ [2, 5, 1, 9, 5, 6]
→ [2, 5, 1, 5, 9, 6]
→ [2, 5, 1, 5, 6, 9] ...
排序后:
[1, 2, 5, 5, 6, 9]
✅ 稳定
✅ 2. 选择排序(Selection Sort)
🧠 原理:
每次找最小值放到前面,交换次数少
示例过程(部分):
[5, 2, 9, 1, 5, 6]
→ 选出 1 → [1, 2, 9, 5, 5, 6]
→ 选出 2 → [1, 2, 9, 5, 5, 6]
→ 选出 5 → [1, 2, 5, 9, 5, 6]
→ ...
排序后:
[1, 2, 5, 5, 6, 9]
❌ 不稳定
✅ 3. 插入排序(Insertion Sort)
✍️ 原理:
每个元素向前插入到合适位置
示例过程(部分):
[5, 2, 9, 1, 5, 6]
→ 插入2 → [2, 5, 9, 1, 5, 6]
→ 插入9 → [2, 5, 9, 1, 5, 6]
→ 插入1 → [1, 2, 5, 9, 5, 6]
→ 插入5 → [1, 2, 5, 5, 9, 6]
→ 插入6 → [1, 2, 5, 5, 6, 9]
✅ 稳定
✅ 4. 归并排序(Merge Sort)
🧩 原理:
分而治之 → 先拆分,再合并排序
拆分过程:
[5,2,9,1,5,6] → [5,2,9] 和 [1,5,6]
→ [5,2] [9] 和 [1] [5,6]
→ ...
合并过程:
[5,2] → [2,5]
[1,5,6] → 合并 → [1,5,6]
最终合并 → [1,2,5,5,6,9]
✅ 稳定
✅ 5. 快速排序(Quick Sort)
⚡ 原理:
选一个基准,分成比它小和大的两组递归排
示例过程(部分):
选 pivot = 6
→ 小于6:[5,2,1,5],大于6:[9]
→ 排小组:[5,2,1,5] 递归
→ 最终:[1,2,5,5,6,9]
❌ 不稳定
✅ 6. 堆排序(Heap Sort)
🏗️ 原理:
构造最大堆,每次取堆顶放末尾,重新堆化
示例过程(部分):
构建最大堆:9 在堆顶
→ swap(9,6) → [5,2,6,1,5,9]
→ 重新堆化 → 6 在堆顶,再 swap...
→ 最终:[1,2,5,5,6,9]
❌ 不稳定
✅ 7. 计数排序(Counting Sort)
🎯 原理:
统计每个元素出现次数,然后按顺序输出
适合:
- 元素是非负整数
- 范围小(如 0~100)
示例:
原始数组 [5, 2, 9, 1, 5, 6]
计数数组:
count[1] = 1
count[2] = 1
count[5] = 2
count[6] = 1
count[9] = 1
输出排序结果:
[1, 2, 5, 5, 6, 9]
✅ 稳定
✅ 8. 桶排序(Bucket Sort)
🪣 原理:
将数据分到不同区间的桶里,每个桶内部排序,再合并
适合:数据均匀分布
示例:
- 分桶:{1,2},{5,5,6},{9}
- 每个桶排序后合并
→[1, 2, 5, 5, 6, 9]
✅ 稳定
✅ 9. 基数排序(Radix Sort)
🔢 原理:
从个位到最高位依次排序(适合整数/字符串)
示例(数字按位):
[5,2,9,1,5,6] → 只有一位数,直接按个位排序 → [1,2,5,5,6,9]
多位数例子如 [170, 45, 75, 90, 802]
✅ 稳定