优化一:当待排列序列的长度分割到一定大小时,使用插入排序
原因:对于很小和部分有序的数组,快排不如插入排序好。当待排序序列的长度分割到一定大小后,继续使用分割的效率比插入排序要差; 但是三分取中+插入排序还不能处理重复数组;
优化二:聚集相同基准法;处理重复的数组元素
原因:在一次分割结束后,可以把与par相等的元素聚集在一起。下次分割时,不用在对和par相等元素进行分割
举例:
待排序序列 1 4 6 7 6 6 7 6 8 6
三数取中选取枢轴:下标为4的数6
转换后,待分割序列:6 4 6 7 1 6 7 6 8 6
枢轴par:6
本次划分后,未对与par元素相等处理的结果:1 4 6 6 7 6 7 6 8 6
下次的两个子序列为:1 4 6 和 7 6 7 6 8 6
本次划分后,对与key元素相等处理的结果:1 4 6 6 6 6 6 7 8 7
下次的两个子序列为:1 4 和 7 8 7
经过对比,我们可以看出,在一次划分后,把与par相等的元素聚在一起,能减少迭代次数,效率会提高不少
具体过程:在处理过程中,会有两个步骤
划分结束后,把与par相等的元素移到par周围
举例:
待排序序列 1 4 6 7 6 6 7 6 8 6
三数取中选取枢轴:下标为4的数6
转换后,待分割序列:6 4 6 7 1 6 7 6 8 6
枢轴par:6
划分结束后,把与par相等的元素移到枢轴周围
结果为:1 4 66(枢轴) 6 6 6 7 8 7
此时,与6相等的元素全移到枢轴周围了,之后在对14和787两个子序列进行快排
之后,在1 4 和 7 8 7两个子序列进行快排
/**
* @Author 《BoYou》
* @Description 快排的优化
* 当数据小于100的时候,用直接插入
* 海量数据时,每次取到par时,左右各循环
* 将与par相同的值都移动到par附近,则下次排序
* 就会从不相同的临界值开始
* @Date 2019/1/10 -- 下午 8:51
*/
public class FastSort05 {
public static void main(String[] args) {
Random ran=new Random();
int[] array=new int[120];
for (int i = 0; i <120 ; i++) {
array[i] = ran.nextInt(99)+1;
}
quicksort(array);
System.out.println(Arrays.toString(array));
}
public static void quicksort(int[] array){
quick(array,0,array.length-1);
}
public static int[] foucsParNum(int[] array,int par,int low,int high){
//聚集相同元素
int left=par-1;
int right=par+1;
int[] brray=new int[2];
for (int i = par-1; i >low ; i--) {
if (array[i]==array[par]){
if (left!=i){
swap(array,left,i);
}
left--;
}
}
for (int j = par+1; j <high ; j++) {
if (array[j]==array[par]){
if (right!=j){
swap(array,right,j);
}
right++;
}
}
brray[0]=left;
brray[1]=right;
return brray;
}
public static void quick(int[] array, int low,int high){
if (high-low+1<100){
insertsort(array,low,high);
return;
}
midThree(array,low,high);
int par=parvion(array,low,high);
int[] brray=foucsParNum(array,par,low,high);
int left=brray[0];
int right=brray[1];
if (left>low){
quick(array,low,left);
}
if (right<high){
quick(array,right,high);
}
}
public static void insertsort(int[] array,int low,int high){
int tmp=0;
int j=0;
for (int i = 1; i <= high; i++) {
tmp=array[i];
for ( j = i-1; j >=low ; j--) {
if (array[j]>tmp){
array[j+1]=array[j];
}else {
break;
}
}
array[j+1]=tmp;
}
}
//三分取中法实现原理:
//array[mid]<=array[low]<=array[high];
public static void midThree(int[] array,int low,int high){
int mid=(low+high)/2;
if (array[mid]>array[low]){
swap(array,low,mid);
}
if (array[mid]>array[high]){
swap(array,mid,high);
}
if (array[low]>array[high]){
swap(array,low,high);
}
}
public static void swap(int[] array ,int low,int rand){
int tmp=array[low];
array[low]=array[rand];
array[rand]=tmp;
}
public static int parvion(int[] array,int low,int high){
int tmp=array[low];
while (low<high){
while (low<high&&tmp<array[high]){
high--;
}
if (low<high){
array[low]=array[high];
low++;
}else break;
while (low<high&&tmp>array[low]){
low++;
}
if (low<high){
array[high]=array[low];
high--;
}else break;
}
array[low]=tmp;
return low;
}
}