首先我们先来了解下快速排序的时间复杂度和稳定性分析,
快速排序的时间复杂度平均为o(n*logn)最优情况为o(n*logn)最差情况为o(n^2)
稳定性为不稳定的
然后让我们正式开始分析快速排序
首先我们要了解快速排序就要先理解三色旗问题:
有一条绳子上面挂有白、红、蓝三种颜色的多面旗子,这些旗子的排列是无序的。现在要将绳子上的旗子按蓝、白、红三种颜色进行归类排列,但是只能在绳子上进行旗子的移动,并且每次只能调换两个旗子。问如何采用最少的步骤来完成三色旗的排列呢?
对于这种问题我们就可以将0代表蓝色,1代表白色,2代表红色,放到数组里面进行排序,我们可以采用双指针,将蓝色全放到白色左面,红色全放到白色右面。接下来看下三色旗问题的解决代码
class Solution {
public:
void sortColors(vector<int>& nums) {
int left = 0-1,right = nums.size(),i = 0;//将left和right这么定义是为了下面快排处理边界值问题
while(i<right)
{
if(nums[i]>1)
{swap(nums[i],nums[--right]);//因为不能保证换过来的不是2所以此时i不能++
}
else if(nums[i]<1)
{
swap(nums[i++],nums[++left]);
}
else if(nums[i]==1){
i++;
}
}
}
};
此代码为力扣75.颜色分类的通过代码
可以看出三色旗的思想就是确定一个基准值,再将小于基准值的交换到基准值左面,将大于基准值交换到基准值右面
接下来我们带着三色旗的思想来看快速排序的代码
#include <iostream>
#include <vector>
using namespace std;
pair<int, int>Quick(vector<int>&nums,int L,int R)//将排序好的左右边界返回
{
int temp = nums[L];
int i = L - 1, j = R + 1,index = L;
while (index < j)
{
if(nums[index]>temp)
{
swap(nums[index], nums[--j]);
}
else if (nums[index] < temp)
{
swap(nums[index++], nums[++i]);
}
else if(nums[index] == temp)
{
index++;
}
}
return make_pair(i, j);
}
void Quick_sort(vector<int>&nums,int L,int R)
{
if(L>=R)return;
pair<int,int>a = Quick(nums, L, R);
//递归利用pair返回的左右边界,再将左右边界的子数组进行排序
Quick_sort(nums, L, a.first);
Quick_sort(nums, a.second, R);
}
void main()
{
vector<int>nums = { 5,6,4,3,2 };
Quick_sort(nums, 0, nums.size() - 1);
for (int it : nums)
{
cout << it << " ";
}
}
接下来我们以56432这个数组来举例
我们确定当前这次排序基准值为5,i和j的值最开始在数组的两边,目前nums[index]=temp执行index++;
此时nums[index]=6>temp,我们把6交换到数组右面;
接下来再看交换过来的数的大小1,发现此时<temp,我们把这个数交换到左边;
4也一样交换到左边
3也交换到左边
此时此次排序结束,我们发现当前数组最后排序的结果为24356,和最后结果23456,虽然整个数组的顺序没对,但是我们发现5的相对位置对了,接下来我们只要通过递归,将5的左右子数组进行排序,最后一定可以得到一个正确的顺序。