快速排序 确定主元以及随机化 三路快排

快速排序时间复杂度为O(nlogn),由于每次主元所在次序并不一定是在数列中央,所以复杂度并不是确定的。

特殊的,当原数组排序程度越高的时候,快速排序时间复杂度会退化,当原数组完全有序时,快速排序时间复杂度退化成O(n^2)

       确定主元排序:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+5;
int a[maxn];
void quick_sort(int left,int right)
{
    if(left>=right) return;
    //选取主元
    int temp = a[left];
    int i = left;
    int j = right;
    while(i!=j)
    {
        while(a[j]>=temp&&i<j)
            j--;
        while(a[i]<=temp&&i<j)
            i++;
        swap(a[i],a[j]);
    }
    swap(a[left],a[i]);
    quick_sort(left,i-1);
    quick_sort(i+1,right);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    quick_sort(0,n-1);                //左闭右闭
    for(int i=0;i<n;i++)
        printf("%d%c",a[i],i==n-1?'\n':' ');
    return 0;
}

注意其中左闭右闭的写法,避免数组下标越界产生问题;

同时,要注意选定主元后,必须是先从后找小于主元的数,再从前找大于主元的数,这样是为了避免最后i和j相等的时候,主元交换了一个大于它的数,造成乱序错误;

      随机化主元:

//随机化快速排序
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+5;
int a[maxn];
int rand(int l,int r)
{
    srand(time(NULL));
    return rand()%(r-l+1)+l;
}
void quick_sort(int left,int right)
{
    if(left>=right) return;
    //随机选取主元,对于原数组有序程度高的情况下,时间复杂度会退化成O(n^2) 这时采用随机化算法使得复杂度稳定在O(nlogn)
    int k = rand(left,right);
    int temp = a[k];
    int i = left;
    int j = right;
    swap(a[left],a[k]);
    while(i!=j)
    {
        while(a[j]>=temp&&i<j)
            j--;
        while(a[i]<=temp&&i<j)
            i++;
        swap(a[i],a[j]);
    }
    swap(a[left],a[i]);
    quick_sort(left,i-1);
    quick_sort(i+1,right);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    quick_sort(0,n-1);                //左闭右闭
    for(int i=0;i<n;i++)
        printf("%d%c",a[i],i==n-1?'\n':' ');
    return 0;
}

三路快排:当重复元素过多的时候,快速排序时间复杂度会退化成O(n^2),这时采用三路快排,加入随机选取主元

参考博客:https://www.imooc.com/article/16141

//三路快排  +    随机选取主元     可以避免快速排序复杂度退化的问题
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000+5;
int rand(int l,int r)
{
    srand(time(NULL));
    return rand()%(r-l+1)+l;
}
void quick_sort(int l,int r,int *a,int len)
{
    if(l>=r) return;
    if(a==nullptr) return;
    //完成一次3路快排
    //随机选取主元
    int temp =*(a+rand(l,r));
    int rzero = l;                  //指向第一个temp元素位置   以及小于temp元素的边界位置
    int rone = l;
    int ltwo = r;                //指向下一个大于主元的数所存放的位置
    while(rone<=ltwo)
    {
        if(*(a+rone)==temp) {
            rone++;
        }
        else if(*(a+rone)<temp) {
            swap(*(a+rone),*(a+rzero));
            rzero++,rone++;
        }
        else if(*(a+rone)>temp) {
            swap(*(a+rone),*(a+ltwo));
            ltwo--;
        }
    }
    if(*(a+ltwo)==temp) ltwo++;
    if(rone>=len||nums[rone]!=temp) rone--;
    quick_sort(l,rzero-1,a);
    quick_sort(ltwo,r,a);
}
int main()
{
    int n,a[maxn];
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    quick_sort(0,n-1,a,n);
    for(int i=0;i<n;i++)
        cout<<a[i]<<" ";
    cout<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值