【优化1】
第一版快速排序的对象是有序数组时,递归深度为O(n),容易造成栈溢出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hbzHkMhM-1610469804197)(347A6AB82C234141BFBB5292C5705FEE)]
使p的索引为[l,r]中的一个随机数,再将他和 l 调换位置
public static <E extends Comparable<E>> int partition(E[] arr,int l,int r,Random random){
//把数组分为 arr[l] | arr(l+1,j) | arr(j+1,i-1) | arr[e] | arr(e+1,r) 的形式
// 生成一个[l,r]的随机值 ,先生成 [0,r-l] 再加上 l
int p = random.nextInt(r-l+1) + l;
//将 l 位置的元素 与 p 位置的元素进行交换
swap(arr,l,p);
//初始化 j 的索引
int j = l;
for (int i = l + 1; i <= r; i++) {
if(arr[i].compareTo(arr[l]) < 0){
j++;
swap(arr,i,j);
}
}
swap(arr,l,j);
return j;
}
【优化2】
对于常数列,快速排序的常数列 为 O(n^2)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WpY4pOTG-1610469804200)(AE974C45FC144D1B86A842103002D1DB)]
使用双路快速排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NXb33VsL-1610469804202)(2E822D4915844CFCA3568D88E63F4CB4)]
public class QuickSortTwoWays {
private QuickSortTwoWays(){}
public static <E extends Comparable<E>> void sort(E[] arr){
//优化:我们只创建一次random的对象
Random random = new Random();
sort(arr,0,arr.length-1,random);
}
private static <E extends Comparable<E>> void sort(E[] arr,int l,int r,Random random){
if(l >= r) return;
//返回p的索引位置
int p = partition(arr,l,r,random);
// 对 arr[l,p-1]进行排序
sort(arr,l,p-1,random);
//对 arr[p+1,r]进行排序
sort(arr,p+1,r,random);
}
private static <E extends Comparable<E>> int partition(E[] arr,int l,int r,Random random){
// 生成一个[l,r]的随机值 ,先生成 [0,r-l] 再加上 l
int p = random.nextInt(r-l+1) + l;
//将 l 位置的元素 与 p 位置的元素进行交换,
swap(arr,l,p);
//初始化 i,j 的索引,实现 arr[l+1...i-1]<=v; arr[j+1...r]>=v
int i = l + 1,j = r;
while(true){
while(i <= j && arr[i].compareTo(arr[l]) < 0)
i++;
while(j >= i && arr[j].compareTo(arr[l]) > 0)
j--;
if(i >= j) break;
swap(arr,i,j);
i++;
j--;
}
swap(arr,l,j);
return j;
}
private static <E extends Comparable<E>> void swap (E[] arr,int i,int j){
E temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int n = 1000000;
SortingHelper.sortTest("MergeSort",n);
SortingHelper.sortTest("MergeSortBU",n);
SortingHelper.sortTest("QuickSort",n);
SortingHelper.sortTest("QuickSortTwoWays",n);
}
}
```java
public class QuickSortTwoWays {
private QuickSortTwoWays(){}
public static <E extends Comparable<E>> void sort(E[] arr){
//优化:我们只创建一次random的对象
Random random = new Random();
sort(arr,0,arr.length-1,random);
}
public static <E extends Comparable<E>> void sort(E[] arr,int l,int r,Random random){
if(r - l <= 8) {
insertSort(arr,l,r);
return;
}
//返回p的索引位置
int p = partition(arr,l,r,random);
// 对 arr[l,p-1]进行排序
sort(arr,l,p-1,random);
//对 arr[p+1,r]进行排序
sort(arr,p+1,r,random);
}
public static <E extends Comparable<E>> int partition(E[] arr,int l,int r,Random random){
// 生成一个[l,r]的随机值 ,先生成 [0,r-l] 再加上 l
int p = random.nextInt(r-l+1) + l;
//将 l 位置的元素 与 p 位置的元素进行交换,
swap(arr,l,p);
//初始化 i,j 的索引,实现 arr[l+1...i-1]<=v; arr[j+1...r]>=v
int i = l + 1,j = r;
while(true){
while(i <= j && arr[i].compareTo(arr[l]) < 0)
i++;
while(j >= i && arr[j].compareTo(arr[l]) > 0)
j--;
if(i >= j) break;
swap(arr,i,j);
i++;
j--;
}
swap(arr,l,j);
return j;
}
public static <E extends Comparable<E>> void swap (E[] arr,int i,int j){
E temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static <E extends Comparable<E>>void insertSort(E[] arr,int l,int r){
for (int i = l; i <= r; i++) {
//将 arr[i] 插入到合适的位置
E temp = arr[i];
int j;
for (j = i;j-1 >= l && temp.compareTo(arr[j-1]) < 0;j--)
arr[j] = arr[j-1];
arr[j] = temp;
}
}
public static void main(String[] args) {
int n = 1000000;
SortingHelper.sortTest("MergeSort",n);
SortingHelper.sortTest("MergeSortBU",n);
SortingHelper.sortTest("QuickSort",n);
SortingHelper.sortTest("QuickSortTwoWays",n);
}
}
【对比结果】
MergeSort:n = 1000000:0.445049s
MergeSortBU:n = 1000000:0.5078592s
QuickSort:n = 1000000:0.3762748s
QuickSortTwoWays:n = 1000000:0.2422526s