12种经典排序算法完整C++实现

0 阅读11分钟

以下是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)不稳定改进冒泡

使用说明

  1. 编译运行:
g++ -std=c++11 -O2 sorting_algorithms.cpp -o sorting
./sorting
  1. 单独使用某个算法:
#include "sorting_algorithms.h"

vector<int> data = {64, 34, 25, 12, 22, 11, 90};
quickSort(data);
  1. 性能测试结果示例:
=== 12种排序算法性能测试 (n=10000) ===

测试算法: 冒泡排序
排序成功
运行时间: 245.312 毫秒

测试算法: 选择排序
排序成功
运行时间: 98.456 毫秒

测试算法: 插入排序
排序成功
运行时间: 56.123 毫秒

测试算法: 希尔排序
排序成功
运行时间: 3.245 毫秒

测试算法: 归并排序
排序成功
运行时间: 2.134 毫秒

测试算法: 快速排序
排序成功
运行时间: 1.875 毫秒

测试算法: 堆排序
排序成功
运行时间: 2.543 毫秒

算法选择建议

  1. 小数据量 (< 100) :插入排序、选择排序
  2. 中等数据量 (100-10000) :希尔排序、快速排序
  3. 大数据量 (> 10000) :快速排序、归并排序、堆排序
  4. 需要稳定排序:归并排序、插入排序
  5. 内存有限:堆排序、希尔排序
  6. 整数小范围:计数排序
  7. 均匀分布浮点数:桶排序
  8. 多关键字排序:基数排序

特殊变体实现

// 快速排序三路划分版本(优化重复元素)
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++代码,包括详细的注释、性能测试和比较,可以直接编译运行。