快速排序中的算法艺术

先给出个人认为在众多由不同的划分过程导致的各种快排算法中最高效简洁的算法:

void Qsort(int *A,int x,int y)
{
	if(x>=y) return;
	int p=x,q=y,m=A[x];
	do
	{
		while(A[p]<m) p++;
		while(A[q]>m) q--;
		if(p<=q) swap(&A[p++],&A[q--]);
	}while(p<q);
	Qsort(A,x,q);
	Qsort(A,p,y);
}


其次,给出这个算法的分析:

void Qsort(int *A,int x,int y)
{
	if(x>=y) return;
    int p=x,q=y,m=A[x];
    do{
         while(A[p]<m) p++;//在左边找到不小于m的元素 
         while(A[q]>m) q--;//在右边找到不大于m的元素 
         if(p<=q)//在自加自减之前,使左边A[p]不大于m,右边A[q]不小于m。
         {
         	swap(&A[p++],&A[q--]);//考虑在这一步之后,p>q的情形。则在自加自减之前,有两种情况,1)q-p=1,则退出时,p-q=1,也即pq换成了qp的顺序,此时,[q+1,y]中的元素一定不小于m,[x,p-1]一定不大于m,此时再对而p=q+1,q=p-1,所以此时再对[x,q],[p,y]排序即可 
         	//print(A,n);//2)在自加自减之前,p==q,显然A[p]=A[q]=m,之后的顺序是qop,也即q与p隔着一个位置,此时,[x,q]的元素均不大于m,[p,y]中的元素均不小于m 
         }//合并一下,即对[x,q],[p,y]分别排序即可 
    }while(p<q);
    //printf("p=%d q=%d\n",p,q);
    Qsort(A,x,q);
    Qsort(A,p,y);
}


如果,你觉得上面的算法难以理解划分过程的细节,如什么时候p<q,为什么A[p]<m,而不是A[p]<=m,试试理解这个,我认为这个在理解上是最简单的:

void qsort(int *A,int x,int y)//[x,y]
{
	if(x>=y) return;
	int p=x,q=y,m=A[x];
 	for(;;)
	{
	    while(A[q]>m) q--;//找到右边第一个不大于m的元素 
	    if(q==p) break;
		swap(&A[p++],&A[q]);//把左边当前元素与右边不大于m的元素交换,保证左边当前元素不大于m 
		while(A[p]<m) p++;//在左边找到不小于m的元素,在第一轮的检查中,A[q]此时为m,最极端情况是在p==q时,一定会终止循环 
		if(p==q) break;//此时终止循环,左边的元素都不大于m,右边的元素都不小于m,中间的元素为m 
		swap(&A[p],&A[q--]);//把m移到左边p处,运行后,原来q所在处的元素一定大于等于m	
	}
	qsort(A,x,p-1);//对左边不大于m的所有元素排序 
	qsort(A,q+1,y);//对右边不小于m的所有元素排序 
}


以下算法也容易理解,而且不需要swap函数:

void Qsort(int *A,int x,int y)
{
     if(x>=y) return;//递归边界
     int p=x,q=y,m=A[x];//把A[x]设为标兵,同时把此位置看做空位 
     do 
     {
        while(p<q && A[q]>=m)//找到右侧第一个小于m的元素 
           q--;
        if(p<q) A[p++]=A[q];//移到空位,此时空位位置上的元素小于m,,加入判断条件(p<q)是因为要确保上一循环语句是因为找到元素而退出的 
        while(p<q && A[p]<=m)//找到左侧第一个大于m的元素 
           p++;
        if(p<q) A[q--]=A[p];//将找到的大于m的元素移到空位,加入判断条件(p<q)是因为要确保上一循环语句是因为找到元素而退出的 
     }while(p<q);//每次对p,q的值仅仅加1或减1,所以最后必定是p==q而退出的 
     A[p]=m;//放回空位 
     Qsort(A,x,p-1);
     Qsort(A,p+1,y);
}


给出其中一个完整测试程序:

#include<stdio.h>
#include<string.h>
#include<time.h>

const int maxn=5000000;

void swap(int *a,int *b)
{
	int t=*a;*a=*b;*b=t;
}

void qsort(int *A,int x,int y)//[x,y]
{
	if(x>=y) return;
	int p=x,q=y,m=A[x];
 	for(;;)
	{
	    while(A[q]>m) q--;//找到右边第一个不大于m的元素 
	    if(q==p) break;
		swap(&A[p++],&A[q]);//把左边当前元素与右边不大于m的元素交换,保证左边当前元素不大于m 
		while(A[p]<m) p++;//在左边找到不小于m的元素,在第一轮的检查中,A[q]此时为m,最极端情况是在p==q时,一定会终止循环 
		if(p==q) break;//此时终止循环,左边的元素都不大于m,右边的元素都不小于m,中间的元素为m 
		swap(&A[p],&A[q--]);//把m移到左边p处,运行后,原来q所在处的元素一定大于等于m	
	}
	qsort(A,x,p-1);//对左边不大于m的所有元素排序 
	qsort(A,q+1,y);//对右边不小于m的所有元素排序 
}

int A[maxn];

void print(int *A,int n)
{
	printf("%d",A[0]);
	for(int i=1;i<n;i++)
		printf(" %d",A[i]);	
	printf("\n");
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&A[i]);
	//print(A,n);
	qsort(A,0,n-1);
	print(A,n);
	//printf("Time used=%.4lf\n",(double)clock()/CLOCKS_PER_SEC);
    return 0;
}


测试样例:

10
-70 -94 231 -404 -318 -203 99 99 -383 175


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值