快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。
切分过程:通常取数组第一个元素作为切分,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于它的元素,交换这两个元素。不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[l] 和 a[j] 交换位置
快排的每一步,有下列的数组{6,1,2,7,9,3,4,5,10,8},盗张图(嘿嘿),地址:https://www.cnblogs.com/ysocean/p/8032632.html#_label1
性能分析:
快速排序是原地排序,不需要辅助数组,但是递归要用辅助栈,最好的情况下是将数组切分成二个一样的部分。复杂度为O(n*logn)
最坏情况下是原来数组就已经有序,这时复杂度就为O(n^2),因此为防止数组一开始就有序,应该随机打乱数组的顺序。
关于优缺点和相关的优化,这篇文章写的挺好的:https://blog.csdn.net/pcwl1206/article/details/83067542#4、快速排序
和这篇:https://www.cnblogs.com/ysocean/p/8032632.html#_label1
解决原数组有序的情况:找一个可能在文件的中间位置的元素作为pivot。则可以选取数组中最左边元素、最右边元素以及中间元素中中间大小的元素作为pivot,这样使得最坏情况几乎不可能再发生
public class ReviceDemo {
private static int medianOf3(int[] array, int left, int right) {
int center = (right - left) / 2 + left;
//保证arr[right]最大
if(array[left]>array[right]){
swap(array, left,right);
}
if(array[center]>array[right]){
swap(array, center,right);
}
//比较center和left,让最大的在left位置上
if(array[center]>array[left]){
swap(array, center,left);
}
return array[left]; //array[left]的值已经被换成三数中的中位数, 将其返回
}
private static int partitionIt(int[] array, int left, int right) {
//为什么 j加一个1,而i没有加1,是因为下面的循环判断是从--j和++i开始的.
//而基准元素选的array[left],即第一个元素,所以左游标从第二个元素开始比较
int i = left;
int j = right + 1;
int pivot = array[left];// pivot 为选取的基准元素(头元素)
int size = right - left + 1;
if (size >= 3) {
pivot = medianOf3(array, left, right); //数组范围大于3,基准元素选择中间值。
}
while (true) {
while (i < right && array[++i] < pivot) {
}
while (j > 0 && array[--j] > pivot) {
}
if (i >= j) {// 左右游标相遇时候停止, 所以跳出外部while循环
break;
} else {
swap(array, i, j);// 左右游标未相遇时停止, 交换各自所指元素,循环继续
}
}
swap(array, left, j);//基准元素和游标相遇时所指元素交换,为最后一次交换
return j;// 一趟排序完成, 返回基准元素位置(注意这里基准元素已经交换位置了)
}
public static void swap(int []arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void main(String[] args) {
int arr[]={1,4,6,2,8};
int i = medianOf3(arr, 0, arr.length - 1);
System.out.print(i);
}
}
解决数组长度较小的时候,用插入排序
解决数组中重复元素较多的时候,可用荷兰国旗问题解决:实际上荷兰国旗问题可以解决数组中有大量重复元素,和数组原来有序的情况,关键代码在于swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
public class QuickSort {
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
int[] p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1);
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
int cur=l;
while (cur < more) {
if (arr[cur] < arr[r]) {
swap(arr, ++less, cur++);
} else if (arr[cur] > arr[r]) {
swap(arr, --more, cur);
} else {
cur++;
}
}
swap(arr, more, r);
return new int[] { less + 1, more };
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}