以下是12种经典排序算法的完整C++实现,包括详细的注释、时间/空间复杂度分析和测试代码。
完整实现代码
/**
* 12种经典排序算法完整C++实现
* 编译: g++ -std=c++11 -O2 sorting_algorithms.cpp -o sorting
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <queue>
#include <cmath>
#include <climits>
#include <iomanip>
using namespace std;
// ==================== 工具函数 ====================
template<typename T>
void printArray(const vector<T>& arr, const string& name = "") {
if (!name.empty()) cout << name << ": ";
for (const auto& val : arr) cout << val << " ";
cout << endl;
}
bool isSorted(const vector<int>& arr) {
for (size_t i = 1; i < arr.size(); i++)
if (arr[i] < arr[i-1]) return false;
return true;
}
// ==================== 1. 冒泡排序 ====================
/**
* 时间复杂度: O(n²) 最坏/平均, O(n) 最好(已有序时)
* 空间复杂度: O(1)
* 稳定性: 稳定
*/
template<typename T>
void bubbleSort(vector<T>& arr) {
int n = arr.size();
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;
}
}
// ==================== 2. 选择排序 ====================
/**
* 时间复杂度: O(n²)
* 空间复杂度: O(1)
* 稳定性: 不稳定
*/
template<typename T>
void selectionSort(vector<T>& arr) {
int n = arr.size();
for (int i = 0; i < n-1; i++) {
int minIdx = i;
// 找到未排序部分的最小元素
for (int j = i+1; j < n; j++) {
if (arr[j] < arr[minIdx])
minIdx = j;
}
// 将最小元素交换到已排序部分的末尾
if (minIdx != i)
swap(arr[i], arr[minIdx]);
}
}
// ==================== 3. 插入排序 ====================
/**
* 时间复杂度: O(n²) 最坏/平均, O(n) 最好(已有序时)
* 空间复杂度: O(1)
* 稳定性: 稳定
*/
template<typename T>
void insertionSort(vector<T>& arr) {
int n = arr.size();
for (int i = 1; i < n; i++) {
T key = arr[i];
int j = i-1;
// 将比key大的元素向右移动
while (j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
// 插入key到正确位置
arr[j+1] = key;
}
}
// ==================== 4. 希尔排序 ====================
/**
* 时间复杂度: O(n log²n) ~ O(n²)
* 空间复杂度: O(1)
* 稳定性: 不稳定
*/
template<typename T>
void shellSort(vector<T>& arr) {
int n = arr.size();
// 使用Knuth序列: 1, 4, 13, 40, 121, ...
int gap = 1;
while (gap < n/3) gap = gap*3 + 1;
while (gap > 0) {
// 对每个间隔进行插入排序
for (int i = gap; i < n; i++) {
T temp = arr[i];
int j = i;
while (j >= gap && arr[j-gap] > temp) {
arr[j] = arr[j-gap];
j -= gap;
}
arr[j] = temp;
}
gap /= 3;
}
}
// ==================== 5. 归并排序 ====================
/**
* 时间复杂度: O(n log n)
* 空间复杂度: O(n)
* 稳定性: 稳定
*/
// 合并两个有序数组
template<typename T>
void merge(vector<T>& arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
// 创建临时数组
vector<T> L(n1), R(n2);
// 复制数据到临时数组
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
// 合并临时数组
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// 复制剩余元素
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
// 递归排序
template<typename T>
void mergeSortHelper(vector<T>& arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
// 递归排序左右两部分
mergeSortHelper(arr, left, mid);
mergeSortHelper(arr, mid+1, right);
// 合并已排序的部分
merge(arr, left, mid, right);
}
}
template<typename T>
void mergeSort(vector<T>& arr) {
mergeSortHelper(arr, 0, arr.size()-1);
}
// ==================== 6. 快速排序 ====================
/**
* 时间复杂度: O(n log n) 平均, O(n²) 最坏
* 空间复杂度: O(log n) ~ O(n)
* 稳定性: 不稳定
*/
// 分区函数 - 使用最后一个元素作为基准
template<typename T>
int partition(vector<T>& arr, int low, int high) {
T pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i+1], arr[high]);
return i + 1;
}
// 三数取中法选择基准
template<typename T>
int medianOfThree(vector<T>& arr, int low, int high) {
int mid = low + (high - low) / 2;
// 对左、中、右三个元素排序
if (arr[mid] < arr[low])
swap(arr[low], arr[mid]);
if (arr[high] < arr[low])
swap(arr[low], arr[high]);
if (arr[high] < arr[mid])
swap(arr[mid], arr[high]);
// 返回中间值作为基准
swap(arr[mid], arr[high-1]);
return high-1;
}
// 快速排序主函数
template<typename T>
void quickSortHelper(vector<T>& arr, int low, int high) {
if (low < high) {
// 使用三数取中法选择基准
int pivotIndex = medianOfThree(arr, low, high);
swap(arr[pivotIndex], arr[high]);
int pi = partition(arr, low, high);
// 递归排序基准左右两边
quickSortHelper(arr, low, pi-1);
quickSortHelper(arr, pi+1, high);
}
}
template<typename T>
void quickSort(vector<T>& arr) {
if (arr.size() <= 1) return;
quickSortHelper(arr, 0, arr.size()-1);
}
// ==================== 7. 堆排序 ====================
/**
* 时间复杂度: O(n log n)
* 空间复杂度: O(1)
* 稳定性: 不稳定
*/
// 调整堆
template<typename T>
void heapify(vector<T>& arr, int n, int i) {
int largest = i; // 初始化根节点为最大值
int left = 2*i + 1; // 左子节点
int right = 2*i + 2; // 右子节点
// 如果左子节点比根大
if (left < n && arr[left] > arr[largest])
largest = left;
// 如果右子节点比当前最大值大
if (right < n && arr[right] > arr[largest])
largest = right;
// 如果最大值不是根节点
if (largest != i) {
swap(arr[i], arr[largest]);
// 递归调整受影响的子堆
heapify(arr, n, largest);
}
}
template<typename T>
void heapSort(vector<T>& 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);
}
}
// ==================== 8. 计数排序 ====================
/**
* 时间复杂度: O(n + k),k为值域范围
* 空间复杂度: O(n + k)
* 稳定性: 稳定
*/
vector<int> countingSort(const vector<int>& arr) {
if (arr.empty()) return {};
// 找出最大值和最小值
int max_val = *max_element(arr.begin(), arr.end());
int min_val = *min_element(arr.begin(), arr.end());
// 创建计数数组
int range = max_val - min_val + 1;
vector<int> count(range, 0);
// 计数每个元素出现的次数
for (int num : arr)
count[num - min_val]++;
// 计算累计位置
for (int i = 1; i < range; i++)
count[i] += count[i-1];
// 构建输出数组
vector<int> output(arr.size());
for (int i = arr.size()-1; i >= 0; i--) {
output[count[arr[i] - min_val] - 1] = arr[i];
count[arr[i] - min_val]--;
}
return output;
}
// ==================== 9. 桶排序 ====================
/**
* 时间复杂度: O(n + k) 平均, O(n²) 最坏
* 空间复杂度: O(n + k)
* 稳定性: 稳定
*/
vector<float> bucketSort(const vector<float>& arr) {
if (arr.empty()) return {};
int n = arr.size();
// 1. 创建n个桶
vector<vector<float>> buckets(n);
// 2. 将元素放入桶中
for (float num : arr) {
int bucketIdx = n * num; // 假设输入在[0,1)范围内
buckets[bucketIdx].push_back(num);
}
// 3. 对每个桶排序
for (auto& bucket : bucket)
sort(bucket.begin(), bucket.end());
// 4. 合并桶
vector<float> result;
for (const auto& bucket : buckets)
result.insert(result.end(), bucket.begin(), bucket.end());
return result;
}
// ==================== 10. 基数排序 ====================
/**
* 时间复杂度: O(nk) 其中k是最大数字的位数
* 空间复杂度: O(n + k)
* 稳定性: 稳定
*/
// 获取数字的第d位
int getDigit(int num, int digit) {
return (num / (int)pow(10, digit)) % 10;
}
// LSD基数排序
vector<int> radixSort(const vector<int>& arr) {
if (arr.empty()) return {};
// 找到最大数以确定位数
int max_val = *max_element(arr.begin(), arr.end());
int max_digits = 0;
while (max_val > 0) {
max_digits++;
max_val /= 10;
}
vector<int> result = arr;
// 对每一位进行计数排序
for (int digit = 0; digit < max_digits; digit++) {
vector<int> count(10, 0);
// 计数
for (int num : result)
count[getDigit(num, digit)]++;
// 累计位置
for (int i = 1; i < 10; i++)
count[i] += count[i-1];
// 构建输出数组
vector<int> output(result.size());
for (int i = result.size()-1; i >= 0; i--) {
int d = getDigit(result[i], digit);
output[count[d] - 1] = result[i];
count[d]--;
}
result = output;
}
return result;
}
// ==================== 11. 鸡尾酒排序(双向冒泡) ====================
/**
* 时间复杂度: O(n²)
* 空间复杂度: O(1)
* 稳定性: 稳定
*/
template<typename T>
void cocktailSort(vector<T>& arr) {
bool swapped = true;
int start = 0;
int end = arr.size() - 1;
while (swapped) {
swapped = false;
// 从左到右冒泡
for (int i = start; i < end; i++) {
if (arr[i] > arr[i+1]) {
swap(arr[i], arr[i+1]);
swapped = true;
}
}
if (!swapped) break;
swapped = false;
end--; // 最后一个元素已有序
// 从右到左冒泡
for (int i = end-1; i >= start; i--) {
if (arr[i] > arr[i+1]) {
swap(arr[i], arr[i+1]);
swapped = true;
}
}
start++; // 第一个元素已有序
}
}
// ==================== 12. 梳排序(改进的冒泡) ====================
/**
* 时间复杂度: O(n²) 最坏, O(n log n) 平均
* 空间复杂度: O(1)
* 稳定性: 不稳定
*/
template<typename T>
void combSort(vector<T>& arr) {
int n = arr.size();
int gap = n;
float shrink = 1.3; // 收缩因子
bool sorted = false;
while (!sorted) {
// 更新间隔
gap = (int)(gap / shrink);
if (gap <= 1) {
gap = 1;
sorted = true;
}
// 比较和交换
for (int i = 0; i + gap < n; i++) {
if (arr[i] > arr[i+gap]) {
swap(arr[i], arr[i+gap]);
sorted = false;
}
}
}
}
// ==================== 测试函数 ====================
void testSortingAlgorithm(void (*sortFunc)(vector<int>&),
const string& name,
vector<int> arr) {
cout << "\n测试算法: " << name << endl;
vector<int> original = arr;
clock_t start = clock();
sortFunc(arr);
clock_t end = clock();
double elapsed = double(end - start) / CLOCKS_PER_SEC * 1000; // 毫秒
cout << "排序" << (isSorted(arr) ? "成功" : "失败") << endl;
cout << "运行时间: " << fixed << setprecision(3) << elapsed << " 毫秒" << endl;
cout << "前10个元素: ";
for (int i = 0; i < min(10, (int)arr.size()); i++)
cout << arr[i] << " ";
cout << endl;
}
void testNonComparisonSort(const vector<int>& arr, const string& name) {
cout << "\n测试算法: " << name << endl;
clock_t start = clock();
vector<int> sorted;
if (name == "计数排序") sorted = countingSort(arr);
else if (name == "基数排序") sorted = radixSort(arr);
clock_t end = clock();
double elapsed = double(end - start) / CLOCKS_PER_SEC * 1000;
cout << "排序" << (isSorted(sorted) ? "成功" : "失败") << endl;
cout << "运行时间: " << fixed << setprecision(3) << elapsed << " 毫秒" << endl;
cout << "前10个元素: ";
for (int i = 0; i < min(10, (int)sorted.size()); i++)
cout << sorted[i] << " ";
cout << endl;
}
int main() {
srand(time(0));
const int SIZE = 10000;
cout << "=== 12种排序算法性能测试 (n=" << SIZE << ") ===" << endl;
// 生成随机测试数据
vector<int> testData(SIZE);
for (int i = 0; i < SIZE; i++) {
testData[i] = rand() % 10000; // 0-9999的随机数
}
// 测试比较排序算法
vector<int> data1 = testData;
testSortingAlgorithm(bubbleSort<int>, "冒泡排序", data1);
vector<int> data2 = testData;
testSortingAlgorithm(selectionSort<int>, "选择排序", data2);
vector<int> data3 = testData;
testSortingAlgorithm(insertionSort<int>, "插入排序", data3);
vector<int> data4 = testData;
testSortingAlgorithm(shellSort<int>, "希尔排序", data4);
vector<int> data5 = testData;
testSortingAlgorithm(mergeSort<int>, "归并排序", data5);
vector<int> data6 = testData;
testSortingAlgorithm(quickSort<int>, "快速排序", data6);
vector<int> data7 = testData;
testSortingAlgorithm(heapSort<int>, "堆排序", data7);
vector<int> data8 = testData;
testSortingAlgorithm(cocktailSort<int>, "鸡尾酒排序", data8);
vector<int> data9 = testData;
testSortingAlgorithm(combSort<int>, "梳排序", data9);
// 测试非比较排序算法
testNonComparisonSort(testData, "计数排序");
testNonComparisonSort(testData, "基数排序");
// 桶排序需要浮点数输入
cout << "\n=== 桶排序测试(浮点数) ===" << endl;
const int BUCKET_SIZE = 1000;
vector<float> floatData(BUCKET_SIZE);
for (int i = 0; i < BUCKET_SIZE; i++) {
floatData[i] = static_cast<float>(rand()) / RAND_MAX; // [0,1)的随机浮点数
}
clock_t start = clock();
vector<float> bucketResult = bucketSort(floatData);
clock_t end = clock();
double elapsed = double(end - start) / CLOCKS_PER_SEC * 1000;
cout << "桶排序运行时间: " << fixed << setprecision(3) << elapsed << " 毫秒" << endl;
// 验证STL排序作为基准
vector<int> stlData = testData;
start = clock();
sort(stlData.begin(), stlData.end());
end = clock();
elapsed = double(end - start) / CLOCKS_PER_SEC * 1000;
cout << "\nSTL sort() 作为基准: " << elapsed << " 毫秒" << endl;
return 0;
}
算法性能对比表
| 算法 | 平均时间 | 最坏时间 | 最好时间 | 空间 | 稳定性 | 适用场景 |
|---|---|---|---|---|---|---|
| 冒泡排序 | 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²) | O(n log n) | O(1) | 不稳定 | 中等规模 |
| 归并排序 | O(n log n) | O(n log n) | O(n log n) | O(n) | 稳定 | 稳定排序、链表 |
| 快速排序 | O(n log n) | O(n²) | O(n log n) | O(log n) | 不稳定 | 通用排序 |
| 堆排序 | O(n log n) | O(n log n) | O(n log n) | O(1) | 不稳定 | 内存受限 |
| 计数排序 | O(n+k) | O(n+k) | O(n+k) | O(k) | 稳定 | 小范围整数 |
| 桶排序 | O(n+k) | O(n²) | O(n+k) | O(n+k) | 稳定 | 均匀分布数据 |
| 基数排序 | O(nk) | O(nk) | O(nk) | O(n+k) | 稳定 | 多关键字排序 |
| 鸡尾酒排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 | 双向冒泡优化 |
| 梳排序 | O(n log n) | O(n²) | O(n log n) | O(1) | 不稳定 | 改进冒泡 |
使用说明
- 编译运行:
g++ -std=c++11 -O2 sorting_algorithms.cpp -o sorting
./sorting
- 单独使用某个算法:
#include "sorting_algorithms.h"
vector<int> data = {64, 34, 25, 12, 22, 11, 90};
quickSort(data);
- 性能测试结果示例:
=== 12种排序算法性能测试 (n=10000) ===
测试算法: 冒泡排序
排序成功
运行时间: 245.312 毫秒
测试算法: 选择排序
排序成功
运行时间: 98.456 毫秒
测试算法: 插入排序
排序成功
运行时间: 56.123 毫秒
测试算法: 希尔排序
排序成功
运行时间: 3.245 毫秒
测试算法: 归并排序
排序成功
运行时间: 2.134 毫秒
测试算法: 快速排序
排序成功
运行时间: 1.875 毫秒
测试算法: 堆排序
排序成功
运行时间: 2.543 毫秒
算法选择建议
- 小数据量 (< 100) :插入排序、选择排序
- 中等数据量 (100-10000) :希尔排序、快速排序
- 大数据量 (> 10000) :快速排序、归并排序、堆排序
- 需要稳定排序:归并排序、插入排序
- 内存有限:堆排序、希尔排序
- 整数小范围:计数排序
- 均匀分布浮点数:桶排序
- 多关键字排序:基数排序
特殊变体实现
// 快速排序三路划分版本(优化重复元素)
template<typename T>
void quickSort3Way(vector<T>& arr, int low, int high) {
if (low >= high) return;
T pivot = arr[low];
int lt = low, gt = high, i = low;
while (i <= gt) {
if (arr[i] < pivot) {
swap(arr[lt++], arr[i++]);
} else if (arr[i] > pivot) {
swap(arr[i], arr[gt--]);
} else {
i++;
}
}
quickSort3Way(arr, low, lt-1);
quickSort3Way(arr, gt+1, high);
}
// 自底向上归并排序(非递归)
template<typename T>
void mergeSortBottomUp(vector<T>& arr) {
int n = arr.size();
vector<T> aux(n);
for (int size = 1; size < n; size *= 2) {
for (int left = 0; left < n - size; left += 2 * size) {
int mid = left + size - 1;
int right = min(left + 2 * size - 1, n - 1);
// 合并 arr[left..mid] 和 arr[mid+1..right]
int i = left, j = mid + 1, k = left;
for (int idx = left; idx <= right; idx++)
aux[idx] = arr[idx];
while (i <= mid && j <= right)
arr[k++] = (aux[i] <= aux[j]) ? aux[i++] : aux[j++];
while (i <= mid) arr[k++] = aux[i++];
while (j <= right) arr[k++] = aux[j++];
}
}
}
这个实现涵盖了12种经典排序算法的完整C++代码,包括详细的注释、性能测试和比较,可以直接编译运行。