本文正在参加「Java主题月 - Java 刷题打卡」,详情查看活动链接
一、前言
快速排序:是由东尼·霍尔提出的一种高效的排序算法,简称快排。
可以用 3 个步骤 6 个字来概括:选基、分割、递归:
-
选基:首先挑选基准值
-
分割:分割数组,把小于基准值的元素放到基准值前面,大于基准值的元素放到基准值后面
-
递归:递归地对小于基准值的子序列和大于基准值的子序列进行排序
举栗,动图如下:
为什么快排会比冒泡等快?
因为其是跳跃式交换,即每次交换相隔较远的 2个元素。
二、知识点
知识点,如下:
- 时间复杂度
- 逆序对
- 实现可分为两种:
Lomuto分割方法:实现简单,不易出错,效率差一些- 霍尔分割方法:减少交换
(1)时间复杂度
-
最好情况:时间复杂度
O(N * logN) -
最坏情况:时间复杂度
O(N ^ 2),增量元素不互质,则小增量可能根本不起作用 -
稳定性:不稳定。
例如,原数组
{4, 1, 4}不稳定:排序过程中,第二个
4排在了 第一个4前面。
排序总图,如图:
(2)逆序对
逆序对(inversion):对于下标 i < j,如果 arr[i] > a[j],则称 (i, j) 是一对逆序对。
举个栗子,序列 {34, 8, 64, 51, 32, 21} 有多少逆序对?
有9对:
(34, 8), (34, 32), (34, 21), (64, 51),
(64, 32), (64, 21), (51, 32), (51, 21), (32, 21)
可得定理:
- 定理:任意
N个不同元素组成的序列平均具有N(N-1)/4个逆序对 - 定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为
O(N^2)
那么逆序对,有什么用呢?
-
代表了,需要交换的次数。
-
为提高算法效率提供基础
那么要提高算法效率,必须:
-
每次消去不止 1个逆序对
-
每次交换相隔较远的 2个元素
(3)实现
1)Lomuto 分割方法
实现简单,不易出错,效率差一些。
基准线:以最高点
public class QuickSort {
// Time: O(n * log(n)), Space: O(n)
public void lomutoSort(int [] arr) {
if (arr == null || arr.length == 0) return;
lomutoSort(arr, 0, arr.length - 1);
}
private void lomutoSort(int [] arr, int low, int high) {
if (low < high) {
int k = lomutoPartition(arr, low, high);
lomutoSort(arr, low, k - 1);
lomutoSort(arr, k + 1, high);
}
}
private int lomutoPartition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low;
for (int j = low; j < high; ++j) {
if (arr[j] < pivot) {
swap(arr, i, high);
++i;
}
}
swap(arr, i, high);
return i;
}
private void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
2)霍尔分割方法
基准线:以中间点
public class QuickSort {
// Time: O(n * log(n)), Space: O(n)
public void hoareSort(int [] arr) {
if (arr == null || arr.length == 0) return;
hoareSort(arr, 0, arr.length - 1);
}
private void hoareSort(int [] arr, int low, int high) {
if (low < high) {
int k = hoarePartition(arr, low, high);
hoareSort(arr, low, k);
hoareSort(arr, k + 1, high);
}
}
private int hoarePartition(int [] arr, int low, int high) {
int pivot = arr[low + (high - low) / 2];
int i = low, j = high;
while (true) {
while (arr[i] < pivot) ++i;
while (arr[j] > pivot) --j;
if (i >= j) return j;
swap(arr, i++, j--);
}
}
private void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}