【数据结构】快速排序及优化

快速排序(Quicksort)是对冒泡排序的一种改进。

其基本思想是:选择一个基准,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比基准大,另外一部分的所有数据都要比基准小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

 

Partition()函数:

每次划分时,当满足判断条件low<high,

1.从high开始向前搜索,找一个比基准小的数数据,将其与基准交换

2.然后从low开始向后搜索,找一个比基准大的数据,将其放到high的位置上,

重复1,2  直到不满足low<high跳出循环,将基准放在low=high的位置上,返回基准的新位置。

//快速排序的一次划分
int Partition(int *arr,int low,int high)//O(n)(时),O(1)(空) 
{
    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;//low==high
    return low;
}

Quick()函数:

做为内部函数是为了完成一次封装,

对排序划分的递归调用,

先处理基准左边的数据,调用划分,基准左右两边至少有两个数据,才会调用划分

static void Quick(int*arr,int low,int high)//low为首位数据的指针,high为末位数据的指针
{
    int par = Partition(arr,low,high);
    if(low+1 < par)
//左边至少两个数据
    {
        Quick(arr,low,par-1);
    }

    if(par+1 < high)//右边至少两个数据
    {
        Quick(arr,par+1,high);
    }
}

对快排的一次包装,使其只有两个参数,与其他排序的参数一致

void QuickSort(int *arr,int len)//O(nlogn),O(logn),不稳定
{
    Quick(arr,0,len-1);
}

//非递归的快速排序
void QuickSort2(int *arr,int len)//O(n),O(logn),不稳定
{
    SeqStack s;
    InitStack(&s);
    int low = 0;
    int high = len-1;

    int par = Partition(arr,low,high);
    if(low+1 < par)
    {
        Push(&s,low);
        Push(&s,par-1);
    }

    if(par+1 < high)
    {
        Push(&s,par+1);
        Push(&s,high);
    }
    while(!IsEmpty(&s))
    {
        Pop(&s,&high);
        Pop(&s,&low);
        par = Partition(arr,low,high);
        if(low+1 < par)
        {
            Push(&s,low);
            Push(&s,par-1);
        }
        if(par+1 < high)

        {
            Push(&s,par+1);
            Push(&s,high);
        }

    }

    Destroy(&s);
}

对于优化

快排对于初始记录基本有序的情况下,快排与冒泡无异,

对于分治算法,当每次划分时,算法若都能分成两个等长的子序列时,那么分治算法效率会达到最大。也就是说,基准的选择是很重要的。选择基准的方式决定了两个分割后两个子序列的长度,进而对整个算法的效率产生决定性影响。

最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列

 

方法(1):随机选取基准(不重要)

引入的原因:在待排序列是部分有序时,固定选取枢轴使快排效率底下,要缓解这种情况,就引入了随机选取枢轴

   //基准选区

    srand((unsigned)time(NULL)); 

    int pivotPos;//基准

    pivotPos= rand()%(high - low) + low; 

 

方法(3):三数取中(median-of-three(优化有序的数据)

引入的原因:虽然随机选取枢轴时,减少出现不好分割的几率,但是还是最坏情况下还是O(n^2),要缓解这种情况,就引入了三数取中选取枢轴

。。。代码,之后再上

 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值