快速排序
-
确定分界点x:
方法:
- q[l] //左端点
- q[r] //右端点
- q[(l+r)/2] //中点
- q[随便] //任意
2.调整区间:
把<=x的和>=x的分开(x随意,放两边都可以)
暴力实现:
int a[],int b[]; //a装<=x,b装>=x
memset(a,0x3f3f3f3f,sizeof(a));
memset(b,0x3f3f3f3f,sizeof(b));
for(int i=l;i<=r;i++)
{
if(q[i]<=q[x]) a[i]=q[i];
else b[i]=q[i];
}//先分类
while(a[i]!=0x3f3f3f3f) lena++;
while(b[i]!=0x3f3f3f3f) lenb++;
for(int i=1;i<=lena;i++) q[i]=a[i];
for(int i=lena+1;i<=lenb;i++) q[i]=b[i];
//再把a[]和b[]放回q[]里去
优美实现:
用两个指针i,j分别从两端向x的方向移动
当i的其中一个位置>=x时,将i停止移动,开始移动j
当j的其中一个位置<=x时,将j停止移动,将两个值交换
然后继续移动i,重复......直到i与j都到达x处
int i=l;//等于左端点
int j=r;//等于右端点
while(q[i]<=q[x]) i++;//如果i的其中一个位置>=x时,将i停止移动
while(q[j]>=q[x]) j--;当j的其中一个位置<=x时,将j停止移动
swap(q[i],q[j]);//将两个值交换
3.分别处理左右两端(递归)
只用把左右两边分别排好序了,又因为左区间的最大值小于右区间的最小值,所以两边就排好序了。
Ac Code
//运用优美实现完成的代码
#include <iostream>
using namespace std;
const int N=1e6+10;
int n,q[N];
void qsort(int q[],int l,int r)
{
if(l>=r) return ;
//如果两个指针重合就完成了
int x=q[(l+r)/2];//其实在哪都没所谓
int i=l-1,j=r+1;
//因为下面的是无论三七二十一都将i,j移动一位,再判断到没到,所以要在边界的两端前一位开始
while(i<j)
{
do i++; while(q[i]<x);//找到第一个不符合规则的点
do j--; while(q[j]>x);//找到第一个不符合规则的点
if(i<j) swap(q[i],q[j]);//交换它们的值
}
qsort(q,l,j);//左半序列
qsort(q,j+1,r);//右半序列
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
//输入
qsort(q,0,n-1);
//排序
for(int i=0;i<n;i++) printf("%d ",q[i]);
//输出
return 0;
}
为什么先移动再判断就能消除指针所指元素等于pivot从而进入无限循环的问题?
你好作者,我没看过基础课的视频。想请教一下是如何想到先移动再进行指针移动这一步的?