版权声明:本文为博主原创文章,若需转载,请评论说明,并在文章显著位置标明原文出处。 https://blog.csdn.net/lishang6257/article/details/83037445
快速排序
- 接着主文章结构继续分析快速排序
- 快速排序实现主流上分为两种,第一种为快排的开山鼻祖 在1962年给出的,第二种是后来者给出的另一种实现方案。本文给出两种并非最原始的,而是经过随机化主元后给出的改进方案。
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int &a,int &b){int c = a;a = b;b = c;}
int partition(vector<int> &a,int low,int high)
{
//C. A. R. Hoare
srand(unsigned(time(NULL)));
int j = low + rand()%(high - low + 1);
swap(a[high],a[j]);
j = low;
for(int i = low;i < high;i ++){
if(a[i] <= a[high])swap(a[i],a[j++]);
}
swap(a[j ],a[high]);
return j ;
}
int partition2(vector<int>&a,int low,int high)
{
srand(unsigned(time(NULL)));
int j = low + rand()%(high - low + 1);
swap(a[high],a[j]);
int pivot = a[high];
while(low < high){
while(low < high && a[low] <= pivot){low ++;}
a[high] = a[low];
while(low < high && a[high] > pivot){high --;}
a[low] = a[high];
}
cout << low << " " << high << ";\n";
a[low] = pivot;
return low;
}
void quickSort(vector<int> &a,int low,int high)
{
if(low >= high) return ;
int pivot = partition(a,low,high);
quickSort(a,low,pivot-1);
quickSort(a,pivot+1,high);
}
int main()
{
vector<int> a = {1,40,10,4,5,8,9,1};
// cout << partition2(a,0,a.size()-1) << "|";
quickSort(a,0,a.size()-1);
for(auto c : a) cout << c << " ";
return 0;
}
-
思路引擎
-
快速排序是利用分治策略完成,分成三部曲:分解,解决,合并。
问题定义:将序列 非降序
分解:将序列 找到r,并使得 的元素均小于 , 均大于
解决:递归的调用快速排序算法,对 , 在进行排序
合并:所有子数组已经有序,无需进行合并操作。 -
如何分解子数组,使得满足分治的目的
方法一:- 空出首元素(首元素作为主元), 端 端向序列中间进行扫描;
- 对于 端元素,如果该元素小于 填补 端空缺位,那么该元素所占据的位置就成了空缺位,然后切换到 端;
- 对于 端元素,如果该元素大于 填补 端空缺位,那么该元素所占据的位置就成了空缺位,然后切换到 端;
- 若 端与 端相遇,那么相遇点一定是空缺位,再用主元元素填补就可以了。
方法二:
- 设置两个变量i、j,排序开始的时候:i=0,j=N-1;
- 以第一个数组元素作为关键数据,赋值给key,即key=A[0];
- 从j开始向前搜索,即由后开始向前搜索(j- -),找到第一个小于key的值A[j],将A[j]和A[i]互换;3. 从j开始向前搜索,即由后开始向前搜索(j- -),找到第一个小于key的值A[j],将A[j]和A[i]互换;
- 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
- 重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
方法二的描述引用自 百度百科-快速排序
-
时间复杂度
-
快速排序的时间复杂度与数组划分的效果有关,下面给出两个极端下的时间复杂度求解
- 当每次数组划分都只纯粹划分成长度为1和长度为
的两个部分,时间复杂度
- 当每次数组划分是都能划分成两个相等的部分,则时间复杂度可表示
这里由递归式求时间复杂度采用的主方法,感兴趣的可移步。
- 当每次数组划分都只纯粹划分成长度为1和长度为
的两个部分,时间复杂度
-
由于上面的分析可以看出数据的分布对快排的影响很大,为了尽量减少这方面的影响,我们在选取主元的时候尽量随机选择,而不是机械的选择最首或者最尾。这样快排的期望时间复杂度就变成了 ,具体的证明可以参考算法导论的相关内容。
-
-
稳定性分析
这边很容易可以看出快排是不稳定,原因和选择排序比较类似,我们在进行置换元素时,无法判定置换后的位置前方是否存在键值相同元素,换句话说在置换时无法确保相同键值元素的相对次序。