快速排序是由冒泡排序改进而得的。在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序。如果能通过两个(不相邻)记录的依次交换,消除多个逆序,则会大大加快排序的速度。快速排序方法中的一次交换可能消除多个逆序。
[算法思想]在待排序的n个记录中任取一个记录(通常取第一个记录)作为枢轴(或支点),设其关键字为pivotkey。经过一趟排序后,把所有关键字小于pivotkey的记录交换到前面,把所有关键字大于pivotkey的记录交换到后面,结果将待排序记录分成两个子表,最后将枢轴放置在分界处的位置。然后,分别对左、右子表重复上述过程,直至每一子表只有一个子记录时,排序完成。又是分治的思想,分解,解决,合并。
其中,一趟快速排序的具体做法如下。
1)附设两个指针low和high,初始时分别指向表的下界和上界,设枢轴记录的关键字为pivotkey(第一趟时,low=1;high=L.length;)
2)从表的最右侧位置,依次向左搜索找到第一个关键字小于pivotkey的记录和枢轴记录交换。具体操作是:当low<high时,若high所指的关键字大于等于pivotkey,则向左移动指针high,(执行操作--high);否则将high所指记录与枢轴记录交换。
3)然后再从表的最左侧位置,依次向右搜索找到第一个关键字大于pivotkey的记录和枢轴记录交换。具体操作是:当low<high时,若low所指的关键字小于等于pivotkey,则向右移动指针low(执行操作++low);否则将low所指记录与枢轴记录交换。
4)重复步骤(2)和步骤(3),直到low与high相等为止。此时low或high的位置即为枢轴在此趟排序中的最终位置,原表被分成两个子表。
在上述过程中,记录的交换都是与枢轴之间发生,每次交换都要移动3次记录,可以先将枢轴记录暂存在r[0]的位置上,排序过程中只移动要与枢轴交换的记录,即只做r[low]或r[high]的单向移动,直至一趟排序记录结束后再将枢轴记录移至正确的位置上。
例 已知待排序记录的关键字序列为{49,38,65,97,76,13,27,49},请给出快速排序法进行排序的过程。
每一趟快速排序过程如图(a)所示,整个快速排序的过程如图(b)所示。[算法描述]
int Partition(int L[],int low ,int high)
{
/*对顺序表L中的子表r[low..high]进行一趟排序,返回枢轴位置*/
L[0]=L[low]; /*用子表的第一个记录做枢轴记录*/
int pivotkey=L[low]; /*枢轴记录关键字保存在pivotkey中*/
while(low < high) /*从表的两端交替地向中间扫描*/
{
while(low<high && L[high]>=pivotkey) --high;
L[low]=L[high];
while(low<high && L[low]<=pivotkey) ++low;
L[high]=L[low];
}
L[low]=L[0]; /*枢轴记录到位*/
return low;
}
void Qsort(int L[],int low,int high)
{
/*对顺序表L中的子序列L[low..high]做快速排序*/
if(low<high) /*长度大于1*/
{
int pivotloc=Partition(L,low,high); /*将L[low..high]一分为二,pivotloc是枢轴位置*/
Qsort(L,low,pivotloc-1); /*对左子表递归排序*/
Qsort(L,pivotloc+1,high); /*对右子表递归排序*/
}
}
void QuickSort(int L,int n)
{
Qsort(L,1,n);
}
[算法分析]
1)时间复杂度
最好O(nlog2n);最坏O(n^2);平均O(nlog2n);
2)空间复杂度
快速排序是递归的,执行时需要一个栈来存放相应的数据。最大递归调用次数与递归树的深度一致,所以最好情况下的空间复杂度为O(log2n)最坏情况下为O(n).
[完整代码]#include<iostream>
using namespace std;
int Partition(int L[],int low ,int high)
{
/*对顺序表L中的子表r[low..high]进行一趟排序,返回枢轴位置*/
L[0]=L[low]; /*用子表的第一个记录做枢轴记录*/
int pivotkey=L[low]; /*枢轴记录关键字保存在pivotkey中*/
while(low < high) /*从表的两端交替地向中间扫描*/
{
while(low<high && L[high]>=pivotkey) --high;
L[low]=L[high];
while(low<high && L[low]<=pivotkey) ++low;
L[high]=L[low];
}
L[low]=L[0]; /*枢轴记录到位*/
return low;
}
void Qsort(int L[],int low,int high)
{
/*对顺序表L中的子序列L[low..high]做快速排序*/
if(low<high) /*长度大于1*/
{
int pivotloc=Partition(L,low,high); /*将L[low..high]一分为二,pivotloc是枢轴位置*/
Qsort(L,low,pivotloc-1); /*对左子表递归排序*/
Qsort(L,pivotloc+1,high); /*对右子表递归排序*/
}
}
void QuickSort(int L[],int n)
{
Qsort(L,1,n);
}
int main()
{
int ans[9]={0,49,38,65,97,76,13,27,49};
QuickSort(ans,8);
for(int i=1;i<=8;i++)
cout<<ans[i]<<" ";
return 0;
}
[运行结果]
附:<啊哈!算法>里快排的实现
#include<stdio.h>
int a[101],n;
void quicksort(int left,int right)
{
int i,j,t,temp;
if(left>right)
{
return ;
}
temp=a[left]; /*temp中存的就是基准数*/
i=left;
j=right;
while(i!=j)
{
/*顺序很重要 要先从右往左*/
while(a[j] >= temp && i<j)
j--;
while(a[i] <= temp && i<j)
i++;
if(i<j) /*交换两个数的位置*/
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
/*最终将基准数归位,交换*/
a[left]=a[i];
a[i]=temp;
quicksort(left,i-1); /*继续处理左边的,这是一个递归的过程*/
quicksort(i+1,right); /*继续处理右边的,这是一个递归的过程*/
return ;
}
int main()
{
int i,j;
scanf_s("%d",&n);
for(i=1;i<=n;i++)
{
scanf_s("%d",&a[i]);
}
quicksort(1,n);
/*输出排序后的结果*/
for(i=1;i<=n;i++)
{
printf("%d ",a[i]);
}
getchar();
return 0;
}