什么是快速排序?
快速排序(Quick Sort)是一种高效的排序算法,采用"分治"策略。它的核心思想是:选择一个基准值(pivot),将数组分成两部分,一部分比基准值小,另一部分比基准值大,然后递归地对这两部分进行排序。
为什么选择前后指针法?
在快速排序的几种实现方法中(Hoare版本、前后指针、挖坑法),前后指针法相对容易理解。
前后指针法思路
- 选择最左边的元素作为基准值(key)
- 定义两个指针:prev(慢指针)和cur(快指针)
- cur先移动,如果cur指向的元素小于key,prev就前进并交换prev和cur指向的元素
- 当cur走到数组末尾,将key与prev指向的元素交换
- 递归处理key左边和右边的子数组
C语言实现代码
cpp
#include <stdio.h>
// 交换两个元素的值
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 快速排序函数
void quickSort(int arr[], int left, int right) {
// 递归终止条件:子数组长度小于等于1
if (left >= right) {
return;
}
// 选择最左边的元素作为基准值
int key = arr[left];
int prev = left; // 慢指针
int cur = left + 1; // 快指针
// cur移动,prev跟随
while (cur <= right) {
// 如果cur指向的元素小于基准值
if (arr[cur] < key) {
prev++; // prev前进
swap(&arr[cur], &arr[prev]); // 交换cur和prev指向的元素
}
cur++; // cur总是前进
}
// 将基准值放到正确位置
swap(&arr[left], &arr[prev]);
// 递归排序左右子数组
quickSort(arr, left, prev - 1);
quickSort(arr, prev + 1, right);
}
// 打印数组
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr) / sizeof(arr[0]);
printf("原始数组: ");
printArray(arr, n);
quickSort(arr, 0, n - 1);
printf("排序后数组: ");
printArray(arr, n);
return 0;
}
-
swap函数:用于交换两个元素的值,是排序中常用的操作。
-
quickSort函数:
left
和right
表示当前要排序的子数组的左右边界- 选择最左边的元素作为基准值
key
prev
从基准值后一个位置开始,cur
从prev
的下一个位置开始cur
向前移动,如果遇到比key
小的元素,prev
就前进并交换prev
和cur
指向的元素- 当
cur
走到数组末尾,将key
与prev
指向的元素交换
-
递归 :将数组分成两部分,分别对左右子数组递归调用
quickSort
。
快速排序的执行过程(以10, 7, 8, 9, 1, 5为例)
- 选择10作为基准值
- 从左到右遍历:7、8、9都比10小,1和5也比10小
- 遍历完成后,10应该放在第5个位置(索引4)
- 交换10和1,得到[1, 7, 8, 9, 10, 5]
- 递归排序[1, 7, 8, 9]和[5]
时间复杂度
最佳情况:O(n log n) - 每次都能将数组分成两个相等的子数组
最坏情况:O(n²) - 数组已经基本有序,每次只能减少一个元素
平均情况:O(n log n)。
1.递归的终止条件if (left >= right)
很重要,避免无限递归。
2.注意cur
的边界条件,要小于等于right
3.基准值的选择影响排序效率,这里选择最左边的元素是简化实现