快速排序算法分析和实现

快速排序的思想:

选择一个基准元素,比基准元素小的放基准元素的前面,比基准元素大的放基准元素的后面,这种动作叫分区,每次分区都把一个数列分成了两部分,每次分区都使得一个数字有序,然后将基准元素前面部分和后面部分继续分区,一直分区直到分区的区间中只有一个元素的时候,一个元素的序列肯定是有序的嘛,所以最后一个升序的序列就完成啦

但是关于基准元素的选择有两种

1.第一种是每次都选序列的子序列的第一个元素(有缺陷)

2.第二种是每次都选择子序列中的第x个元素,x随机

普通快速排序

代码如下:

 

#include<bits/stdc++.h>
using namespace std;
#define n 5
int a[n];
void swap_t(int a[],int i,int j)
{
    int t=a[i];
    a[i]=a[j];
    a[j]=t;
}
int par(int a[],int p,int q)
{
    int i=p;//p是轴
    int x=a[p];//基准元素
    for(int j=p+1;j<=q;j++)
    {
        if(a[j]<=x)//升序
        {
            i++;
            swap_t(a,i,j);
        }
    }
    swap_t(a,p,i);
    return i;//轴位置
}
void QuickSort(int a[],int p,int q)
{
    if(p<q)//序列中元素个数大于1
    {
        int r=par(a,p,q);
        QuickSort(a,p,r-1);
        QuickSort(a,r+1,q);
    }
}
int main()
{
    int i;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    QuickSort(a,0,n-1);
    for(i=0;i<n;i++)
    {
        printf("%d\n",a[i]);
    }
    return 0;
}
View Code

算法分析:

1.最好情况:(每次分区时子序列中元素个数相同)

T(n)=2T(n/2)+O(n)=O(n*logn) log的底是2

2.最坏情况:序列是由大到小排序的

比如:7 6 5 4 3 2 1   -----> ( 进行依次分区,基准元素是7)  1 6 5 4 3 2 7,元素7的后面是没有元素的,同理 再将序列1 6 5 4 3 2分区,变成了1 2 5 4 3 6,分区6的后面也是没有元素的(7不属于这个分区),所以最坏情况的快速排序相当于冒泡排序了。。。。。。。有没有一种操蛋的感觉

T(n)=T(1)+T(n-1)+O(n)

      =T(1)+T(1)+T(n-2)+T(n-1)+O(n-1)+O(n) 

      继续变形下去

      T(常数)可以去掉

     T(n)=O(1)+O(2)+.......+O(n)//等差数列求和

      T(n)=O((1+n)*n/2)=n*n //常数可以省略

所以T(n)=n*n

3.一般情况:

T(n)=T(n/5)+T(4*n/5)+O(n) //假设前面分成1份后面分成4份这种情况

      =T(n/25)+T(4*n/25)+O(n/5)+T(4*n/25)+T(16*n/25)+O(4*n/5) 

我们假设T(n/5) 和T(4*n/5)展开成一颗树的形状,经过一系列比较复杂的推导之后(不好描述。。。。。)得到树的最大深度是log 5/4 n(底数的5/4),然后log 5/4 n 经过数学等价变形为log 2 n(底数为2)

然后又经过一系列复杂推导后(。。。。。。。。。。),树的最大宽度为:n

所以T(n)=n*log 2 n(底数为2)

总结:普通快排存在缺陷,缺陷在于每次基准元素的选择

二,改进之后的快速排序:随机化快速排序(每次随机在序列中选择基准元素),因为快排的性能取决于划分的对称性

附加知识:生成p,q之间的随机数:

方法:先生成随机数n,int i=n%(q-p+1)+p ,i就是p,q之间的随机数

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define n 5
int a[n];
void swap_t(int a[],int i,int j)
{
    int t=a[i];
    a[i]=a[j];
    a[j]=t;
}
int par(int a[],int p,int q)
{
    int i=p;//p是轴
    int x=a[p];
    for(int j=p+1;j<=q;j++)
    {
        if(a[j]<=x)
        {
            i++;
            swap_t(a,i,j);
        }
    }
    swap_t(a,p,i);
    return i;//轴位置
}
int Random(int p,int q)
{
    return rand()%(q-p+1)+p;
}
int Randomizedpar(int a[],int p,int q)
{
    int i=Random(p,q);
    swap_t(a,p,i);//第一个和第i个交换,相当于有了一个随机基准元素
    return par(a,p,q);
}
void RandomizedQuickSort(int a[],int p,int q)
{
    if(p<q)
    {
        int r=Randomizedpar(a,p,q);
        printf("%d到%d之间的随机数:%d\n",p,q,r);
        RandomizedQuickSort(a,p,r-1);
        RandomizedQuickSort(a,r+1,q);
    }
}
int main()
{
    int i;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    RandomizedQuickSort(a,0,n-1);
    for(i=0;i<n;i++)
    {
        printf("%d\n",a[i]);
    }
    return 0;
}
View Code

总结:快排虽然不稳定,但是高效(关于不稳定的概念请百度。。。)

    

有错误的地方麻烦大佬们指正!!!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值