现附上经典源代码
#include<iostream>
using namespace std;
void kp(int a[],int l,int r)
{
if(l>=r)return;
int i=l;
int j=r;
int p=a[l];
while(i<j)
{
while(i<j&&a[j]>=p)j--;
while(i<j&&a[i]<=p)i++;
swap(a[i],a[j]);
}
swap(a[l],a[j]);
kp(a,l,j-1);
kp(a,j+1,r);
}
int main()
{
int n;
cin>>n;
int a[100005];
for(int i=0;i<=n-1;i++)
{
cin>>a[i];
}
kp(a,0,n-1);
for(int i=0;i<=n-1;i++)
{
cout<<a[i]<<' ';
}
return 0;
}
现在看来,快排就是基于pivot的一项操作之的递归,然后逐渐得到排序后的数组。
每次操作就是把第一个数作为基准(pivot),把它放到一个合适的位置,让前面的数比它小,后面的数比它大,就可以了。
也就是这一段:
while(i<j)
{
while(i<j&&a[j]>=p)j--;//从前面开始找,找到一个比pivot大的
while(i<j&&a[i]<=p)i++;//从后面开始找,找到一个比pivot小的
swap(a[i],a[j]);//把前面比pivot基准大的,与后面比pivot基准小的互换位置。
}
//当循环出来时,i和j相等了,也就是说在i=j这个位置上,前面的,和后面的都符合这个所谓“合适的位置”
swap(a[l],a[j]);
//然后这个时候我们把基准放在这个位置,就行了。
接下来就是递归的过程了
kp(a,l,j-1);
kp(a,j+1,r);
把i=j这个位置前面和后面都以相同的方法排序。
就做完了。
然后这个方法会被洛谷卡,因为当数据为1,2,3,4,5,6......n的时候,我们这个方法一次就移动了一次,退化为了一个O(n^2)复杂度的算法了。。。
所以,我偷了一波鸡,以中间的位置上的数为基准,就过了。
就像这样:
void kp2(int l,int r)
{
if(l>=r)return;
int ll=l;
int rr=r;
int tt=a[(l+r)/2];
while(ll<=rr)
{
while(tt<a[rr])
{
rr--;
}
while(tt>a[ll])
{
ll++;
}
if(ll<=rr)
{
swap(a[ll],a[rr]);
ll++;
rr--;
}
}
if(l<rr)kp2(l,rr);
if(r>ll)kp2(ll,r);
}
以前觉得吧,我排序用sort不就无敌了吗,学那些排序干啥?
现在觉得,知道一个排序的算法实现,思考一个算法的运作过程,才是最有意义的。
欢迎各位大佬指出我的问题。