文章目录
一、经典快速排序
(一)、经典快速排序的实现理论
经典快速排序是用数组的最后一个数(这里记为 x )进行划分。也就是 <x、=x、>x。
- 有一个长度为 n 的数组 arr 。此时的数组的最后一个数为 arr[n - 1],我们根据 arr[n-1] 对数组进行排序。
- 设置一个变量 less 指向数组的第一个数的前一个位置(这里为 - 1),设置一个变量 more 指向数组的最后一个数 more(这里为 n - 1 )。设置一个变量 cur 指向数组当前数的位置。
- 对 arr[cur] 和 arr[n - 1]进行比较:
(1)如果 arr[cur] < arr[n - 1],交换 less 指向的数组的后一个数和arr[cur],然后 less 加 1(因为less划分的其实是 <x 的范围,此时 <x 范围内多个一个数,所以 less 需要加 1);
(2)如果 arr[cur] > arr[n - 1],交换 more 指向的前一个数和 arr[cur],然后 more 减 1 (因为more划分的其实是 >x 的范围,此时 >x 范围多了一个数,所以 more 需要 减 1);
(3)如果 arr[cur] = arr[n-1],less 和 more 不变
- 此时 cur 的数已经与 arr[n-1](数组的最后一个数)比较完毕,
(1)如果 arr[cur] < arr[n - 1] 或 arr[cur] = arr[n-1],cur 加 1,继续进行下一轮的比较;
(2)如果 arr[cur] > arr[n-1],cur 不变。(因为交换这两个数后,不知道交换过来的数的属于哪个范围(<x、=x、>x)),所以需要重新判定这个数属于哪个范围,cur 不变);
- 重复进行 3、4 步骤,直到 cur = more 结束(此时当前数组中所有的数已经比较完毕)。
(二)、经典快速排序的代码实现(Java)
/*
经典快速排序:用数组的最后一个数划分
*/
import java.util.Arrays;
public class JQuickSort {
public static void jQuickSort(int[] arr) {
if (arr == null || arr.length < 2) // arr == null 说明数组不存在,不用比较;
return; // 数组长度小于 2,说明数组只有 1 个数或者根本没有数,自然不用比较;
jQuickSort(arr, 0, arr.length - 1); // 对整个数组进行经典快速排序
}
public static void jQuickSort(int[] arr, int L, int R) {
// 如果L=R,说明此时数组只有一个数,不需要进行排序了。
if (L < R) {
// 获得 = x 的范围,数组 p 是一个长度为 2 的数组,里面存放着两个下标,分别为 =x 的第一个数下标和最后一个数的下标
int[] p = partition(arr, L, R);
jQuickSort(arr, L, p[0] - 1); // 对 < x 部分进行排序
jQuickSort(arr, p[1] + 1, R); // 对 > x 部分进行排序
}
}
public static int[] partition(int[] arr, int L, int R) {
int less = L - 1; // L 指向数组第一个数,最开始 < x 区域没有数,所以 less 指 L 的前一个位置
int more = R; // R 指向数组最后一个数,最开始 > x 区域没有数,所以 more 指向 R
while (L < more) {
if (arr[L] < arr[R]) {
swap(arr, L++, ++less);
} else if (arr[L] == arr[R])
L++;
else
swap(arr, L, --more);
}
// 交换 >x 的第一个数和数组的最后一个数,此时当前数组就是 <x、=x、>x
swap(arr, more, R);
return new int[] {less + 1 , more};
}
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[] a = {1, 2 ,4, 5, 4, 10, 2};
System.out.println(Arrays.toString(a));
jQuickSort(a);
System.out.println(Arrays.toString(a));
}
}
(三)、经典快速排序的时间复杂度
经典快速排序的时间复杂度为 O(N^2)。
每次都用数组的最后一个数进行划分,一次搞定排好一个数,所以时间复杂度为O(N),
一共有 N 个数,所以时间复杂度为 O(N^2)。
二、随机快速排序
(一)、随机快速排序的实现理论
随机快速排序与经典快速排序的区别就是:在数组中随机选一个数与最后一个数进行交换,对整个数组进行划分。
(二)、随机快速排序的代码实现(Java)
import java.util.Arrays;
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;
while (L < more) {
if (arr[L] < arr[R]) {
swap(arr, L++, ++less);
} else if (arr[L] > arr[R]) {
swap(arr, L, --more);
} else {
L++;
}
}
swap(arr, R, more);
return new int[] {less + 1, more};
}
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[] a = {1, 2 ,4, 5, 4, 10, 2};
System.out.println(Arrays.toString(a));
quickSort(a);
System.out.println(Arrays.toString(a));
}
}
(三)、随机快速排序的时间复杂度
随机快速排序由于每次划分的依据是从数组随机选出的,所以数据状况对它的影响减弱,所以时间复杂度为 O(N*logN)