1 切换到插入排序
对于小数组,递归类型的排序比插入排序要慢。当递归到某个范围内的小数组时切换到插入排序性能会有良好的提高。经验表明,这个范围在5~15的时候效果良好
1.1 快速排序优化
public class QuickWithInsertSort extends BaseQuickSort {
//阙值
private final int CUTOFF = 10;
@Override
protected void quickSort(Comparable[] arrs, int left, int right) {
if (left + CUTOFF >= right){
// 如果切分到某个阈值内的小数组用插入排序
insertSort(arrs, left, right);
return;
}
int j = partition(arrs, left, right);
quickSort(arrs, left, j - 1);
quickSort(arrs, j + 1, right);
}
}
1.2 归并排序优化
public class MergeWithInsertSort extends BaseMergeSort {
// 阙值
private final int CUTOFF = 7;
@Override
protected void mergeSort(Comparable[] arr, int left, int right, Comparable[] temp) {
if (left < right) {
//当数组长度达到阙值时,使用插入排序
if (right <= left + CUTOFF) {
insertSort(arr, left, right);
return;
}
int mid = (left + right) / 2;
//左边递归分解,使得左子序列有序
mergeSort(arr, left, mid, temp);
//右边递归分解,使得右子序列有序
mergeSort(arr, mid + 1, right, temp);
//将两个有序子数组合并操作
merge(arr, left, mid, right, temp);
}
}
}
2 双端比较归并排序
这种排序不会优化归并排序,只是归并排序的另一种写法
在merge()方法中的归并过程需要判断i和j是否已经越界,即某半边已经用尽。可以用另一种方式,去掉检测是否某半边已经用尽的代码。
具体步骤是将数组arr[]的后半部分以降序的方式复制到temp[],然后从两端归并。对于数组{1,2,3}和{2,3,5},第一个子数组照常复制,
第二个则从后往前复制,最终temp[]中的元素为{1,2,3,5,3,2}。这种方法的缺点是使得归并排序变为不稳定排序。
然后从两端依次比较元素,把较小的元素放到数组中
代码实现
public class BinaryWithInsertMergeSort extends MergeWithInsertSort {
@Override
protected void merge(Comparable[] arr, int left, int mid, int right, Comparable[] temp) {
// 在merge()方法中的归并过程需要判断i和j是否已经越界,即某半边已经用尽。可以用另一种方式,去掉检测是否某半边已经用尽的代码。
// 具体步骤是将数组arr[]的后半部分以降序的方式复制到temp[],然后从两端归并。对于数组{1,2,3}和{2,3,5},第一个子数组照常复制,
// 第二个则从后往前复制,最终temp[]中的元素为{1,2,3,5,3,2}。这种方法的缺点是使得归并排序变为不稳定排序。
System.arraycopy(arr, left, temp, left, mid + 1 - left);
for (int j = mid + 1; j <= right; j++) {
temp[j] = arr[right - j + mid + 1];
}
int i = left;
int j = right;
for (int k = left; k <= right; k++) {
if (less(temp[i], temp[j])) {
arr[k] = temp[j --];
} else {
arr[k] = temp[i ++];
}
}
}
}
3 三数取中快速排序
传统的快速排序中,基是随机选取的。如果一个数组原本是从大到小排序的,则会导致左右递归次数不均。基准越接近中位数,递归效果越好。
优化方式是在切分之前把小数组左、中、右元素按照中、小、大排序即可
代码实现
public class MedianQuickSort extends BaseQuickSort {
//阙值
private final int CUTOFF = 7;
@Override
protected void quickSort(Comparable[] arrs, int left, int right) {
if (left + CUTOFF >= right){
insertSort(arrs, left, right);
return;
}
partitionMedianOfThree(arrs, left, right);
int j = partition(arrs, left, right);
quickSort(arrs, left, j - 1);
quickSort(arrs, j + 1, right);
}
private void partitionMedianOfThree(Comparable[] arrs, int left, int right) {
int mid = left + (right + -left) / 2;
// 把左、中、右元素按照中、小、大排序
if (less(arrs[mid], arrs[right])) {
exch(arrs, mid, right);
}
if (less(arrs[left], arrs[right])) {
exch(arrs, left, right);
}
if (less(arrs[mid], arrs[left])) {
exch(arrs, mid, left);
}
}
}