快速排序算法完整详解(原理+分步过程+代码+优化)
本文目录如下:
一、快速排序基本思想
快速排序是交换排序的一种,基于分治、递归思想,是冒泡排序的优化升级版。
核心思路:在序列中选取一个基准值(pivot),通过一趟排序,将数组分区,比基准值小的放左边,比基准值大的放右边。完成分区后,基准值就位。再对左右两个子区间递归重复分区操作,最终实现整体有序。
特点:每一轮排序确定一个基准值的最终位置,不像冒泡一样逐轮固定末尾最大值。
1、时间复杂度
基础版快排(固定左端基准)
- 最好情况(每次均分区间):O(nlogn)
- 最坏情况(有序/逆序数组):O(n²)
- 平均情况:O(nlogn)
优化版快排(随机/三数取中基准)
- 几乎杜绝最坏情况,日常稳定 O(nlogn)
- 平均、最好均为 O(nlogn)
2、空间复杂度
- 基础版、优化版:O(logn) ~ O(n)
- 解释:快排非原地排序(逻辑上原地),主要消耗递归栈空间;最优栈深度logn,最坏n
二、数组分步排序演示
待排序原始数组:3,9,-1,10,20
规则:默认选取最左侧元素为基准值,左指针找大值,右指针找小值,相遇交换,最终归位基准数。
第一轮分区(基准值 pivot = 3)
初始数组:【3,9,-1,10,20】
1、右指针先向左找小于3 的数:找到 -1
2、左指针向右找 大于3 的数:找到 9
3、交换 9 和 -1 → 数组:【3,-1,9,10,20】
4、左右指针继续移动,最终相遇在索引1位置
5、将基准值 3 与相遇位置的值交换 → 【-1,3,9,10,20】
第一轮结果:基准值3已归位,左边全部小、右边全部大
递归处理左右子区间
左区间:[-1],只有单个元素,天然有序,无需排序
右区间:[9,10,20]
对右区间重复选取基准、分区、递归操作:
1、以9为基准,分区后9归位,右侧剩余[10,20]
2、以10为基准,分区后10归位,剩余20天然有序
最终得到有序数组:[-1,3,9,10,20]
三、快速排序核心规律小结(适配快排特性)
1、快排不固定循环轮数,采用递归分治,不断划分子区间
2、每一次分区,仅确定基准值的最终位置
3、相较于冒泡每轮只能确定一个最值,快排一次分区可批量规整大量元素,效率极高
4、极端情况下(有序数组选最左为基准)会退化效率,需要针对性优化
四、基础版快速排序代码(单边递归+左右指针法)
public class QuickSort {
public static void main(String[] args) {
int[] arr = {3, 9, -1, 10, 20};
quickSort(arr, 0, arr.length - 1);
// 输出结果
for (int num : arr) {
System.out.print(num + " ");
}
}
// 快排递归方法
public static void quickSort(int[] arr, int left, int right) {
// 递归终止条件:区间只剩0/1个元素
if (left >= right) {
return;
}
// 得到基准值位置
int pivotIndex = partition(arr, left, right);
// 递归处理左区间
quickSort(arr, left, pivotIndex - 1);
// 递归处理右区间
quickSort(arr, pivotIndex + 1, right);
}
// 分区方法:返回基准值最终下标
public static int partition(int[] arr, int left, int right) {
int pivot = arr[left]; // 选最左为基准
int l = left;
int r = right;
while (l < r) {
// 右指针找比pivot小的
while (l < r && arr[r] >= pivot) {
r--;
}
// 左指针找比pivot大的
while (l < r && arr[l] <= pivot) {
l++;
}
// 交换左右指针元素
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
// 指针相遇,基准值归位
arr[left] = arr[l];
arr[l] = pivot;
return l;
}
}
五、快速排序优化方案(面试必考)
基础版缺陷:有序数组、逆序数组下,每次分区极不均衡,递归深度最大,算法退化严重,时间复杂度退化为 O(n²)。
优化方式:随机基准值 / 三数取中法,避免极端分区。
下面给出 随机选取基准优化版(工程常用、面试首选):
import java.util.Random;
public class QuickSort {
public static void main(String[] args) {
int[] arr = {3, 9, -1, 10, 20};
quickSort(arr, 0, arr.length - 1);
for (int num : arr) {
System.out.print(num + " ");
}
}
public static void quickSort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int pivotIndex = partitionRandom(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
// 优化:随机选取基准
public static int partitionRandom(int[] arr, int left, int right) {
// 随机下标
int randomIndex = new Random().nextInt(right - left + 1) + left;
// 交换到最左,复用原有分区逻辑
int temp = arr[left];
arr[left] = arr[randomIndex];
arr[randomIndex] = temp;
return partition(arr, left, right);
}
// 原有分区逻辑不变
public static int partition(int[] arr, int left, int right) {
int pivot = arr[left];
int l = left;
int r = right;
while (l < r) {
while (l < r && arr[r] >= pivot) r--;
while (l < r && arr[l] <= pivot) l++;
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
arr[left] = arr[l];
arr[l] = pivot;
return l;
}
}
六、面试核心总结(对标冒泡笔记结尾)
1、快排核心:分治+递归+左右分区,基准值归位
2、相比于冒泡O(n²),快排效率极高,是实战最常用排序
3、原生快排缺陷:有序数组会退化,必须随机基准优化
4、平均复杂度 O(nlogn) 的原因:绝大多数场景分区均衡,递归层数为logn
更多推荐


所有评论(0)