先讲经典快排。
荷兰国旗
从0 遍历到 n-1 ,num=5,第一个是 4 ,4 与 num 比较,当前数<= num ,把当前数,与小于等于区域中的下一个数交换。然后小于等于区域向右扩大一个位置。> num 的数,直接跳。
变种
有三个下标,一个是小于区域,一个是大于区域,一个是等于区域,叫 cur 。
遇到 cur =num,直接跳下一个。
遇到 cur < num,先和小于区域的下一个数交换,less + 1 ,cur +1.
遇到 cur > num 的数后,会与大于区域的前一个数交换。假设是 X ,然后大于区域向左移动一个位置,就是 more 向左移动一下。然后 cur 会停留在原地,考察这个 X 与 num 之间的大小关系。三种情况。
如果 cur 与 more 撞上 了,整个流程停止。(循环停止的条件)
开始一个数组,最后一个值作为划分值。
然后整个数组分为两个部分,<=X 的在左边,>=X 的在右边。
然后<=X 的当做一个全新的数组,再次把最后一个值当做划分值。两个部分拆分下去,让整个部分都有序。以上是经典快排。
改进:
=x 的部分不动,小于X 的区域和大于 X 的区域继续这样的过程——递归。
思路:
一个类三个方法,一个 quickSort 方法重载(判空,运行另一个重载方法),另一个 quickSort 方法重载(临界条件+接受 partition 方法的返回值+左右部分的递归)。
第二个方法是 swap 方法。
第三个方法是 partition 方法(返回的是一个数组,接受两个元素),设置小于大于的两个指针,less ,more 。while(L<more),三个 if 判断 L(cur)与 R (num) 的大小关系。最后交换边界值与 more 。最后返回一个只有两个元素的数组。
package suanfa;
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) { //默认在最后一个位置做划分,这个意思是num是最后一个值
if (L < R) { // 临界条件
//swap(arr,L+(int)(Math.random()*(R-L+1)),R); 这时一个随机快排
int[] p = partition(arr, L, R); //经过一个p过程,返回一个数组,是等于区域的左右两个边界
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; // less 是小于区域的 ,L 是 cur
int more = R; // more 意思是 num 是最后一个值,R 与 num 复用了
while (L < more) { //循环条件,只要左边界<右边界,循环下去
if (arr[L] < arr[R]) {
swap(arr, ++less, L++); //与 less 区域的下一个位置交换,
} else if (arr[L] > arr[R]) {
swap(arr, --more, L);
} else {
L++;
}
}
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;
}
public static void main(String[] args) {
int[] arr = { 0, 1, -94, 65, 888 };
System.out.println(java.util.Arrays.toString(arr));
quicksort(arr);
System.out.println(java.util.Arrays.toString(arr));
}
}
第二个重载方法中的停止循环的条件。小于区域<大于区域,停止。并且 if 逻辑贯穿整第二个 quickSort 方法。
patition中,声明了小于区域和大于区域。L < more,不是 < R ,因为 more 才是大于区域,R 是只是右边界。cur < more ,循环一直执行。
return 返回 new int[]{ less+1,more}, 是等于区域的边界。