快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
Partition过程:
给定一个数组arr,和一个整数num。请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。
要求额外空间复杂度O(1),时间复杂度O(N)
这里的num是数组最右边的数字
public int partition(int[] arr, int left, int right) {
int num = arr[right];
int begin = left;
int end = right;
while (begin < end) {
while (begin < end && arr[begin] <= num) {
begin++;
}
while (begin < end && arr[end] >= num) {
end--;
}
swap(arr, begin, end);
}
swap(arr, begin, right);
return begin;
}
但是如果很多相等的数字,这种方法就不是很好
下面这个方式,是将等于num的数字放在中间,小于num的放在左边,大于Num的放在右边
// arr[L...R] 玩荷兰国旗问题的划分,以arr[R]做划分值
// <arr[R] ==arr[R] > arr[R]
public int[] netherlandsFlag(int[] arr, int left, int right) {
if (left > right) {
return new int[]{-1, -1};
}
if (left == right) {
return new int[]{left, right};
}
int less = left - 1;
int more = right;
int index = left;
while (index < more) {
if (arr[index] == arr[right]) {
index++;
} else if (arr[index] < arr[right]) {
swap(arr, index++, ++less);
} else {
swap(arr, index, --more);
}
}
swap(arr, more, right);
return new int[]{less + 1, more};
}
快排1.0版本:
package com.zy.base.class003;
import java.util.Arrays;
public class Code03_PartitionAndQuickSort {
public static void main(String[] args) {
int[] arr = {3, 1, 3, 2, 10, 8, 9, 6, 8, 6};
new Code03_PartitionAndQuickSort().quickSort1(arr);
System.out.println(Arrays.toString(arr));
}
public int partition(int[] arr, int left, int right) {
int num = arr[right];
int begin = left;
int end = right;
while (begin < end) {
while (begin < end && arr[begin] <= num) {
begin++;
}
while (begin < end && arr[end] >= num) {
end--;
}
swap(arr, begin, end);
}
swap(arr, begin, right);
return begin;
}
private void swap(int[] arr, int left, int right) {
int tmp = arr[left];
arr[left] =arr[right];
arr[right] = tmp;
}
// 快排递归版本
public void quickSort1(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process1(arr, 0, arr.length - 1);
}
private void process1(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int partition = partition(arr, left, right);
process1(arr, left, partition - 1);
process1(arr, partition + 1, right);
}
}
快速排序2.0版本
package com.zy.base.class003;
import java.util.Arrays;
public class Code03_PartitionAndQuickSort {
public static void main(String[] args) {
int[] arr = {3, 1, 3, 2, 10, 8, 9, 6, 8, 6};
// int partition = new Code03_PartitionAndQuickSort().partition(arr, 0, arr.length - 1);
// System.out.println(partition);
// new Code03_PartitionAndQuickSort().netherlandsFlag(arr, 0, arr.length - 1);
new Code03_PartitionAndQuickSort().quickSort2(arr);
System.out.println(Arrays.toString(arr));
}
// arr[L...R] 玩荷兰国旗问题的划分,以arr[R]做划分值
// <arr[R] ==arr[R] > arr[R]
public int[] netherlandsFlag(int[] arr, int left, int right) {
if (left > right) {
return new int[]{-1, -1};
}
if (left == right) {
return new int[]{left, right};
}
int less = left - 1;
int more = right;
int index = left;
while (index < more) {
if (arr[index] == arr[right]) {
index++;
} else if (arr[index] < arr[right]) {
swap(arr, index++, ++less);
} else {
swap(arr, index, --more);
}
}
swap(arr, more, right);
return new int[]{less + 1, more};
}
private void swap(int[] arr, int left, int right) {
int tmp = arr[left];
arr[left] =arr[right];
arr[right] = tmp;
}
// 快排递归版本
public void quickSort2(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process2(arr, 0, arr.length - 1);
}
private void process2(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int[] ints = netherlandsFlag(arr, left, right);
process2(arr, left, ints[0] - 1);
process2(arr, ints[1] + 1, right);
}
}
快速排序3.0
package com.zy.base.class003;
import java.util.Arrays;
public class Code03_PartitionAndQuickSort {
public static void main(String[] args) {
int[] arr = {3, 1, 3, 2, 10, 8, 9, 6, 8, 6};
// int partition = new Code03_PartitionAndQuickSort().partition(arr, 0, arr.length - 1);
// System.out.println(partition);
// new Code03_PartitionAndQuickSort().netherlandsFlag(arr, 0, arr.length - 1);
new Code03_PartitionAndQuickSort().quickSort3(arr);
System.out.println(Arrays.toString(arr));
}
// arr[L...R] 玩荷兰国旗问题的划分,以arr[R]做划分值
// <arr[R] ==arr[R] > arr[R]
public int[] netherlandsFlag(int[] arr, int left, int right) {
if (left > right) {
return new int[]{-1, -1};
}
if (left == right) {
return new int[]{left, right};
}
int less = left - 1;
int more = right;
int index = left;
while (index < more) {
if (arr[index] == arr[right]) {
index++;
} else if (arr[index] < arr[right]) {
swap(arr, index++, ++less);
} else {
swap(arr, index, --more);
}
}
swap(arr, more, right);
return new int[]{less + 1, more};
}
private void swap(int[] arr, int left, int right) {
int tmp = arr[left];
arr[left] =arr[right];
arr[right] = tmp;
}
public void quickSort3(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process3(arr, 0, arr.length - 1);
}
private void process3(int[] arr, int start, int end) {
if (start >= end) {
return;
}
swap(arr, start + (int) Math.random() * (end - start + 1), end);
int[] ints = netherlandsFlag(arr, start, end);
process3(arr, start, ints[0] - 1);
process3(arr, ints[0] + 1, end);
}
}