必学排序算法——快速排序

前言

快速排序算法是必须掌握的一种基础算法,在一些比较出名的竞赛acm、蓝桥杯,并且在一些公司面试题中都可能会出现,而且作为简单题我们必须要拿下,所以我们要引起重视,下面让我们来深入了解归并快速算法。
在这里插入图片描述

一、什么是快速排序

快速排序(Quick Sort)是一种高效的排序算法,采用分治法(Divide and Conquer)策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。

二、算法步骤

1.选择基准(Pivot):
从数组中选择一个元素作为基准。通常选择第一个元素、最后一个元素、中间元素或随机元素作为基准。

2.分区(Partitioning):
重新排列数组,所有比基准小的元素摆放在基准的前面,所有比基准大的元素摆在基准的后面(相同的数可以到任何一边)。在这个分区退出之后,该基准就处于数组的中间位置。

递归排序子数组:
递归地将小于基准值元素的子数组和大于基准值元素的子数组排序。

三、算法思想

第一步、选择基准元素:从数组中选择一个元素作为基准。​
第二步、分割数组:将比基准小的元素放在基准的左边,比基准大的元素放在基准的右边。​
第三步、递归排序:对基准左边和右边的子数组分别进行快速排序。​
重复步骤 一 至 三,直到子数组的长度为 1 或 0。

四、算法分析

时间复杂度
最优情况:当每次选择的基准元素正好将数组分成两等分时,快速排序的时间复杂度是 O(nlogn)。​
最坏情况:当每次选择的基准元素是最大或最小元素时,快速排序的时间复杂度是 O(n^2)。​
平均情况:在平均情况下,快速排序的时间复杂度也是 O(nlogn)。​

空间复杂度
快速排序的空间复杂度是 O(logn),因为在递归调用中需要使用栈来存储中间结果。这意味着在排序过程中,最多需要 O(logn) 的额外空间来保存递归调用的栈帧。

五、算法优点

1.高效性:快速排序在大多数情况下具有较高的排序效率。​
2.适应性:适用于各种数据类型的排序。​
3.原地排序:不需要额外的存储空间。​

六、算法缺点

4.最坏情况性能:在最坏情况下,快速排序的时间复杂度可能退化为 O(n^2)。​
5.不稳定性:快速排序可能会破坏排序的稳定性,即相同元素的相对顺序可能会改变。​

七、优化方案

6.选择合适的基准:选择合适的基准元素可以提高算法的性能。​
7.三数取中:通过选择中间元素作为基准,可以避免最坏情况的出现。​
8.分区的改进:可以使用双指针或其他方法来改进分区的过程,提高算法的效率。​
9.小数组使用插入排序:对于小数组,可以直接使用插入排序,避免不必要的递归。

八、c++代码模板

#include <iostream>  
#include <vector>  
  
// 分区函数,返回基准元素的最终位置  
int partition(std::vector<int>& arr, int low, int high) {  
    int pivot = arr[high]; // 选择最右边的元素作为基准  
    int i = low - 1; // i 是较小元素的索引  
  
    for (int j = low; j < high; ++j) {  
        if (arr[j] <= pivot) {  
            ++i;  
            std::swap(arr[i], arr[j]); // 交换元素  
        }  
    }  
    std::swap(arr[i + 1], arr[high]); // 把基准放到正确的位置  
    return i + 1;  
}  
  
// 快速排序的递归函数  
void quickSort(std::vector<int>& arr, int low, int high) {  
    if (low < high) {  
        int pi = partition(arr, low, high); // 获取分区索引  
        quickSort(arr, low, pi - 1); // 递归排序左子数组  
        quickSort(arr, pi + 1, high); // 递归排序右子数组  
    }  
}  
  
// 打印数组  
void printArray(const std::vector<int>& arr) {  
    for (int num : arr) {  
        std::cout << num << " ";  
    }  
    std::cout << std::endl;  
}  
  
int main() {  
    std::vector<int> arr = {10, 7, 8, 9, 1, 5};  
    int arr_size = arr.size();  
  
    std::cout << "Given array is \n";  
    printArray(arr);  
  
    quickSort(arr, 0, arr_size - 1);  
  
    std::cout << "\nSorted array is \n";  
    printArray(arr);  
    return 0;  
}

九、算法动态图解

在这里插入图片描述

十、经典真题

1.存在重复元素

(帅哥们这个蓝色字体可以点进去看原题)

代码题解

class Solution {
    int partition(vector<int>&a,int l,int r){
        int idx=l+rand()%(r-l+1);//rand最小值是0,所以idx的最小值是l,rand的最大值是r-l所以idx最大值是r
        swap(a[l],a[idx]);//idx这个值与这个范围最前面的值交换
        int i=l,j=r;
        int x=a[i];
        while(i<j){
            while(i<j&&a[j]>x)j--;//如果a[j]>x满足条件,j往前走;如果不满足条件就跳出循环
            if(i<j){//如果i<j说明这个区域没有遍历完
                swap(a[i],a[j]);
                i++;
            }
            while(i<j&&a[i]<x)i++;//同理满足a[i]<x条件,i往后走;不满足条件跳出循环
            if(i<j){
                swap(a[i],a[j]);
                j--;
            }
        }
        return i;
    }
    void quickSort(vector<int>&a,int l,int r){
        if(l>=r)return ;
        int pivox=partition(a,l,r);//找锚点
        quickSort(a,l,pivox-1);//从锚点的左部分继续找锚点
        quickSort(a,pivox,r);//从锚点右部分继续找锚点
    }
public:
    bool containsDuplicate(vector<int>& nums) {
        int n=nums.size();
        quickSort(nums,0,n-1);
        for(int i=1;i<n;i++){
            if(nums[i]==nums[i-1])return true;
        }
        return false;
    }
};

2.多数元素

(帅哥们这个蓝色字体可以点进去看原题)

class Solution {
    int partition(vector<int>&a,int l,int r){
        int i=l,j=r;
        int idx=l+rand()%(r-l+1);
        int x=a[idx];
        swap(a[l],a[idx]);
        while(i<j){
            while(i<j&&x<a[j])--j;
            if(i<j){
                swap(a[i],a[j]);
                i++;
            }
            while(i<j&&x>a[i])i++;
            if(i<j){
                swap(a[i],a[j]);
                j--;
            }
        }
        return i;
    }
    void quickSort(vector<int>&a,int l,int r){
        if(l>=r)return;
        int pivox=partition(a,l,r);
        quickSort(a,l,pivox-1);
        quickSort(a,pivox+1,r);
    }
public:
    int majorityElement(vector<int>& nums) {
        int n=nums.size();
        quickSort(nums,0,n-1);
        return nums[n/2];//排完序以后从n/2的下标开始后面的元素都是该值
    }
};

十、结语

学习算法是一个很艰难,漫长的过程,我们要克服一切困难,学习算法本就是由易到难,我相信通过我们坚持不懈的努力一定能理解并熟练掌握其中细节,加油。
在这里插入图片描述
关注我让我们一起学习编程,希望大家能点赞关注支持一下,让我有持续更新的动力,谢谢大家
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值