快速排序(交换排序,递归操作)
-
思路:
- 快速排序核心思想是找一个基点,然后让基点左右两遍元素依次和它比较,如果左边某个元素大于基点且右边某个小于基点,则将这俩交换;直到左右两边到达基点,越位之后开始递归,总体分为两部分一左一右,而一左一右之中又可以分为一左一右,这样递归下去,直到两端为止。这个过程类似一生二、二生四、四生八......
- 这里可以看出快速排序是不稳定的
(假设,左边第一个数大于基数,最右边有两个相同的数都小于基数,于是,左边的数先和右边后一个数交换,之后如果左边的第二个数仍然大于基数,那么再次进行交换后,两个相同的数的相对位置就发生了改变)
以下用一个图例说明快速排序过程,这里给出一组测试数组:-9,78,0,23,-56,70
;图中pivot表示基准,假设基准=(0+5)/2=2
'一生二' 步骤如下:
递归开始
具体代码
public static void quickSort(int[] nums, int left, int right) {
int pivot = nums[(left + right) / 2];//基准找的中间的
int l = left;//基准左边的
int r = right;//基准右边
int temp = 0;//用于交换的临时变量
while (l < r) {//当索引下标基准左边的小于右边的,说明基准两边的值需要排序
while (nums[l] < pivot)//基准左边的值小于基准时,则不用交换,继续比较下一个,当基准左边的某个值大于基准时,跳出循环,此时l为需要交换的元素下标
l++;
while (nums[r] > pivot)//同理,同上
r--;
if (l == r)//如果当基准左右索引相等时,则退出当前循环,主要是(为了避免同一索引位置的交换)。
break;
temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
if (nums[l] == pivot)//为了避免重复执行上面两个while语句,(当只有两个元素进行比较交换后,那么就应该退出本次循环)
r--;
if (nums[r] == pivot)//同理,同上
l++;
System.out.println(Arrays.toString(nums));
}
r--;//上面的循环执行结束后,基准左小右大成立
l++;//必然l==r==pivot的下标,所以进行r--和l++是为了给左右递归做准备!
if (left < r)//当基准左边第一个r的索引大于0时,那么说明基准左边起码有≥2个值,需要再进行排序
quickSort(nums, left, r);//左递归
if (l < right)//同理,同上
quickSort(nums, l, right);//有递归
}
测试
before:2020/02/13 20:39:07:910
after:2020/02/13 20:39:09:310
800w数据(数据区间在0——1000w)排序:花了大概不到2s
时间复杂度:最坏情况:O(n^2) 最好情况:O(nlogn)
三向切分的快速排序(改进快排之一)
它的出现是对含有以任意概率分布的重复元素的输入进行优化。
基准为左边第一个元素,lt初始位置也是最左边,有一个索引i从基准右边开始遍历,如果发现nums[i]<基准,则进行交换并将lt和i加一;否则如果nums[i]>基准,那么就和右边gt指向的元素进行交换并且gt+1;如果nums[i]=基准,则i++跳过当前元素,进行下一次处理;
public static void sort(int[] nums,int l,int r){
if (r<=l)return;
int lt=l,i=l+1,gt=r;
int pivot=nums[l];
while(i<=gt){
int cmp=compare(nums[i],pivot);
if(cmp<0) exch(nums,lt++,i++);
else if(cmp>0) exch(nums,i,gt--);
else i++;
}
sort(nums,l,lt-1);
sort(nums,gt+1,r);
}
private static void exch(int[] nums,int i,int j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
private static int compare(int a,int b){
if(a<b)return -1;
else if(a>b) return 1;
else return 0;
}
* 对于包含大量重复元素的数组,它将排序时间从线性对数级降低到了线性级别!!!当存在重复元素时,三向切分无疑是最优的算法!