排序算法


快速排序算法(递归)

好的,快速排序(Quick Sort)是一种高效的分治排序算法,平均时间复杂度为 O(n log n),最坏情况下(如数组已有序)为 O(n²),但通过优化策略(如随机化 pivot)可以避免最坏情况。以下是它的核心思想和步骤:


1. 核心思想

通过一趟排序将待排序列分割成独立的两部分,其中一部分的所有元素比另一部分小,然后递归地对这两部分排序,最终使整个序列有序。


2. 具体步骤

  1. 选择基准值(pivot)
    从数组中选择一个元素作为基准(通常选第一个、最后一个或随机元素)。

  2. 分区(Partition)

    • 将小于 pivot 的元素移到其左侧,大于 pivot 的元素移到右侧。
    • 最终 pivot 会位于其正确的位置(即排序后的最终位置)。
    • 分区完成后,数组被划分为两个子数组(左子数组 ≤ pivot,右子数组 > pivot)。
  3. 递归排序子数组
    对左右子数组重复上述过程,直到子数组长度为 1 或 0(已有序)。


3. 示例(以升序排序为例)

假设数组为 [3, 6, 8, 10, 1, 2, 1],选择最后一个元素 1 为 pivot:

  • 分区过程
    • 从左到右遍历,将 ≤ 1 的元素交换到左侧。
    • 最终 pivot 1 被交换到中间位置,数组变为 [1, 1, 2, 10, 8, 6, 3](pivot 的索引为 1)。
  • 递归
    • 左子数组 [1](已有序),右子数组 [2, 10, 8, 6, 3] 继续排序。

4. 代码实现(C++)

#include <iostream>
#include <vector>
using namespace std;

// 分区函数(核心)
int partition(vector<int>& arr, int low, int high) {
    int pivot = arr[high];  // 选择最后一个元素作为基准(可优化为随机选择)
    int i = low - 1;        // i 是小于 pivot 的区域的右边界

    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(arr[i], arr[j]);  // 将小于 pivot 的元素交换到左侧
        }
    }
    swap(arr[i + 1], arr[high]);   // 将 pivot 放到正确位置
    return i + 1;                  // 返回 pivot 的索引
}

// 递归排序函数
void quickSort(vector<int>& arr, int low, int high) {
    if (low < high) {
        int pivotIndex = partition(arr, low, high);  // 分区
        quickSort(arr, low, pivotIndex - 1);        // 递归排序左子数组
        quickSort(arr, pivotIndex + 1, high);        // 递归排序右子数组
    }
}

// 测试代码
int main() {
    vector<int> arr = {3, 6, 8, 10, 1, 2, 1};
    quickSort(arr, 0, arr.size() - 1);

    cout << "Sorted array: ";
    for (int num : arr) {
        cout << num << " ";
    }
    return 0;
}

关键点说明(C++ 特性相关)

  1. 分区优化

    • 上述代码选择最后一个元素作为 pivot,实际工程中可随机选择以避免最坏情况:
      int pivotIndex = low + rand() % (high - low + 1);
      swap(arr[pivotIndex], arr[high]);  // 将随机 pivot 交换到末尾
      
  2. 原地排序

    • 通过传递数组引用 vector<int>& arr 和下标范围 [low, high],避免拷贝开销,符合 C++ 高效特性。
  3. 时间复杂度

    • 平均 O(n log n),最坏 O(n²)(可通过随机化或三数取中法优化)。
  4. STL 对比

    • C++ STL 的 std::sort() 通常使用快速排序的优化混合版本(如内省排序 IntroSort)。

面试中可能的追问

  • 如何避免栈溢出?
    答:尾递归优化或改用迭代版本(用栈模拟递归)。
  • 为什么快速排序比归并排序更常用?
    答:快速排序的常数因子更小,且原地排序节省内存。

5. 关键点

  • 不稳定排序:相同元素的相对位置可能改变。
  • 优化策略
    • 随机选择 pivot 避免最坏情况。
    • 对小规模子数组改用插入排序(减少递归开销)。
  • 空间复杂度
    • 递归栈空间平均 O(log n),最坏 O(n)

6. 对比其他排序

  • 归并排序:稳定且始终 O(n log n),但需要额外空间。
  • 堆排序:无需额外空间,但缓存局部性较差。
posted @ 2025-04-03 12:10  guanyubo  阅读(30)  评论(0)    收藏  举报