未优化的快速排序:
T(n)=2T(n/2)+O(n)。
算法时间复杂度:O(nlgn)。
当主元没选好:(最大/最小):
时间复杂度: O(n²)。
三点中值法:
优化: 在p、r、mid之间,选一个中间值作为主元
#include<iostream>
using namespace std;
//三点中值法
int partition(int A[],int p,int r){
//优化: 在p、r、mid之间,选一个中间值作为主元
int midIndex=p+((r-p)>>1); //中间下标
int midValueIndex=-1; //中值的下标
if(A[p]<=A[midIndex]&&A[p]>=A[r]){
midValueIndex=p;
}
else if(A[r]<=A[midIndex]&&A[r]>=A[p]){
midValueIndex=r;
}
else{
midValueIndex=midIndex;
}
swap(A[p],A[midValueIndex]);
int pivot=A[p];
int left=p+1;//扫描指针
int right=r; //右侧指针
while(left<=right){
//left不停往右走,直到遇到大于主元的元素
while(A[left]<=pivot) left++; //循环退出时,left一定是指向第一个大于主元的位置
while(A[right]>pivot) right--; //循环退出时,right一定是指向最后一个小于等于主元的位置
if(left<right){
swap(A[right],A[left]);
}
}
//while退出时,两者交错,且right指向的是最后一个小于等于主元的位置,也就是主元应该待的位置
swap(A[p],A[right]);
return right;
}
void quickSort(int A[],int p, int r){
if(p<r){
int q=partition(A,p,r);
quickSort(A,p,q-1);
quickSort(A,q+1,r);
}
}
int main(){
int arr[]={1,6,2,3,4,8,11,3,9,4,2,5,3};
quickSort(arr,0,12);
for(int i=0;i<13;i++){
cout<<arr[i]<<" ";
}
return 0;
}
结果:
绝对中值法:
//获取绝对的中值数,,O(N)的样子
int getMedian(int arr[],int p,int r){ //p:首下标; r:最后一个下标
int size=r-p+1; //数组长度
//每五个元素一组, groupSize:组数
int groupSize=(size%5==0)?(size/5):(size/5+1);
//存储各小组的中值
int medians[groupSize];
int indexOfMedians=0; //中值数组medians 的下标
//对每一组进行插入排序
for(int j=0;j<groupSize;j++){
//单独处理最后一组,因为最后一组可能不满5个元素
if(j=groupSize-1){
insertionSort(arr , low: p+j*5 , high: r); //对最后一组进行插入排序
medians[indexOfMedians++]=arr[(p+j*5+r)/2]; //最后一组的中间的那个元素
}
else{
insertionSort(arr , low: p+j*5 , high: p+j*5+4);//对非最后一组进行插入排序
medians[indexOfMedians++]=arr[p+j*5+2]; //当前组(排序后)的中间的那个
}
}
//对medians排序
insertSort(medians,0,medians.length-1); //PS: C++对数组不能用 数组.length(), 对string可以
return medians[medians.length/2];
}
求出中值后,只需和第一个元素交换,后面代码相同。
待排序列表较短时,用插入排序
PS:n<=8; 插入排序( O(n(n-1)/2) )比快速排序( O(2n(lgn+1)) )要快。
n<=8, 插入排序; 否则,快速排序。