This commit is contained in:
krahets
2023-08-19 22:07:27 +08:00
parent 71c7786f51
commit 2e27ad1680
99 changed files with 283 additions and 283 deletions
+6 -6
View File
@@ -2,7 +2,7 @@
comments: true
---
# 11.5.   快速排序
# 11.5   快速排序
「快速排序 Quick Sort」是一种基于分治思想的排序算法,运行高效,应用广泛。
@@ -360,7 +360,7 @@ comments: true
}
```
## 11.5.1.   算法流程
## 11.5.1   算法流程
1. 首先,对原数组执行一次「哨兵划分」,得到未排序的左子数组和右子数组。
2. 然后,对左子数组和右子数组分别递归执行「哨兵划分」。
@@ -586,13 +586,13 @@ comments: true
}
```
## 11.5.2.   算法特性
## 11.5.2   算法特性
- **时间复杂度 $O(n \log n)$ 、自适应排序** :在平均情况下,哨兵划分的递归层数为 $\log n$ ,每层中的总循环数为 $n$ ,总体使用 $O(n \log n)$ 时间。在最差情况下,每轮哨兵划分操作都将长度为 $n$ 的数组划分为长度为 $0$ 和 $n - 1$ 的两个子数组,此时递归层数达到 $n$ 层,每层中的循环数为 $n$ ,总体使用 $O(n^2)$ 时间。
- **空间复杂度 $O(n)$ 、原地排序** :在输入数组完全倒序的情况下,达到最差递归深度 $n$ ,使用 $O(n)$ 栈帧空间。排序操作是在原数组上进行的,未借助额外数组。
- **非稳定排序**:在哨兵划分的最后一步,基准数可能会被交换至相等元素的右侧。
## 11.5.3.   快排为什么快?
## 11.5.3   快排为什么快?
从名称上就能看出,快速排序在效率方面应该具有一定的优势。尽管快速排序的平均时间复杂度与「归并排序」和「堆排序」相同,但通常快速排序的效率更高,原因如下:
@@ -600,7 +600,7 @@ comments: true
- **缓存使用效率高**:在执行哨兵划分操作时,系统可将整个子数组加载到缓存,因此访问元素的效率较高。而像「堆排序」这类算法需要跳跃式访问元素,从而缺乏这一特性。
- **复杂度的常数系数低**:在上述三种算法中,快速排序的比较、赋值、交换等操作的总数量最少。这与「插入排序」比「冒泡排序」更快的原因类似。
## 11.5.4.   基准数优化
## 11.5.4   基准数优化
**快速排序在某些输入下的时间效率可能降低**。举一个极端例子,假设输入数组是完全倒序的,由于我们选择最左端元素作为基准数,那么在哨兵划分完成后,基准数被交换至数组最右端,导致左子数组长度为 $n - 1$ 、右子数组长度为 $0$ 。如此递归下去,每轮哨兵划分后的右子数组长度都为 $0$ ,分治策略失效,快速排序退化为「冒泡排序」。
@@ -1053,7 +1053,7 @@ comments: true
}
```
## 11.5.5.   尾递归优化
## 11.5.5   尾递归优化
**在某些输入下,快速排序可能占用空间较多**。以完全倒序的输入数组为例,由于每轮哨兵划分后右子数组长度为 $0$ ,递归树的高度会达到 $n - 1$ ,此时需要占用 $O(n)$ 大小的栈帧空间。