快速排序
1.快速排序
(1)主要思想
快速排序是一种改进的交换排序算法,是对冒泡排序算法的优化,快速排序的主要思想是分治思想:
- 任取一个元素作为中心pivot
- 所有比pivot小的元素都放在前面,比pivot大的元素都放在后面,形成左右两个子表
- 对各子表重新选择中心元素pivot,并仍然按照该规则进行调整(递归操作)
- 直到每个子表的元素都只剩一个,结束排序(递归结束)
关于pivot插入到中间,并将元素分为左右子表的实现细节(核心):
-
方案1:新数组用于存放数据(空间消耗较大)
- 新开一个数组用于存放数据,比pivot值大的元素放右边(从右向左),比pivot值小的元素放左边(从左向右),最后pivot值放到中间的空出的位置上,
-
方案2:减小使用的空间(只需要1个额外位置)以下是个人认为的快排的标准实现方式,
- 将pivot值存储到
idx=0
的下标位置,此时low位置可用 - 开始针对high指针,当high指针指向的值大于
nums[0]
时,将nums[high]
搬运到low
所指的位置,否则high--
- 开始针对low指针,当low指针指向的值小于
nums[0]
时,将nums[low]
搬运到high
所指的位置,否则low++
- 当
low = high
时,左右子表划分完毕,将pivot值重新放回到low = high
的位置,正式结束分表, - 特点:每一趟的子表的形成是采用从两头向中间交替式的逼近法。
- 将pivot值存储到
(2)局限性
快速排序局限性:
- 快速排序是所有内部排序方法中最好的一个
- 快速排序是一种不稳定的排序方法
- 快速排序不是原地排序(程序中使用了递归需要递归调用栈的支持,而栈的长度取决于递归调用的深度)
- 平均时间复杂度O(nlog2n):QSort—O(log2n)、Partition—O(n)
- 平均情况下需要使用O(logn)的栈空间,最坏情况下栈空间可以达到O(n)
- 快速排序不适用与对原本有序或基本有序的记录序列进行排序(划分元素值的随机性越好,排序速度越快,即非自然排序)
- 改变划分元素的选取方法,最多只能改变算法平均时间性能,无法改变最坏情况下的时间性能O(n2)
- 由于每次枢轴pivot记录的关键字都是大于其他所有记录的关键字,致使一次划分之后得到的子序列(1)的长度为0,这时的快速排序就已经退化成为了没有改进措施的冒泡排序了。
(3)快速排序模板
区间划分思路1:
- 将low值取出单独存放在pivot中,
- 对数组进行排序,排序方式为:当右侧比pivot小时将high覆盖low处值、当左侧比pivot大时将low覆盖high处
- 直到low与high相遇时,将pivot放回low与high相遇的位置
- 一轮排序完毕(pivot所在位置为最终有序位置)
- 递归处理左右两边区间
// pivot划分区间
int partition(SqList &sqlist, int low, int high) {
int pivot = sqlist.data[low];
while (low < high) {
while (sqlist.data[high] >= pivot && low < high) high--;
sqlist.data[low] = sqlist.data[high];
while (sqlist.data[low] <= pivot && low < high) low++;
sqlist.data[high] = sqlist.data[low];
}
sqlist.data[low] = pivot;
return low;
}
// 递归划分
void quick_sort(SqList &sqlist, int low, int high) {
if (low >= high) return;
int p_idx = partition(sqlist, low, high);
quick_sort(sqlist, low, p_idx - 1);
quick_sort(sqlist, p_idx + 1, high);
}
void quick_sort(SqList &sqlist, int low, int high) {
if (low >= high) return;
int pivot = sqlist.data[low];
int i = low, j = high;
while (i < j) {
while(sqlist.data[j] >= pivot && i < j) j--;
sqlist.data[i] = sqlist.data[j];
while(sqlist.data[i] <= pivot && i < j) i++;
sqlist.data[j] = sqlist.data[i];
}
quick_sort(sqlist, low, i - 1);
quick_sort(sqlist, i + 1, high);
}
区间划分思路2:
- 在low与hight的基础上再定义两个指针i、j,两个指针分别向中间移动
- 当 i 指针指向的数字小于pivot时,i 指针继续向右移动,直到 i 大于等于pivot时停下
- 当 j 指针指向的数字大于pivot时,j 指针继续向左移动,直到 j 小于等于pivot时停下
- 当 i、 j指针都停下时,若 i、j处于正常位置则交换对应值
- 否则表示while循环结束
- 递归处理左右两边区间
返回时要注意边界问题,low、high有可能会出现交叉的情况,
// pivot划分区间
int partition(SqList &sqlist, int low, int high) {
int pivot = sqlist.data[low];
low--; high++;
while (low < high) {
do low++; while(sqlist.data[low] < pivot);
do high--; while(sqlist.data[high] > pivot);
if (low < high) swap(sqlist.data[low], sqlist.data[high]);
}
return high;
}
//递归划分
void quick_sort(SqList &sqlist, int low, int high) {
if (low >= high) return;
int p_idx = partition(sqlist, low, high);
quick_sort(sqlist, low, p_idx);
quick_sort(sqlist, p_idx + 1, high);
}
void quick_sort(SqList &sqlist, int low, int high) {
if (low >= high) return;
int pivot = sqlist.data[low];
int i = low - 1, j = high + 1;
while (i < j) {
do i++; while (sqlist.data[i] < pivot);
do j--; while (sqlist.data[j] > pivot);
if (i < j) swap(sqlist.data[i], sqlist.data[j]);
}
quick_sort(sqlist, low, j);
quick_sort(sqlist, j + 1, high);
}
2.AcWing785.快速排序
#include <iostream>
using namespace std;
typedef struct {
int data[100005]; //表数据
int length; //顺序表长度
} SqList;
void quick_sort(SqList &sqlist, int low, int high);
int main() {
SqList sqlist;
cin >> sqlist.length;
for (int i = 0; i < sqlist.length; ++i) cin >> sqlist.data[i];
// sqlist.length = 5;
// int nums[5] = {3, 1, 2, 4, 5};
// for (int i = 0; i < sqlist.length; ++i) sqlist.data[i] = nums[i];
quick_sort(sqlist, 0, sqlist.length - 1);
for (int i = 0; i < sqlist.length; ++i) cout << sqlist.data[i] << " ";
cout << endl;
}
// 快速排序算法
int partition(SqList &sqlist, int low, int high) {
int pivot = sqlist.data[low];
while (low < high) {
while (sqlist.data[high] >= pivot && low < high) high--;
sqlist.data[low] = sqlist.data[high];
while (sqlist.data[low] <= pivot && low < high) low++;
sqlist.data[high] = sqlist.data[low];
}
sqlist.data[low] = pivot;
return low;
}
void quick_sort(SqList &sqlist, int low, int high) {
if (low >= high) return;
int p_idx = partition(sqlist, low, high);
quick_sort(sqlist, low, p_idx - 1);
quick_sort(sqlist, p_idx + 1, high);
}
3.AcWing786.第k个数
tips:文章内容参考acwing算法刷题课程,题解图示内容及代码根据老师课程、以及自己对知识的理解,进行二次整理和部分补充,仅供学习参考使用,不可商业化。