快速排序QuickSort
第一版
要求
使用递归,partion函数将小于目标值的放在左边,大于目标值的放在右边,并返回目标值的位置,以便递归
思路
使用j和i指针,j指向目标值(左边),i指向l+1,两个循环不变量如图,如果i的值比目标值小的化,交换i的值和j+1的值,j++
循环不变量
[l+1,j] < v
[j+1,i-1] >v
代码
import java.util.Arrays;
public class QuickSort {
public static <E extends Comparable<E>> void Sort(E[] arr){
Sort(arr,0,arr.length-1);
}
private static <E extends Comparable<E>> void Sort(E[] arr , int l , int r){
if(l >= r)
return;
int a = partition(arr,l,r);
Sort(arr,l,a-1);
Sort(arr,a+1,r);
}
public static <E extends Comparable<E>> int partition(E[] arr,int l ,int r){
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;
}
public static <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) {
Integer[] arr = {3,1,4,5,2,6,0};
Sort(arr);
System.out.println(Arrays.toString(arr));
}
}
问题1:
当数组是有序的时候时间复杂度较大
改进
在partition中加入随机索引
int randomIndex= random.nextInt(r - l + 1) + l;
//nextInt取的是开区间所以要加一
swap(arr,l,randomIndex);
时间复杂度分析
虽然加了随机标定,但当数组元素都相等时,100%恶化,故仍为O(n2)
问题2:
如果所有元素相等,和问题1一样,最后会得到左边没有元素的情况
改进
//把此处的判断条件加上等于
if(arr[i].compareTo(arr[l])<=0)
第二版(实现双路排序)
要求
使用i和j指针,i指向l+1的元素,j指向r的元素,运用两个循环使得两个指针向中间移动
思路
小循环的条件即为两指针之间有元素(i<=j),如果比标定值小或者大就向中间移动,当i>=j时循环结束,小循环结束后交换两元素,继续向中间移动
代码
public static <E extends Comparable<E>> int partition2ways(E[] arr,int l ,int r){
int i = l + 1;
int j = r;
int randomIndex= random.nextInt(r - l + 1) + l;
swap(arr,l,randomIndex);
while (true){
while (i <= j && arr[i].compareTo(arr[l])<0) i++;
while (i <= j && arr[j].compareTo(arr[l])>0) j--;
if(i >= j) break;
swap(arr,i,j);
i++;
j--;
}
swap(arr,l,i);
return i;
}
时间复杂度分析
和归并排序一样为O(nlogn)
第三版(实现三路排序)
要求
>
思路
三个指针,三个循环不变量,初始值lt=l, i=l+1 ,gt=r+1 如图,循环条件为i<gt,结束后应该
[l,lt-1]<v
[lt,gt-1]=v
[gt,r]>v
循环不变量
[l+1,lt] < v
[lt+1,i-1] = v
[gt,r] > v
代码
private static <E extends Comparable<E>> void Sort3ways(E[] arr , int l , int r){
if(l >= r)
return;
int randomIndex= random.nextInt(r - l + 1) + l;
swap(arr,l,randomIndex);
int lt = l,i = l+1,gt = r+1;
while (i<gt){
if(arr[i].compareTo(arr[l])<0){
lt++;
swap(arr,lt,i);
i++;
}else if(arr[i].compareTo(arr[l])>0){
gt --;
swap(arr,gt,i);
}else {
i++;
}
}
swap(arr,l,lt);
Sort3ways(arr,l,lt-1);
Sort3ways(arr,gt,r);
}