深入理解快速排序

我们知道快排的核心思想是选取一个基准值,通常我们总是选取最左边的元素作为基准值,并以这个基准值来将数组划为两部分,左边部分为小于基准值,右边部分为小于基准值。
但往往我们的数组并不是那么理想的乱序如

  • 数组为基本有序的,只有少数元素是有序的
    • 此时我们选取最左边的元素作为基准值就可能照成数组的两部分极度不平衡
    • 解决办法
      • 每次选取基准值时选取一个·随机值
  • 数组存在大量的重复元素
    • 此时使用也可能照成数组的两部分极度不平衡
  1. 单路快排
//单路快排
void quickSort(vector<int> &arr,int l,int r)
{
    if(arr.size() <= 1)
        return ;
    if(l >= r)
        return ;
    //避免有序情况下两边极度不平衡
    swap(arr[l],arr[rand()%(r-l+1)]);
    int j = l;
    int v = arr[l];
    for(int i = l+1;i <= r;i++)
    {
        if(arr[i] < v)
        {
            j ++;
            swap(arr[j],arr[i]);
        }
    }
    swap(arr[l],arr[j]);

    quickSort(arr,l,j-1);
    quickSort(arr,j+1,r);
  1. 双路快排
//双路快排
void quickSort2(vector<int> &arr,int l,int r)
{
    if(arr.size() <= 1)
        return ;
    if(l >= r)
        return ;
    swap(arr[l],arr[rand()%(r-l+1)]);
    int i = l+1;
    int j = r;
    while(true)
    {
        while(i <= r && arr[i] < v)
            i++;
        while(j >= l+1 && arr[j] > v)
            j--;
        if(i > j)
            break;
        swap(arr[i++],arr[j--]);
    }
    swap(arr[l],arr[j]);
    quickSort2(arr,l,j-1);
	quickSort2(arr,j+1,r);

}

  1. 三路快排
//三路快排
void quickSort3(vector<int> &arr,int l,int r)
{
    if(arr.size() <= 1)
        return ;
    if(l >= r)
        return ;
    swap(arr[l],arr[rand()%(r-l+1)]);
    int lt = l;
    int gt = r+1;
    int v = arr[l];
    int i = l+1;
    while(i < gt)
    {
        if(arr[i] < v)
        {
            swap(arr[++lt],arr[i++]);
        }
        else if(arr[i] > v)
        {
            swap(arr[--gt],arr[i]);
        }
        else
            i++;

    }
    swap(arr[l],arr[lt]);
    quickSort3(arr,l,lt-1);
    quickSort3(arr,gt,r);

}

一般来说我们的双路快排就能解决上述问题,我们标准库体供的sort()一般使用三路快排。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值