一、基本思想
快速排序是一种分治算法,核心思想是:
🌷选定一个基准值(pivot):从数组中选择一个元素作为基准。
🌱分区(Partition):将数组分为两部分,使得左边部分的元素均 ≤ 基准值,右边部分的元素均 ≥ 基准值。
🪴递归排序:对左右两部分递归执行上述过程,直到子数组长度为1或0(已有序)。
二、关键步骤
以升序排序为例:
1.选择基准值:通常选第一个元素、最后一个元素或随机元素(本文以最后一个元素为例)。
分区操作:
2.初始化两个指针:i(指向小于基准的区域的末尾)、j(遍历数组)。
遍历数组,若当前元素 ≤ 基准值,则将其与i+1位置的元素交换,并移动i。
最后将基准值放到i+1的位置,此时基准值的位置已确定。
3.递归排序左右子数组。
三、性能分析
🧀时间复杂度
最优/平均情况:O(n log n),每次分区均匀划分。最坏情况:O(n²),当数组已有序或逆序时,每次分区极度不平衡(可通过随机选基准避免)。
🍙空间复杂度
递归调用栈的深度:最优O(log n),最坏O(n)。🍗稳定性
不稳定:分区过程中可能改变相同元素的相对顺序(如交换时跳过相同值)
四、示例代码
C/C++
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 选最后一个元素作为基准
int i = low - 1; // i 指向小于基准的区域的末尾
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr[i], arr[j]); // 交换到左边
}
}
swap(arr[i + 1], arr[high]); // 基准归位
return i + 1; // 返回基准位置
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1); // 递归左半部分
quickSort(arr, pi + 1, high); // 递归右半部分
}
}
Python
def partition(arr, low, high):
pivot = arr[high] # 选最后一个元素作为基准
i = low - 1 # i 指向小于基准的区域的末尾
for j in range(low, high):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i] # 交换到左边
arr[i + 1], arr[high] = arr[high], arr[i + 1] # 基准归位
return i + 1 # 返回基准位置
def quick_sort(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quick_sort(arr, low, pi - 1) # 递归左半部分
quick_sort(arr, pi + 1, high) # 递归右半部分
Java
int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // 选最后一个元素作为基准
int i = low - 1; // i 指向小于基准的区域的末尾
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
// 交换 arr[i] 和 arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 基准归位
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1; // 返回基准位置
}
void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1); // 递归左半部分
quickSort(arr, pi + 1, high); // 递归右半部分
}
}
五、典型例题
【问题描述】输入一组数据,以0作为输入的结束,分别采用冒泡排序、选择排序、快速排序的方法,对其进行从小到大的排序,给出排序后的结果。
【输入形式】一组数据,以0作为输入的结束
【输出形式】三种排序后的结果
【样例输入】
9 8 4 5 7 2 10 6 0
【样例输出】2 4 5 6 7 8 9 10
2 4 5 6 7 8 9 10
2 4 5 6 7 8 9 10
#include<iostream>
using namespace std;
// 输出数组函数
void output(int a[], int n)
{
for (int i = 0; i < n; i++)
cout << a[i] << ' '; // 输出数组元素,用空格分隔
cout << endl; // 换行
}
// 冒泡排序
void bubblesort(int a[], int n)
{
for (int i = 0; i < n - 1; i++) // 外层循环控制轮数
{
bool flag = false; // 标记本轮是否发生交换
for (int j = 0; j < n - 1 - i; j++) // 内层循环比较相邻元素
{
if (a[j] > a[j + 1]) // 如果前一个元素大于后一个元素
{
// 交换两个元素
int t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
flag = true; // 标记发生交换
}
}
if (flag == false) // 如果本轮没有发生交换,说明数组已经有序
return;
}
}
// 选择排序
void selectsort(int a[], int n)
{
for (int i = 0; i < n - 1; i++) // 外层循环控制当前位置
{
int k = i; // 假设当前位置是最小值的位置
for (int j = i + 1; j < n; j++) // 内层循环寻找最小值的位置
{
if (a[j] < a[k]) // 如果找到更小的元素
k = j; // 更新最小值的位置
}
if (k != i) // 如果最小值不在当前位置
{
// 交换最小值到当前位置
int x = a[i];
a[i] = a[k];
a[k] = x;
}
}
}
// 快速排序的分区函数
int Part(int a[], int low, int high)
{
int p = a[low]; // 选择第一个元素作为基准值
while (low < high) // 循环直到low和high相遇
{
while (low < high && a[high] >= p) // 从右向左找小于基准值的元素
--high;
a[low] = a[high]; // 将小于基准值的元素放到左边
while (low < high && a[low] <= p) // 从左向右找大于基准值的元素
++low;
a[high] = a[low]; // 将大于基准值的元素放到右边
}
a[low] = p; // 将基准值放到正确的位置
return low; // 返回基准值的位置
}
// 快速排序
void fastsort(int a[], int low, int high)
{
if (low < high) // 如果子数组长度大于1
{
int p = Part(a, low, high); // 分区并获取基准值的位置
fastsort(a, low, p - 1); // 递归排序左半部分
fastsort(a, p + 1, high); // 递归排序右半部分
}
}
int main()
{
int a[100]; // 定义数组存储输入数据
int n = 0; // 记录数组长度
for (int i = 0;; i++) // 循环读取输入
{
int x;
cin >> x; // 读取输入的数字
if (x == 0) // 如果输入为0,结束输入
break;
a[i] = x; // 将数字存入数组
n++; // 数组长度加1
}
// 冒泡排序并输出结果
bubblesort(a, n);
output(a, n);
// 选择排序并输出结果
selectsort(a, n);
output(a, n);
// 快速排序并输出结果
fastsort(a, 0, n - 1);
output(a, n);
return 0;
}