一、基本思想:分割(partition) 用一个数将所有其他数值分成左右两部分,使得左边的数小于等于此数,右边的数都大于等于此数。在寻找的过程中要交换两个数的位置。时间复杂度为O(NlogN),是一种不稳定的排序算法。
二、C++实现代码:
void QuickSort(int a[],int left,int right)
{
if(left>right)
return;
int first=left;
int last=right;
int key=a[first];
while(first<last)
{
while(first<last&&a[last]>=key)
--last;
a[first]=a[last];
/*将比第一个大的移到高端*/
while(first<last&&a[first]<=key)
++first;
a[last]=a[first];
/*将比第一个大的移到高端*/
a[first]=key;
/*将比第一个大的移到高端*/
QuickSort(a,left,first-1);
QuickSort(a,first+1,right);
}
}
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]的值赋给A[i];
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]的值赋给A[j];
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
三、在C++中使用:
sort(buf, buf+n, cmp);
- 1)buf:待排序数组的首地址,待排序数组元素共n个。
- 2)buf+n:此处是重点,这个参数不是待排序数组的最后一个元素的地址,而是最后一个元素的后地址。简单来讲,可以理解为 [buf, buf+n) ,即这里两个参数表示的意义是左闭右开。
- 3)cmp:排序方法,这个参数可以省略,省略后默认从小到大排序。也可以自己写一个比较函数来实现,具体见下面的例子。
#include <algorithm>
using namespace std;
bool cmp_up(int a,int b)//升序排序
{
return a<b;
}
bool cmp_down(int a,int b)//降序排序
{
return a>b;
int main()
{
int a[6]={2,9,8,4,6,7};
sort(a,a+6);
//调用方法
sort(a,a+6,cmp_up);
sort(a,a+6,cmp_down);
return 0;
}
//sort(buf, buf+n, cmp);
四、寻找第k小值数字:
(1) 当规模小于阈值时,直接用排序算法返回结果。
(2) 当n大于阈值时,把n个元素划分为5个元素一组的n/5组,排除剩余元素(不会有影响,这里只是为了求中项mm),分别排序,然后挑出每一组元素的中间值,再在所有的中间值中,递归调用本算法,挑出中间值mm。
(3) 把元素划分为A1、A2、A3三组,分别包含小于、等于、大于mm的元素。
(4)分三种情况:
若A1的元素数量大于等于K,即第K个元素在第一组内:在A1中递归查找第k小元素。
若A1、A2元素个数之和大于等于K,即中项mm为第K个元素:返回mm
否则,第K个元素在第三组:在A3中递归寻找第(k-|A1、A2元素数量之和|)小元素。
int findLastKMinNum(int A[],int low,int high,int k)
{
//设置阈值
int p=high-low+1;
if(p<6){
sort(A,A+p);
return A[k-1];
}
else{
//分为五段
int q=p/5;
int remainder=p-q*5;
//每段排序并把中项放入mid
int *mid=new int[q+1];
for(int i=0;i<q;i++)
{
sort(A[5*i],A[5*(i+1)]);
mid[i]=A[i*5+2];
}
if(remainder>0){
sort(A[5*q],A[5*q+remainder]);
mid[q]=A[q*5+(remainder+1)/2-1];
}
//中项集合的中项
int mm=findLastKMinNum(mid,0,q-1,(q+1)/2);
int *A1=new int[p];
int *A2=new int[p];
int *A3=new int[p];
int lenA1=0,lenA2=0,lenA3=0;
//分别与中项比较,分为新的三段
for(int i=low;i<=high;i++){
if(A[i]<mm)
A1[lenA1++]=A[i];
else if(A[i]==mm)
A2[lenA2++]=A[i];
else if(A[i]>mm)
A3[lenA3++]=A[i];
}
//将三段的长度与k比较判断k的位置并递归
int lastKMin=0;
if(lenA1>=k)
lastKMin=findLastKMinNum(A1,0,lenA1-1,k);
else if(lenA1+lenA2>=k)
lastKMin=mm;
else if(lenA1+lenA2<k)
lastKMin=findLastKMinNum(A3,0,lenA3-1,k-lenA1-lenA2);
delete[] mid;
return lastKMin;
}
}
参考:
三种解法:https://blog.csdn.net/weixin_37922777/article/details/82666466