- C++
十大经典排序算法
- @ 2026-1-24 11:20:24
原文链接
本系列算法整理自:https://github.com/hustcc/JS-Sorting-Algorithm
同时也参考了维基百科做了一些补充。
排序算法是《数据结构与算法》中最基本的算法之一。
排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。用一张图概括:

点击以下图片查看大图:
关于时间复杂度
平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。
线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;
O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序
线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。
关于稳定性
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。
名词解释:
- n:数据规模
- k:"桶"的个数
- In-place:占用常数内存,不占用额外内存
- Out-place:占用额外内存
- 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同
包含以下内容:
相关书籍
双向冒泡排序
双向冒泡排序,又叫鸡尾酒排序(Cocktail Sort)。
它的过程是:先从左往右比较一次,再从右往左比较一次,然后又从左往右比较一次,以此类推。
它是为了优化前面的大部分元素都已经排好序的数组的排序,例如对于数组 [2,3,4,5,6,7,8,1],如果使用普通的冒泡排序,需要比较七次;而换成双向冒泡排序,只需比较三次。
public void cocktailSort(int[] a) {
int left = 0;
int right = a.length - 1;
while (left < right) {
for (int i = left; i < right; i++) { // 保证 a[right] 是最大的
if (a[i] > a[i+1]) {
swap(a, i, i+1);
}
}
right--;
for (int i = right; i > left; i--) { // 保证 a[left] 是最小的
if (a[i] < a[i-1]) {
swap(a, i, i-1);
}
}
left++;
}
}
归并排序C++容易理解版本
#include <iostream>
#include <vector>
using namespace std;
// 合并两个有序子数组
void merge(vector<int>& arr, int left, int mid, int right) {
vector<int> temp(right - left + 1);
int i = left, j = mid + 1, k = 0;
// 合并两个有序子数组[4](@ref)
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 复制剩余元素[3](@ref)
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
// 将临时数组复制回原数组[1](@ref)
for (int idx = 0; idx < k; idx++) {
arr[left + idx] = temp[idx];
}
}
// 归并排序(原地修改)
void merge_sort_inplace(vector<int>& arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
// 递归排序左右子数组[6](@ref)
merge_sort_inplace(arr, left, mid);
merge_sort_inplace(arr, mid + 1, right);
// 合并已排序的子数组[4](@ref)
merge(arr, left, mid, right);
}
}
// 包装函数,简化调用
void merge_sort(vector<int>& arr) {
if (!arr.empty()) {
merge_sort_inplace(arr, 0, arr.size() - 1);
}
}
int main() {
vector<int> arr = {38, 27, 43, 3, 9, 82, 10};
cout << "原始数组: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
merge_sort(arr);
cout << "排序后数组: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
return 0;
}
//迭代版本
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 合并两个有序子数组
void merge(vector<int>& arr, int left, int mid, int right, vector<int>& temp) {
int i = left, j = mid + 1, k = left;
// 合并两个有序子数组[1,4](@ref)
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 复制剩余元素[1,4](@ref)
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
// 将临时数组复制回原数组[1](@ref)
for (int idx = left; idx <= right; idx++) {
arr[idx] = temp[idx];
}
}
// 归并排序迭代版本
void merge_sort_iterative(vector<int>& arr) {
int n = arr.size();
if (n <= 1) return;
vector<int> temp(n);
// 从底部开始,逐步增加子数组大小[1,4](@ref)
for (int width = 1; width < n; width *= 2) {
// 每次处理两个相邻的子数组[1](@ref)
for (int left = 0; left < n; left += 2 * width) {
// 计算中点,注意边界保护[3](@ref)
int mid = min(left + width - 1, n - 1);
int right = min(left + 2 * width - 1, n - 1);
// 只有当存在两个子数组需要合并时才进行合并[1](@ref)
if (mid < right) {
merge(arr, left, mid, right, temp);
}
}
}
}
int main() {
vector<int> arr = {38, 27, 43, 3, 9, 82, 10};
cout << "原始数组: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
merge_sort_iterative(arr);
cout << "排序后数组: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
// 测试更多例子
vector<int> arr2 = {5, 2, 8, 1, 9, 3, 7, 4, 6};
cout << "另一个测试数组: ";
for (int num : arr2) {
cout << num << " ";
}
cout << endl;
merge_sort_iterative(arr2);
cout << "排序后: ";
for (int num : arr2) {
cout << num << " ";
}
cout << endl;
return 0;
}
第k大数递归版
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;
// 随机分区函数,返回大于基准值的元素个数
int partition(vector<int>& nums, int left, int right) {
// 随机选择基准值
int random_index = left + rand() % (right - left + 1);
swap(nums[left], nums[random_index]);
int pivot = nums[left];
// 将大于基准值的元素移到左边,小于等于基准值的元素移到右边
int i = left + 1, j = right;
while (i <= j) {
if (nums[i] >= pivot) {
i++;
} else if (nums[j] <= pivot) {
j--;
} else {
swap(nums[i], nums[j]);
i++;
j--;
}
}
// 将基准值放到正确的位置
swap(nums[left], nums[j]);
// 返回大于基准值的元素个数
return j - left;
}
// 快速选择算法,返回第k大的数
int quickSelect(vector<int>& nums, int left, int right, int k) {
if (left == right) return nums[left];
// 进行分区
int cnt = partition(nums, left, right);
// 判断第k大的数在哪一部分
if (k <= cnt) {
// 在左半部分(大于基准值的部分)
return quickSelect(nums, left, left + cnt - 1, k);
} else if (k == cnt + 1) {
// 基准值正好是第k大的数
return nums[left + cnt];
} else {
// 在右半部分(小于等于基准值的部分)
return quickSelect(nums, left + cnt + 1, right, k - cnt - 1);
}
}
// 包装函数,方便调用
int findKthLargest(vector<int>& nums, int k) {
srand(time(0)); // 初始化随机种子
return quickSelect(nums, 0, nums.size() - 1, k);
}
int main() {
// 测试示例
vector<int> nums = {3, 2, 1, 5, 6, 4};
int k = 2; // 找第2大的数
cout << "数组: ";
for (int num : nums) cout << num << " ";
cout << endl;
int result = findKthLargest(nums, k);
cout << "第" << k << "大的数是: " << result << endl;
// 验证:排序后查看
vector<int> sorted_nums = nums;
sort(sorted_nums.begin(), sorted_nums.end(), greater<int>());
cout << "排序后数组(从大到小): ";
for (int num : sorted_nums) cout << num << " ";
cout << endl;
return 0;
}
第K大数迭代版
这个算法是快速排序思想在查找问题上的经典应用,在实际工程中非常高效,是C++标准库std::nth_element函数的实现原理。
int quickSelectIterative(vector<int>& nums, int k) {
int left = 0, right = nums.size() - 1;
srand(time(0));
while (true) {
if (left == right) return nums[left];
// 随机分区
int random_index = left + rand() % (right - left + 1);
swap(nums[left], nums[random_index]);
int pivot = nums[left];
int i = left + 1, j = right;
while (i <= j) {
if (nums[i] >= pivot) i++;
else if (nums[j] < pivot) j--;
else swap(nums[i++], nums[j--]);
}
swap(nums[left], nums[j]);
int cnt = j - left; // 大于基准值的元素个数
if (k <= cnt) {
right = j - 1;
} else if (k == cnt + 1) {
return nums[j];
} else {
left = j + 1;
k -= (cnt + 1);
}
}
}
1 条评论
-
Luftmensch_zcx 404 Not Found LV 7 @ 2026-1-24 20:39:51抢沙发
- 1
