引用:本篇内容整理自王争老师《数据结构与算法之美》一书
核心思想
快速排序又成为快排(QuickSort),它主要利用分治和递归思想。
快排时间复杂度是O(nlogn),空间复杂度是O(1)。
假设有一个数组下标从 p 到 r :
首先选择任意一个数据做为基准点pivot,遍历 p 到 r 之间的数据,将小于pivot的数据放到左边,大于pivot的数据放到右边,最后把pivot放到中间。经过这个过程,原数组就变成了以pivot为分界点,左边是小于pivot的数,右边是大于pivot的数。
然后根据递归思想,我们将左边和右边数据进行递归调用排序方法,直到要排序数组区间为1时,说明数组已经有序了。
利用伪代码表示排序过程:
伪代码:
quick_sort(int[] array) {
quick_sort_c(array, 0, array.length - 1);
}
quick_sort_c(int[] array, int p, int r) {
if p >= r return;
//排序后返回pivot分区点位置
q = partition(array, p, r);
//分区点左边数据递归排序
quick_sort_c(array, p, q - 1);
//分区点右边数据递归排序
quick_sort_c(array, q + 1, r)
}
partition(int[] array, p, r) {
//通常选取左右边元素做为基准元素
pivot = array[r];
//使用下标 i 将数据分为两部分
//下标 p 到 i - 1 部分为小于基准点pivot的数据,称为已处理区间
//下标 i 到 r 成为未处理区间
//每次从 i 到 r中选取一个数据array[j] 与pivot比较
//如果小于pivot,则将array[j]加入到已处理区间尾部,也就是array[i]的位置
i = p;
for(j = p; j < r; j++) {
if (array[j] < pivot) {
//交换位置
swap array[i] with array[j];
i++;
}
}
//将基准数据pivot放到中间位置
swap array[i] with array[r];
return i;
}
完整代码
public static void main(String[] args) {
int[] arr = new int[]{1,5,2,8,6,3,12,9,7};
quickSort(arr,0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
/**
* 快速排序原理
* 1、选取最后一位为基准点
* 2、将小于基准点的数据放在左边
* 3、最后将基准点数据放入中间位置
* 4、基准点两边数据递归进行1、2、3步骤
* @param arr 待排序数组
* @param p 起始索引
* @param r 终点索引
*/
public static void quickSort(int[] arr, int p, int r) {
if(p >= r) {
return;
}
//将数组排序,返回中间基准点数据位置
int q = partition(arr, p, r);
quickSort(arr, p, q - 1);
quickSort(arr, q + 1, r);
}
/**
* 原地分区排序
* @param arr 数组
* @param p 起始索引
* @param r 终点索引
* @return 基准点索引
*/
private static int partition(int[] arr, int p, int r) {
int pivot = arr[r];
int i = p;
for (int j = p; j < r; j++) {
if (arr[j] < pivot) {
swap(arr, i, j);
i++;
}
}
swap(arr, i, r);
return i;
}
/**
* 交换指定下标位置元素
* @param arr 数组
* @param s 下标
* @param d 下标
*/
private static void swap(int[] arr, int s, int d) {
int temp = arr[s];
arr[s] = arr[d];
arr[d] = temp;
}