快速排序算法(C++)实现

分治算法

快速排序本质上是一种分治算法。分治算法的思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,然后分而治之。

分治策略:对于一个规模为n的问题,若该问题可以容易的解决,则直接解决,否则将其分为k个规模较小的子问题。这些子问题互相独立并且与原问题形式相同,递归地解决这些子问题,然后将各子问题地解合并得到原问题地解。这种算法设计策略叫做分治法。

分治法基本步骤

  1. 分解:将原问题分解为若干个规模较小、相互独立、与原问题形式相同的子问题
  2. 解决:若子问题规模较小而容易被解决掉,则直接解决,否则递归的解决各个子问题。
  3. 合并:将各个子问题的解合并为原问题的解。

快速排序

将一组要排序的数据分割成独立地两个部分,其中一部分所有数据都比另一个部分的所有数据小,然后按照这个方法对这两个部分再进行快速排序,整个过程递归进行,最后使数据变成有序。

步骤

  1. 分解:从数列中选出一个元素作为基准元素,使基准元素左边的数据小于等于基准元素,右边的大于基准元素。
  2. 治理:对两个子序列快速排序
  3. 合并:将排好的子序列合并

基准元素选取

  • 选取第一个或者最后一个元素:数组已经有序的时候是一个效率很低的方法
  • 随机选一个数
  • 选中间的数
  • 三数取中:取第一个数、最后一个数和中间数中数值中间的那个数

快速排序代码

class Solution {
    
    
public:
    void quickSort(vector<int>&nums,int left,int right){
    
    
        int mid=nums[(left+right)/2];
        int i=left;
        int j=right;
        while(i<=j){
    
    
            while(nums[i]<mid) i++;
            while(nums[j]>mid) j--;
            if(i<=j){
    
    
                swap(nums[i],nums[j]);
                i++;
                j--;
            }
        }
        if(left<j) quickSort(nums,left,j);
        if(i<right) quickSort(nums,i,right);
    }
    vector<int> sortArray(vector<int>& nums) {
    
    
        quickSort(nums,0,nums.size()-1);
        return nums;
    }
};

运行结果

在这里插入图片描述

优化

参考快速排序三种方式以及快排的优化

  1. 当待排序序列的长度分割到一定大小之后,使用插入排序
  2. 在依次排序之后,可以将与基准值相等的数放在一起,下次分割的时候不考虑这些数。
  3. 优化尾递归

复杂度和稳定性

时间复杂度

最好情况

每次划分所选的关键数据为所在序列的中位数,经过
log ⁡ 2 n \log_2n log2n 趟划分就可以得到长度为1的子序列,时间复杂度为
O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

最坏情况

每次划分所选择的关键数据为所在序列最大或者最小,需要n趟划分
O ( n 2 ) O(n^2) O(n2)

平均时间复杂度

O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

空间复杂度

最优

每一次都平分数组
O ( l o g n ) O(logn) O(logn)

最差

退化为冒泡排序
O ( n ) O(n) O(n)

稳定性

参考深刻剖析快速排序为什么不稳定
不稳定

不稳定的原因

  1. 选取基准数字时随机选择
  2. 在遍历过程中,将小于基准的数字与第一个大于基准的数字位置交换
  3. 在每次遍历完后,将头部的基准数字与最后一个小于基准的数字交换位置

使算法稳定

使用额外辅助空间,此时空间复杂度将会变成O(logn+n)

猜你喜欢

转载自blog.csdn.net/qaaaaaaz/article/details/130039402
今日推荐