快速排序-原理:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
实现:
public static void quickSort(int[] array) {
quickSortHelper(array, 0, array.length - 1);
}
// [left, right] 前闭后闭区间. 针对当前范围进行快速排序
private static void quickSortHelper(int[] array, int left, int right) {
if (left >= right) {
// 区间中有 0 个元素或者 1 个元素
return;
}
// 返回值表示 整理之后, 基准值所处在的位置.
int index = partition(array, left, right);
// [left, index - 1]
// [index + 1, right]
quickSortHelper(array, left, index - 1);
quickSortHelper(array, index + 1, right);
}
private static int partition(int[] array, int left, int right) {
int baseValue = array[right];
int i = left;
int j = right;
while (i < j) {
// 1. 先从左往右找到一个大于基准值的元素
while (i < j && array[i] <= baseValue) {
i++;
}
// 此时 i 指向的位置要么和 j 重合, 要么就是一个比基准值大的元素
// 2. 再从右往左找到一个小于基准值的元素
while (i < j && array[j] >= baseValue) {
j--;
}
// 此时 j 指向的元素要么和 i 重合, 要么就是比基准值小的元素
// 3. 交换 i 和 j 的值
if (i < j) {
swap(array, i, j);
}
}
// 当整个循环结束, i 和 j 就重合了. 接下来就把 基准值 位置的元素交换到 i j 重合位置上.
// 此时 i 和 j 重合位置的元素一定是大于基准值的元素.
// 为啥 i 和 j 重合位置的元素一定大于基准值呢?
// 1) i++ 触发了和 j 重合, 上次循环中刚把 i 和 j 交换元素. 交换之后 j 一定是一个大于基准值的元素. i 再往 j 上靠, 结果也一定是指向大于基准值的元素
// 2) j-- 触发了和 i 重合, 此时 i 一定是指向一个大于基准值的元素(第一个 while 的功能)
swap(array, i, right);
return i;
}
private static void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
性能分析:
时间复杂度:
最好情况下:O(n*(logn))最坏情况下:O(n^2) 平均:O(n*(logn)
空间复杂度:
最好情况下:最好O(log(n)) 最坏:O(n) 平均:O(log(n))
稳定性:不稳定