普通优化快排
相比较原始快排,这里优化了两个地方:
优化1:为防止在近乎有序的数组,partition分割极度不平衡,可将v元素随机化选取
优化2:递归到一定程度可使用插入排序
另外为了方便大家理解partition过程,附图一张:
public void quickSort(int[] nums){
if(nums == null || nums.length <=0)
return;
quickSort(nums , 0 , nums.length-1);
}
public void quickSort(int[] nums , int l , int r){ //对nums[l...r]部分进行快排
//if(l >= r) //原始递归到底方法
//return;
if(r-l <= 15){ //优化2:递归到一定程度可使用插入排序
insertSort(nums , l , r);
return;
}
int p = partition(nums , l , r);
quickSort(nums , l , p-1);
quickSort(nums , p+1 , r);
}
public int partition(int[] nums , int l , int r){
swap(nums , l , l+(int)(Math.random()*(r+1-l)));//优化1:为防止在近乎有序的数组,partition分割极度不平衡,可将v元素随机化选取
int v = nums[l];
int j = l;
for(int i = j+1 ; i<=r ; i++)
if(nums[i]<v)
swap(nums , ++j , i);
swap(nums , l , j);
return j;
}
public void insertSort(int[] nums , int l , int r){
for(int i=l+1 ; i<=r ; i++){
int temp = nums[i];
int j=i;
for(; j>l && nums[j-1]>temp ; j--){
nums[j] = nums[j-1];
}
nums[j] = temp;
}
}
public void swap(int[] nums , int i , int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
双路快排
但此时对于有大量重复元素的情况,依然会造成partition不平衡的情况,所以,可以考虑使用双路快排。如下图所示:i,j分别从两边向中间靠拢,每次交换i,j时,总是arr[i] >= v,arr[j]<=v的情况,这样就将==v的情况在两边平分
具体到代码,只有partition有改动:
int partition(int[] arr, int l, int r){
swap(arr, l, l + (int)(Math.random()*(r-l+1)));
int v = arr[l];
//arr[l+1...i) <= v, arr(j...r] >= v
int i = l+1, j=r;
while(true){
while(i <= r && arr[i] < v)
i++;
while(j >= l+1 && arr[j] > v)
j--;
if(i > j)
break;
swap(arr, i, j);
i++;
j--;
}
swap(arr, l, j);
return j;
}
三路快排
当存在大量重复元素时,三路快排比双路快排更快,因为==v的区间元素直接就不需要再次运算了,效率很高。这里将数组分为三个部分<v, ==v, >v,新建lt与gt进行区分,如图所示:
当运行完毕后,继续快排[l, lt-1]与[gt, r]之间的元素即可,如图所示:
由于partition函数传递lt与gt两个变量不太方便,所以这里将前面partition函数整合至quickSort递归函数中:
private void quickSort(int[] nums, int l, int r){
if(l >= r)
return;
swap(nums , l , l+(int)(Math.random()*(r+1-l)));
int v = nums[l];
int lt = l, gt = r+1, i = l+1;
while(i < gt){
if(nums[i] == v)
i++;
else if(nums[i] < v)
swap(nums, i++, ++lt);
else
swap(nums, i, --gt);
}
swap(nums, l, lt);
quickSort(nums, l, lt-1);
quickSort(nums, gt, r);
}