快速排序
作者:互联网
算法思路
- 每次都确定一个元素的最后位置,同时这个位置左边的数都是比它小,右边的数都是比它大
- 挖坑思路:
- 两个指针,一个left,一个right
- 每次大循环选一个元素flag(选最左边的,其实选什么都没关系),相当于挖了一个坑
- 我们要从右边找到一个比flag小的元素,填上这个坑
- 填上最初的坑,right的位置又多了一个新的坑,我们要从左边找出一个比flag大的元素,填上新的坑
- 循环直到left==right,这个位置就是flag最后的位置
- 再进行递归,分别flag左边的数组和右边的数组进行排序
书面概括
待排序的n个元素中任取一个元素(通常取第一个元素)作为枢轴(或支点),设其关键字为pivotkey。经过一趟排序后,把所有关键字小于pivotkey的元素交换到前面,把所有关键字大于pivotkey的元素交换到后面,结果将待排序记录分成两个子表,最后将枢轴放置在分界处的位置。然后,分别对左、右子表重复上述过程,直至每一子表只有一个元素时,排序完成。
其中,一趟快速排序的具体步骤如下。
- 选择待排序表中的第一个元素作为枢轴,把枢轴暂存在r[0]位置上。附设两个指针low和high,初始时分别指向表的下界和上界,(第一趟,low = 1;high = L.length)。
- 从表的最右侧位置依次向左搜索,找到第一个关键字小于枢轴关键字pivotkey的元素,将其移到low处。具体操作时:当low<high时,若high所指元素的关键字大于等于pivotkey,则向左移动指针high(执行操作:high--);否则将high所指元素与枢轴元素交换。
- 然后再从表的最左侧位置,依次向右搜索找到第一个关键字大于pivotkey的元素和枢轴元素交换。具体操作是:当low<high时,若low所指元素的关键字小于等于pivotkey,则向右移动指针low(执行操作:low++);否则将low所指元素与枢轴元素交换。
- 重复步骤2和3,直到low和high相等为止,此时low或high的位置即为枢轴在此趟排序中的最终位置,原表被分为两个子表。
在上述过程中,元素的交换都是与枢轴之间发生的,每次交换都要移动3次元素,可以先将枢轴元素暂存在r[0]位置上,排序过程中只需移动要与枢轴交换的元素,即只做r[low]和r[high]的单向移动,直至一趟排序结束后再将枢轴元素移至正确的位置。
考虑情况
排序过程会有三种情况
- 待排序元素大于有序序列中最大的元素;
- 待排序元素小于有序序列中的元素,但不小于有序序列中最小的元素;
- 待排序元素小于有序序列中最小的元素,但是因为监视哨的存在,2和3的情况归为一类。
算法效率
- 最好情况:待排序序列为顺序序列
- 比较次数KCN:n-1;
- 移动次数RMN:0;
- 最坏情况:待排序序列为逆序序列
- 比较次数KCN:2 + 3 + ... + n ≈ n²/2;
- 移动次数RMN:(2 + 1) + (3 + 1) + ... + (n + 1) ≈ n²/2;
所以时间复杂度为O(n²);
下面的代码是我按照自己的思路进行编写的,算法效率没有达到应有的程度。
空间复杂度为O(1),监视哨。
算法特点
- 稳定排序;
- 链式存储结构也适合;
- 更适合于初始记录基本有序(正序)的情况,当序列完全无序,尤其是逆序,且元素过多,时间复杂度会大大提高。
算法代码
#include <iostream>
#include <vector>
using namespace std;
void quickSort(vector<int>& v, int l, int r) {
if (l >= r) return;
int left = l, right = r;
int flag = v[l];
while (l < r) {
while (l < r && v[r] >= flag) r--;
v[l] = v[r];
while (l < r && v[l] <= flag) l++;
v[r] = v[l];
}
v[l] = flag;
quickSort(v, left, l-1);
quickSort(v, l+1, right);
}
int main() {
vector<int> v = { 49,38,65,97,76,13,27,49 };
quickSort(v, 0, v.size() - 1);
for (auto a : v) cout << a << " ";
cout << endl;
return 0;
}
运行结果
标签:位置,元素,枢轴,flag,low,排序,快速 来源: https://www.cnblogs.com/wasi-991017/p/11970495.html