快速排序是一种比较高级的排序方法。拥有O(NlogN)的平均复杂度。快速排序的基本思路是交换。
具体做法如下,首先选定序列中的一个元素作为枢轴量(通常选择第一个元素)。然后让序列中的各元素依次和枢轴量进行比较,通过交换使得:比它小的排在它左边,比它大的排在它右边。通过这一趟排序,我们将序列分成了两部分,其中一部分全部比另一部分小(当然枢轴量放在哪一部分无所谓)。之后的想法就比较自然了,我们可以对分成的两部分序列重复上面的过程(递归),直到整个序列有序。
具体操作时,设两个指针low和high,他们的初值分别是序列的起点和终止位置,设枢轴的关键字为pivot,首先从high所指位置向前搜索,找到关键字小于pivot的记录则和枢轴记录交换,注意这个时候不要继续向前搜索,应该从low所指的位置开始向后搜索,找到关键字大于pivot的记录则和枢轴记录交换。前向搜索和后向搜索一定要交替执行,这样可以保证low和high的值不断接近而且可以将和枢轴记录不相等的记录分配到枢轴的两端。如果只从一个方向进行搜索,则不能保证一部分记录都小与另一部分记录。这一点一定要注意。
//快速排序
//lovesunmoonlight
//2017.3.24
#include<iostream>
#include<cstdlib>
#include<cmath>
#define MAX 10
using namespace std;
typedef struct{
int key; //关键字
double data; //数据
}node;
typedef struct{
node r[MAX+1]; //r[0]设置为暂存单元
int len;
}List;
//一趟排序过程,返回值是枢轴量的新位置
int oneStepSwap(List& s,int low,int high)
{
s.r[0]=s.r[low]; //将枢轴记录到r[0]
int pivot=s.r[low].key; //枢轴的键值
while(low<high) //从表的两端交替向中间扫描
{
while(low<high&&s.r[high].key>=pivot) //将比枢轴小的移动到低端
high--;
s.r[low]=s.r[high];
while(low<high&&s.r[low].key<pivot) //将比枢轴大的移动到低端
low++;
s.r[high]=s.r[low];
}
s.r[low]=s.r[0]; //还原枢轴量
return low; //返回枢轴量的位置
}
void quickSort(List& s,int low,int high)
{
if(low<high) //当序列中只有一个元素结束递归
{
int pivot=oneStepSwap(s,low,high); //一趟排序,将序列一分为二
quickSort(s,low,pivot-1); //递归排序左边序列
quickSort(s,pivot+1,high); //递归排序右边序列
}
}
void output(const List& s)
{
cout<<"Key Data"<<endl;
for(int i=1;i<s.len;i++)
cout<<s.r[i].key<<" "<<s.r[i].data<<endl;
cout<<endl;
}
int main()
{
List s;
//初始化表
s.len=MAX+1;
s.r[0].key=0;
s.r[0].data=-1;
for(int i=1;i<s.len;i++)
{
s.r[i].data=rand()%100;
s.r[i].key=rand()%50;
}
cout<<"Initialized: "<<endl;
output(s);
cout<<"The pivot:"<<endl;
cout<<s.r[1].key<<" "<<s.r[1].data<<endl<<endl;
int result=oneStepSwap(s,1,s.len-1);
cout<<"After oneStepSwap: "<<endl;
output(s);
cout<<"The position of the pivot now: "<<result<<endl<<endl;
cout<<"After quickSort: "<<endl;
quickSort(s,1,s.len-1);
output(s);
return 0;
}
经过测试,在我的i5台式机排序10万个数所需要的时间大约为450ms,用STL的qsort排了一下大概是300ms左右,应该算是比较高效的排序算法了。