QuickSort 拿下!

本文详细介绍了如何使用C++实现快速排序算法来求解将非负整数数组转换为最小数字的问题,包括快速排序的基本思路、递归实现、边界处理以及优化版的随机选取基准元素。通过实例演示了从初始代码到优化过程,适合深入理解快速排序和边界情况处理。
摘要由CSDN通过智能技术生成

剑指 Offer 45. 把数组排成最小的数
  输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

  由于这一题的解题思路是:首先将数组转换为字符数组,然后根据规则对其进行排序;排序的时候可以用到QuickSort(快速排序),又是一个没有系统研究过的tag,因此,特地对其进行一个仔细研究。
在这里插入图片描述

首先是代码

void QuickSort2(vector<int>& arr,int left,int right){
    //快速排序,每次选取第一个元素作为基准数据,将数组分为两个部分,
    //左边的元素都小于基准数据,右边的元素都大于基准数据。
    if(left>=right)
        return;
    int low=left;
    int high=right;
    while(low<high){
        while(low<high&&arr[high]>=arr[left])
            high--;
        while(low<high&&arr[low]<=arr[left])
            low++;
        swap(arr[low],arr[high]);
    }
    swap(arr[left],arr[low]);
    QuickSort2(arr,left,low-1);
    QuickSort2(arr,low+1,right);
}

然后是快速排序的思路

  例如 [49, 38, 65, 97, 23]
首先选取第一个元素49,将余下的元素按照大小关系分布在49的两边,我们可以规定:比49小,放在左边,比49大,放在右边;
   此时就是:[左边数组,49,右边数组]。这就是一次快速排列后的结果;
   紧接着,我们同样对左边数组、右边数组使用快速排列,直到最后数组里面只有一个元素,此时数组里面的顺序就完成了!
   思路就是这样,先不要想实现,思路你有了吗,是不是很easy!

最后是实现

  我们可以采用递归的思路,例如我们的函数是QuickSort();当我们调用的时候,先执行一次快排,这样我们就将数组按照大小关系分布在了第一个元素的左右两边,然后调用QuickSort(左边数组),QuickSort(右边数组);
我最开始的思路是这样的:

void QuickSort(vector<int>& arr,int left,int right){
    //快速排序,每次选取第一个元素作为基准数据,将数组分为两个部分,
    //左边的元素都小于基准数据,右边的元素都大于基准数据。
    if(left>=right)
        return;
    int low=left;
    int high=right;
    int tmp=arr[low];
    while(low<high){
        while(low<high&&arr[high]>=tmp)
            high--;
        arr[low]=arr[high];
        while(low<high&&arr[low]<=tmp)
            low++;
        arr[high]=arr[low];
    }
    arr[low]=tmp;
    QuickSort(arr,left,low-1);
    QuickSort(arr,low+1,right);
}

而后,才修改成了上述QuickSort2的形式,两种都大同小异;

边界问题

执行完一次快排后的情况

 此时 low=high ;但是,QuickSort2里面 swap(arr[left],arr[low]);,此时如果arr[low]>arr[left]的话,岂不是排了个寂寞?

    swap(arr[left],arr[low]);
    QuickSort2(arr,left,low-1);
    QuickSort2(arr,low+1,right);

不存在这种情况: low指向的一定是比arr[left]小的数据,所以,如果在low的后面有比arr[left]大的数据,一定会被high遍历淘汰。

递归最后满足什么条件退出?

 我们每次都是使用一个数据将数组分为两部分,然后对这两部分进行快速排列。

    QuickSort2(arr,left,low-1);
    QuickSort2(arr,low+1,right);

当由左右边界限定的数组长度小于2的时候,就可以退出了;当只有一个数的时候,显然不用排序,当left>right的时候,显然也不用,因为已经越界了
(越界的情况何时产生:例如[49,38,37,44,23],第一次快排后,low=high=4,此时调用: QuickSort2(arr,low+1,right);就会产生越界的情况)
在这里插入图片描述

c++完整代码

#include<iostream>
#include<vector>
using namespace std;

void QuickSort(vector<int>& arr,int left,int right){
    //快速排序,每次选取第一个元素作为基准数据,将数组分为两个部分,
    //左边的元素都小于基准数据,右边的元素都大于基准数据。
    if(left>=right)
        return;
    int low=left;
    int high=right;
    int tmp=arr[low];
    while(low<high){
        while(low<high&&arr[high]>=tmp)
            high--;
        arr[low]=arr[high];
        while(low<high&&arr[low]<=tmp)
            low++;
        arr[high]=arr[low];
    }
    arr[low]=tmp;
    QuickSort(arr,left,low-1);
    QuickSort(arr,low+1,right);
}

void QuickSort2(vector<int>& arr,int left,int right){
    //快速排序,每次选取第一个元素作为基准数据,将数组分为两个部分,
    //左边的元素都小于基准数据,右边的元素都大于基准数据。
    if(left>=right)
        return;
    int low=left;
    int high=right;
    while(low<high){
        while(low<high&&arr[high]>=arr[left])
            high--;
        while(low<high&&arr[low]<=arr[left])
            low++;
        swap(arr[low],arr[high]);
    }
    swap(arr[left],arr[low]);
    QuickSort2(arr,left,low-1);
    QuickSort2(arr,low+1,right);
}
int main(){
    vector<int> Arr={49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22};
    QuickSort2(Arr,0,Arr.size()-1);
    return 0;

}

快排的优化

  这几天又刷了LC912. 排序数组,没有想到官方不讲武德,测试集里面新增加了一个很长的有序数组,那么我之前写的快排就会退化为时间复杂度为O(N2) ,这个时候就需要对快排进行一个优化,就是每次不是选取第一个元素作为基准,而是随机选取;
只需要增加一句即可:

void QuickSort3(vector<int>& arr,int left,int right){
    //快速排序,每次选取第一个元素作为基准数据,将数组分为两个部分,
    //左边的元素都小于基准数据,右边的元素都大于基准数据。
    if(left>=right)
        return;
    //随机选取一个元素作为本次的基准
    //(right - left + 1) 总共有几个数 
    //rand() % (right - left + 1) 随机选取一个数
    //rand() % (right - left + 1) + left 这个数的实际下标
    int i = rand() % (right - left + 1) + left;
    swap(arr[left], arr[i]);
    int low=left;
    int high=right;
    while(low<high){
        while(low<high&&arr[high]>=arr[left])
            high--;
        while(low<high&&arr[low]<=arr[left])
            low++;
        swap(arr[low],arr[high]);
    }
    swap(arr[left],arr[low]);
    QuickSort2(arr,left,low-1);
    QuickSort2(arr,low+1,right);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值