快速排序的几种优化方式
1.对于基准选取方式的优化:
(1),随机选取基准的方法:
/*进行第一趟快速排序
* */
public static int partion(int[] array,int low,int high){
int tmp = array[low];
while(low<high){
while(low < high && array[high] >= tmp){
--high;
}
if(low >= high){
break;
}else{
array[low] = array[high];
}
while(low < high && array[low] <= tmp){
++low;
}
if(low >= high){
break;
}else{
array[high] = array[low];
}
}
array[low] = tmp;
return low;
}
/*交换函数
*/
public static void swap(int[] array,int start,int end){
int tmp = array[start];
array[start] = array[end];
array[end] = tmp;
}
public static void Quick(int[] array,int start,int end){
/*让随机数位置的元素与start位置的元素进行交换
* */
swap(array,start,(int)(Math.random()%(end-start)+start));//产生start与end直接的随机数,并执行强制转换
//然后进行第一次排序
int par = partion(array,start,end);
//对par左面的元素进行排序
if(par > start+1){
Quick(array, start, par-1);
}//对par有面的元素进行排序
if(par < end-1){
Quick(array, par+1, end);
}
}
(2),三数取基准法
在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。
public static void dealPivot(int[] a, int left, int right) {
int mid = (left + right) / 2;
//把mid left right 三个位置中中间的元素放在left位置
if(a[left]<a[right]){
if(a[mid]>a[left]&&a[mid]<a[right]){
swap(a, left, mid);
}
if(a[mid]<a[left]){
}
if(a[right]<a[mid]){
swap(a, left, right);
}
}
if(a[left]>a[right]){
if(a[mid]<a[left]&&a[mid]>a[right]){
swap(a, left, mid);
}
if(a[mid]>a[left]){
}
if(a[right]>a[mid]){
swap(a, left, right);
}
}
}
2.同元素聚合法
把所有与基准相同的元素放在中间,以减少不必要的找基准次数。
public static int[] focurNum(int[] array,int start,int end,int par){
/*聚集与基准相同的元素
* */
int parLeft = par-1;//从基准左面相邻的位置开始
int parRight = par+1;//从基准右面相邻的位置开始
int tmp = 0;
/*先在左面找相同的
* */
for(int i = par-1;i >= start;i--){
if(array[i] == array[par]){
if(i != parLeft){//找到与基准相同的值,进行交换
tmp = array[parLeft];
array[parLeft] = array[i];
array[i] = tmp;
parLeft--;//移动下标
}else{
parLeft--;
}
}
}
int left = parLeft;//左面离基准最近的一个与基准不同的元素的下标
/*
* 右边找
*/
for(int j = par+1;j <= end;j++){
if(array[j] == array[par]){
if(j != parRight){
tmp = array[parRight];
array[parRight] = array[j];
array[j] = tmp;
parRight++;
}else{
parRight++;
}
}
}
int right = parRight;//右面离基准最近的一个与基准不同的元素的下标
int[] brray = new int[2];//使用brray数组把俩个下标储存起来
brray[0] = left;
brray[1] = right;
return brray;//返回brray数组
}
/*快速排序
*/
public static void Quick(int[] array,int start,int end){
int par = partion(array,start,end);//先进行第一次找基准
int[] brray = focurNum(array,start,end,par);
int left = brray[0];//左面离基准最近的一个与基准不同的元素的下标赋给left
int right = brray[1];//右面离基准最近的一个与基准不同的元素的下标赋给right
if(par > start+1){//基准左面排序
Quick(array, start, left);
}
if(par < end-1){//基准右面排序
Quick(array, right, end);
}
}
3,数据少的时候,用直接插入法
public static void quick1(int []a,int start,int end){
if((a.length)<10){//当数组的长度不足10的时候,使用直接插入排序
for(int i=1;i<a.length;i++){
int temp = a[i];
int j=0;
for( j=i-1;j>=0;j--){
if(a[j]>temp){
a[j+1] = a[j];
}else{
break;
}
}
a[j+1] = temp;
}
return ;
}
int par=partion(a, start, end);//先确定第一个基准
if(par>start+1){//如果基准左面有俩个或者俩个以上的元素
quick1(a, start, par-1);//左面进行快速排序
}
if(par<end-1){//如果基准右面有俩个或者俩个以上的元素
quick1(a, par+1, end);//右边进行快速排序
}
}