计蒜客T1746 - 快速排序 - 快排模板题 - 递归写法
时间复杂度
平均情况: \(Ο(nlogn)\)
最坏状况下则需要 \(Ο(n^2)\) 次比较
AC代码(以左边为基准)
#include<iostream>
#include<string>
#include<cmath>
#include<map>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
int a[100010],n;
void quicksort(int L, int R)
{
if(L>=R) return;
int i=L,j=R; // a[L]中存的就是基准数
while(i!=j)
{
//要先从右边开始找(不能交换顺序)
// (最后交换基准时换过去的数要保证比基准小,因为基准选取数组第一个数,在小数堆中)
while(a[j]>=a[L]&&i<j) j--; // 大的放右
while(a[i]<=a[L]&&i<j) i++; //再找右边的 // 小的放左
if(i<j) swap(a[i],a[j]);
}
swap(a[L],a[i]); // 将基准数归位
quicksort(L,i-1); // 递归继续处理左边的
quicksort(i+1,R); // 递归继续处理右边的
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
quicksort(0,n-1);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
cout<<endl;
return 0;
}
优化过的快排AC代码
这个是以最右边为基准点。
优化:基准点随机选择。
#include<iostream>
#include<string>
#include<cmath>
#include<map>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
int a[100010],n;
void quicksort(int L,int R)
{
if(L>=R) return;
int p=rand()%(R-L+1)+L; //p就是[L,R)范围内随机生成的基准数下标 (随机下标)
// 也可以p=L+(R-L)/2; // 或p=(L+R)/2(中间元素下标)
swap(a[p],a[R]);// 把最后一个数a[R]变成基准数
int i=L,j=R,x=a[R]; // x是基准数 最右边那个元素定为基准数
while(i<j)
{
while(a[i]<=x&&i<j) i++; // 小的放左
while(a[j]>=x&&i<j) j--; // 大的放右
if(i<j) swap(a[i],a[j]);
}
//结束while会出一个新的基准数a[j],j是基准数下标
//***这个时候i肯定>=j 所以if(i>j)这个条件写不写都ok
swap(a[j],a[R]); // 将基准数归位
quicksort(L,i-1); // 递归继续处理左边的
quicksort(i+1,R); // 递归继续处理右边的
}
int main()
{
srand(time(0)); //srand(time(NULL));
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
quicksort(0,n-1);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
cout<<endl;
return 0;
}
优化过的快排代码注意问题
-
为什么j不等于R-1,要等于R?
- 把这两组数据分别代进去走一遍:1 2 或 2 1
-
进入while的时候为什么要先让i往右走再让j往左走,而不是先让j先往左i再往右?
- 把这组数据代入
1 7 8 5
我们会发现,如果先让j先走的话,j和i之后会同时走到数字1这个位置,当while出去的时候,会把1和5进行交换,这样子小的数字就跑到基准数的位置上去了,从而造成错误。
- 把这组数据代入