基本思想:在当前的序列(k1,k2,···,kn)中任意选取一个元素,把该元素称为基准元素或支点,把小于等于基准元素的所有元素都移到基准元素的前面,把大于基准元素的所有元素都移到基准元素的后面,这样使得基准元素所处的位置恰好就是排序的最终位置,并且把当前参加排序的序列划分为前后两个子序列。其中,前面的子序列中的元素都小于等于基准元素,后面的子序列的元素都大于基准元素。接下来分别对这两个子序列重复上述的排列操作(如果子序列的长度大于1),直到使得所有元素都被移动到排序后他们应处的最终的位置上。
快速排序优势原因:快速排序方法之所以效率较高,是因为每一次元素的移动都是跳跃式的。因为每趟排序都要指定一个基准点,把小于等于基准元素的所有元素都移到基准元素的前面,把大于基准元素的所有元素都移到基准元素的后面,这样每次元素的移动就不会像冒泡排序那样只能在相邻元素之间进行,元素移动的间隔距离较大,因此总的比较和移动次数减少,排序的速度从而提高。
在排序的过程中,每次按照基准元素将原序列分为前后两个子序列的过程成为一次划分操作。一次划分操作如下:
假设原序列为:{5,7,4,2,11,10,6}。
首先设置两个变量i和j。i=1,指向元素5;j=7,指向元素6.设定基准元素i指向的元素5:
{5,7,4,2,11,10,6}
↑ ↑
i j
(1)反复执行i=i+1的操作,直到i指向的元素大于等于基准元素5,或者i指向序列尾部,即i=7为止。然后反复执行j=j-1的操作,直到j指向的元素小于等于基准元素5,或者j指向序列的首部,即j=1为止:
{5,7,4,2,11,10,6}
↑ ↑
i=2 j=4
(2)若此时i<j,则将i与j指向的元素进行交换:
{5,2,4,7,11,10,6}
↑ ↑
i=2 j=4
然后重复执行****(1)、(2)或(3)。执行完(2)后:
{5,2,4,7,11,10,6}
↑ ↑
j=3i=4
(3)若此时i>=j,则将基准元素与j指向的元素交换位置:
{4,2,5,7,11,10,6}
↑ ↑
j=3i=4
至此完成了原序列的第一次划分,接下来分别递归地对基准点5前后的子序列中长度大于1的子序列重复执行上述操作,直到整个序列排序结束。
系列的每一次划分操作都是按照:(1)→(2)→(1)···(2)→(1)→(3)→结束,这样的过程进行的。也就是说,只有当i>=j时才将本次划分的基准元素放置到它最终的位置上。
进行完序列的一次划分后,再对基准元素5前后的两个子序列分别重复上述的操作。对于每个子序列的操作又是一次划分的过程,每次划分元素的基准元素仍可设定为该子序列的第一个元素
快速排序的递归算法如下:
void sort(keytype k[],int s,int t)
{
int i,j;
if(s<t)
{
i=s;
j=t+1;
while(1)
{
do{
i++;//重复执行i++操作
}while(!(k[s]<=k[i]||i==t));//将i向序列尾部移动
do{
j--;//重复执行j--的操作
}while(!(k[s]>k[j]||j==s));//将j向序列首部移动
if(i<j)
swap(k[i],k[j]);//i与j所指元素进行交换
else
break;//找到基准元素所在位置,跳出循环
}
swap(k[s],k[j]);//交换基准元素与k[j]的位置,完成一次划分
sort(k,s,j-1);//递归排序基准元素前面的子序列
sort(k,j+1,t);//递归排序基准元素后面的子序列
}
}
该算法中,子算法swap(k1,k2)的功能是交换k1,k2的位置。
由于快速排序的算法特性的约束,快速排序一般适用于顺序表现行结构或数组序列的排序,并不适合于在链表结构上实现排序。
【实例】
编写一个C程序,实现数据序列{2,5,6,3,7,8,0,9,12,1}的快速排序,要求从大到小,并输出排序后的数列元素。
【分析】
前面介绍的快速排序算法只适用于序列的从小到大的排序,在这里要实现序列的从大到小的排序,因此上述算法要稍加修改。
#include<stdio.h>
void swap(int *a,int *b)//序列中元素的交换
{
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}
void sort(int k[],int s,int t)//快速排序
{
int i,j;
if(s<t)
{
i=s;
j=t+1;
while(1)
{
do{
i++;//重复执行i++操作
}while(!(k[s]>k[i]||i==t));//将i向序列尾部移动
do{
j--;//重复执行j--的操作
}while(!(k[s]<=k[j]||j==s));//将j向序列首部移动
if(i<j)
swap(&k[i],&k[j]);//i与j所指元素进行交换
else
break;//找到基准元素所在位置,跳出循环
}
swap(&k[s],&k[j]);//交换基准元素与k[j]的位置,完成一次划分
sort(k,s,j-1);//递归排序基准元素前面的子序列
sort(k,j+1,t);//递归排序基准元素后面的子序列
}
}
main()
{
int k[10]={2,5,6,3,7,8,0,9,12,1},i;
printf("原序列为:\n");
for(i=0;i<10;i++)//显示原序列中的元素
printf("%d ",k[i]);
sort(k,0,9);//快速排序
printf("\n排序后的序列为:\n");
for(i=0;i<10;i++)//显示排序后的结果
printf("%d ",k[i]);
return 0;
}
运行结果如图: