快速排序介绍
在此文章之前请先阅读快速排序
快速排序的优化主要是再基准的选择上和尽量减少partition的运行。
其基准选择有几种方法1.随机选择法2.三分取中法,等等。
减少partition的方法主要输相同元素聚合。
其实现方法为
1.随机选择法
原来的选择基准为一直选择low下标的元素,所以在处理某些大量有序的序列的时候就会造成大量的元素在一侧,使得快排没有任何效果。
此时只需要在快排前面加入一段代码。
//产生start - end 的随机数
int randomNum= (int)(Math.random()*(end-start)+start);
//交换start下标和随机位置的两个数,因为我们的partition默认取的是
//start位置所以可以通过换位置实现以随机位置为基准。
swap(array, start,randomNum);
2.三分取中法
加入一个函数
/**
* 三分取中
* @param array 数组
* @param low 下限
* @param hight 上限
*/
public static void SelectThreeMid(int[] array,int low,int hight)
{
int mid = (low+hight)>>>1;
if(array[low]<array[mid]) //目标low>mid
{
swap(array, mid, low);
}
if(array[hight]<array[mid]) //目标hight>mid
{
swap(array, hight, mid);
}
if(array[low]>array[hight]) //目标low<hight
{
swap(array, low, hight);
}
//最终结果为 low 下标的为中间值
}
只需要将这行代码插入到partition执行之前,此代码就会将三个数中中间的数放入到下限下标,然后partition就会用下限下标来作为标准快排。
3.同元素聚合法
同元素聚合及为当以某个元素当做partition的基准的时候,顺便将和其相同的元素聚合在一起然后再进行partition。
函数
/**
* 聚集和基准相同的元素
* @param array 数组
* @param start 开始下标
* @param end 结束下标
* @param par 基准
*/
private static int[] focus(int[] array, int start, int end, int par) {
//查找的范围
int left = par-1;
int right = par+1;
//交换的指引变量
int parLeft = par-1;
int parRight = par+1;
//左边找相同的
for (int i = left; i >=start; i--) {
//当找到相同的
if(array[i] == array[par])
{
//如果不相邻
if(i!=parLeft)
{ //i和交换的指引下标进行交换
swap(array, parLeft, i);
//指引下标移动
parLeft--;
}
else
{ //如果相邻,只移动指引下标
parLeft--;
}
}
}
//右边找 原理同上
for (int i = right; i <=end; i++) {
if(array[i] == array[par])
{
if(i!=parRight)
{
swap(array, parRight, i);
parRight++;
}
else
{
parRight++;
}
}
}
//new一个数组,放入聚合在一起元素的上下限,及下次快排应该越过其,只在其上下限进行排序
int [] focus = {parLeft,parRight};
return focus;
}
这个要对快速排序的函数进行改造
public static void Quick(int[] array,int start,int end)
{
//先找到基准下标
int par = partion(array, start, end);
//调用聚集函数,聚集,找到应该快排的区段
int[] focus = focus(array,start,end,par);
int left = focus[0];
int right = focus[1];
//判断基准的左边是不是还有1个以上元素,如果是再调用快排
if(par>start+1)
{
Quick(array, start, left);
}
//判断基准的右边是不是还有1个以上元素,如果是再调用快排
if(par<end-1)
{
Quick(array, right, end);
}
}
4.当数据量小到某个节点的使用使用快排
快排函数
/**
* 给某个区段快速排序 [start,end]
* @param array
* @param start
* @param end
*/
private static void insert_sort(int[] array,int start,int end) {
int temp = 0;
int j = 0;
for (int i = start+1; i < end+1; i++) {
temp = array[i];
for (j = i-1; j >= 0 ; j--) {
if(array[j]>temp){
array[j+1] = array[j];
}else
{
break;
}
}
array[j+1] = temp;
}
}
快排函数改造
在快排函数的第一行加上
if(end-start+1<num)
{
insert_sort(array,start,end);
return;
}
此函数可以实现在快排的数量级小于num的时候实现插入排序。
最佳方案
以上方案有的可以叠加使用,当然效果是最好的
查阅资料可知,以上方法的组合,目前最快的可能是三数取中+聚集+插入排序