说明
是冒泡排序的升级
每次选择基准数,把小于基准数的放到基准数的左边,把大于基准数的放到基准数的右边,采用“分治思想”处理剩余的序列元素,直到整个序列变为有序序列。
算法效率提升
- 对于小段趋于有序的序列采用插入排序
- 三数取中法。旨在挑选合适的基准数,防止快排退化成冒泡排序。
- 随机数法。
时间空间复杂度
排序算法 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
快速排序 | O() | O() | O() | O() ~ O(n) | 不稳定 |
序列是有序的话再使用快速排序空间复杂度为O(n)
代码
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
// 快排分割处理函数
int Partation(int arr[], int begin, int end) {
int val = arr[begin]; // 选取基准数, 我们选择第一个元素
// 进行一次快排操作
while (begin < end) {
while (begin < end && arr[end] > val) {
// 从后往前找到第一个小于val的元素
end--;
}
if (begin < end) {
// 找到了,将右边的元素放到左边
arr[begin] = arr[end];
begin++; // 左边元素下标向右移动一位
}
while (begin < end && arr[begin] < val) {
// 从前往后找到第一个大于val的元素
begin++;
}
if (begin < end) {
// 找到了,将左边的元素放到右边
arr[end] = arr[begin];
end--; // 右边边元素下标向左移动一位
}
}
// begin == end的位置,就是存放基准数的位置
arr[begin] = val;
return begin;
}
void QuickSort(int arr[], int begin, int end) {
// 递归结束条件
if (begin >= end) {
return;
}
// 在[begin, end]区间的元素做一次快排分割处理
int pos = Partation(arr, begin, end); // pos为处理后基准数存放的位置
// 对基准数的左边和右边的序列再分别进行快排
QuickSort(arr, begin, pos - 1);
QuickSort(arr, pos + 1, end);
}
void QuickSort(int arr[], int size) {
return QuickSort(arr, 0, size - 1);
}
int main() {
int arr[10];
srand(time(nullptr));
for (int i = 0; i < 10; i++) {
arr[i] = rand() % 100 + 1;
}
for (int v : arr) {
cout << v << " ";
}
cout << endl;
QuickSort(arr, 10);
for (int v : arr) {
cout << v << " ";
}
cout << endl;
return 0;
}
测试
➜ build git:(quick-sort) ✗ ./QuickSort
91 77 90 78 41 2 95 55 5 64
2 5 41 55 64 77 78 90 91 95
快速排序优化
优化一
随着快速排序的进行,数据逐渐趋于有序,此时对于快速排序已不再有优势了。对于趋于有序的序列,使用插入排序效率会更高。所以说在一定的范围内,我们可以使用插入排序代替快速排序。
void QuickSort(int arr[], int begin, int end) {
// 递归结束条件
if (begin >= end) {
return;
}
// 优化一:
if (end - begin <= 5) { // 当序列的数据元素个数为5个以内的时候,调用插入排序
InsertSort(arr, end - begin);
return;
}
// 在[begin, end]区间的元素做一次快排分割处理
int pos = Partation(arr, begin, end); // pos为处理后基准数存放的位置
// 对基准数的左边和右边的序列再分别进行快排
QuickSort(arr, begin, pos - 1);
QuickSort(arr, pos + 1, end);
}
优化二
- middle = (L + R) / 2 , middle的位置。
- 采用
三数取中法(数值在中间的数)
,找合适的基准数。如果不找到一个合适的基准数的话会导致树的深度变大。