电脑生活派
柔彩主题三 · 更轻盈的阅读体验

快速排序和归并排序哪个快(详细解析)

发布时间:2025-12-15 04:19:44 阅读:193 次

在处理数据库中的大量记录时,排序算法的效率直接影响查询响应速度。比如你运营一个电商平台,用户按销量排序商品,后台需要快速返回结果。这时候,工程师常在快速排序和归并排序之间纠结:到底谁更快?

平均情况下的表现

从理论上看,快速排序的平均时间复杂度是 O(n log n),归并排序也是 O(n log n)。但实际运行中,快速排序通常更胜一筹。因为它原地排序,不需要额外的存储空间,缓存命中率高,交换操作更少。

举个例子,你在写一个订单统计脚本,对十万条订单按金额排序。用快速排序可能耗时 12 毫秒,而归并排序因为要频繁分配临时数组,可能跑到 18 毫秒。虽然差距不大,但在高频调用场景下,积少成多。

最坏情况谁更扛得住

快速排序的软肋是极端情况。如果数据已经基本有序,而你又恰好选了个糟糕的基准点(pivot),它会退化到 O(n²)。就像你整理收件箱,按时间排序时数据本就有序,快排反而慢得像冒泡。

而归并排序不管数据长什么样,都能稳定在 O(n log n)。它的逻辑简单粗暴:拆到单个元素,再两两合并。这种“稳”在数据库索引构建这类关键任务中很吃香。

代码实现对比

下面是两种排序的简化实现:

void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = (low - 1);

    for (int j = low; j <= high - 1; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]);
    return (i + 1);
}
void mergeSort(int arr[], int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}

void merge(int arr[], int l, int m, int r) {
    // 合并两个有序子数组
    int i, j, k;
    int n1 = m - l + 1;
    int n2 = r - m;

    int L[n1], R[n2];

    for (i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];

    i = 0; j = 0; k = l;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }
}

可以看到,归并排序需要额外数组空间,代码逻辑也更繁琐。而快排的递归结构更简洁,适合手写调试。

数据库系统里的选择

现代数据库如 MySQL 或 PostgreSQL,并不会直接拿原始快排处理 ORDER BY。它们用的是优化版—— introsort(内省排序),开始用快排,一旦发现递归过深就切换到堆排序,兼顾速度与稳定性。

如果你在做报表导出功能,数据量小且要求稳定,归并排序更安心;如果是实时查询排序,快排或其变种通常是首选。