起因很简单,就是在acWing里做一道快排模板,但是提交了代码就是TLE。于是好奇心大发仔细对比了一下自己写的和课程中展示的代码。
以下是1.0版:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n;
int q[N];
void quick_sort(int q[],int l,int r) {
if (l >= r) return;
int x=q[l],i=l-1,j=r+1;
while(i<j) {
do i++; while(q[i]<x);
do j--; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
quick_sort(q,l,i-1);
quick_sort(q,i,r);
}
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++) {
scanf("%d",&q[i]);
}
quick_sort(q,0,n-1);
for(int i=0;i<n;i++) {
printf("%d ", q[i]);
}
return 0;
}
大不解,遂问ds问题所在。ds回答如下:
TLE 的原因: 最坏时间复杂度 O(n²) 你的代码选择 q[l](第一个元素)作为 pivot,如果输入是已排序或接近排序的数组,会导致递归深度变成 O(n),时间复杂度退化为 O(n²)。 咱们不妨举一个简单的例子看看,为什么左边界会在一定情况下超时 如果数组已经有序(或逆序): 比如 [1, 2, 3, 4, 5],每次选 pivot = 第一个元素: 第一次:pivot = 1 → 左边 [],右边 [2, 3, 4, 5](没分割)。 第二次:pivot = 2 → 左边 [],右边 [3, 4, 5](又没分割)。 ... 每次只减少 1 个元素,递归深度变成 N 层,每层处理 N 个元素 → O(N²)!
所以,在快速排序的时候,我们通常有四种选择基准的方法:左端,右端,中间位置,随机位置。
更改中间位置为基准后成功ac,代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n;
int q[N];
void quick_sort(int q[],int l,int r) {
if (l >= r) return;
int x=q[(l+r+1)/2],i=l-1,j=r+1;
while(i<j) {
do i++; while(q[i]<x);
do j--; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
quick_sort(q,l,i-1);
quick_sort(q,i,r);
}
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++) {
scanf("%d",&q[i]);
}
quick_sort(q,0,n-1);
for(int i=0;i<n;i++) {
printf("%d ", q[i]);
}
return 0;
}
最后,ds给出了一个很幽默的解决方法:随机位置
(但是总觉得有点~~不太靠谱啊

京公网安备 11010502036488号