• 排序和顺序统计学(2)——快速排序


      快排我接触的也比较多了,从之前NOIP的时候算法老师讲的版本,到之前数据结构课上学习的版本,到现在《算法导论》里讲的版本,我个人并不能不能区别它们的好坏,权且都写出来,以后再来区别。三种实现方式如下:

    noip:

    void qsort1(int *a,int l,int r)
    {
    int i,j,mid,temp;
    i=l;j=r;mid=a[(i+j)/2];
    while(i<=j)
    {
    while(a[i]<mid) i++;
    while(a[j]>mid) j--;
    if(i<=j)
    {
    temp=a[i];a[i]=a[j];a[j]=temp;
    i++;j--;
    }
    }
    if(l<j) qsort1(a,l,j);
    if(i<r) qsort1(a,i,r);
    }

    思路即是选取中间数作为参考值,i,j分别从两端向另外一端枚举,然后从左边找到一个比它小的数,从右边找到一个比它大的数,互换位置,直到i,j位置互调,然后进行下一轮递归。

    数据结构:

    int partition(int *a,int l,int r)
    {
    int temp;
    while(l<r)
    {
    while(l<r&&a[l]>=flag) l++;
    temp=a[l];a[l]=a[r];a[r]=temp;
    while(l<r&&a[r]<=flag) l++;
    temp=a[l];a[l]=a[r];a[r]=temp;
    }
    return l;
    }
    void qsort2(int *a,int l,int r)
    {
    if(l<r)
    {
    int flag = partition(a,l,r);
    qsort2(a,l,flag-1);
    qsort2(a,flag+1,r);
    }
    }

    这个实现就是遇到大的就往后移,遇到小的就往前移。

    算法导论:

    int partition(int *a,int l,int r)
    {
    int i,j,x,temp;
    x=a[r];
    i=l-1;
    for(j=l;j<r;j++)
    if(a[j]<x)
    {
    i++;
    temp=a[i];a[i]=a[j];a[j]=temp;
    }
    temp=a[i+1];a[i+1]=a[r];a[r]=temp;
    return i+1;
    }
    void qsort3(int *a,int l,int r)
    {

    if(l<r)
    {
    int flag = partition(a,l,r);
    qsort3(a,l,flag-1);
    qsort3(a,flag+1,r);
    }
    }

    算法格式上来说,算法导论的版本与数据结构类似,但是思路上有些不同:算法导论是维护一个相邻的小队列,当发现队列右端的数比flag标签小时,就将它与队列中的一个数调换,这样可以轻易地将待排序数组分为四段:最左侧 l~i均小于flag,i+1~j均大于flag,j+1~r-1为未排序,r处即是flag标签。

      po完了三种版本的代码,再来谈一下快速排序,快排顾名思义就是非常快的排序,它是一种原地排序算法(不需要辅助数组),不稳定的,同时它的期望值是较为理想的O(nlgn),但最坏情况下会达到O(n^2)。

    下面讲述快排的几种优化方法。

      第一点,怎么变稳定。这个应该不难,就是添加一个标号数组,记录未排序时各元素的下标(b[i]=i),排序时加入双关键字(先按照大小排,大小相同按照标号排)即可,这种方法对于快速排序的时间复杂度影响不是很大,因此有必要时可以这样修改以适应不同情况。

      第二点,快速排序的最坏情况是O(N^2),即每次划分都划分成(1,n-1)这样的集合,这是我们无论如何也不想看到的情况。因此我们可以引入随机化快排。

    对于第一种版本,只要对mid进行小操作即可(mid=a[(l+r)/2]改为mid=a[random(l,r)])    //此处存疑,因为看了算法导论之后才清楚认识到快排的最坏情况是什么,这个算法每次将集合划分为等长的两部分,按理说深度是lgn的,但之前好多情况过不了题目,后来使用随机化确实过掉了。

    第二种版本我并不知道如何使用随机化-。-

    第三种版本则是在x的选择上动手脚(x=a[r]改为x=random(l,r);swap(a[x],a[r]);x=a[r];)这样就从l,r之间随机选择了一个数作为x,而不是原本的a[r]。

      第三点,跟归并排序的优化类似,就是在划分到足够小的集合时使用插入排序,这个在另一篇文章里已经说过了,应当将集合划分为lgn大小时使用插入排序,最好情况即此。

  • 相关阅读:
    一个表缺失索引发的CPU资源瓶颈案例
    SQLServer 版本之八大方法搞清 "我是谁"
    DBA成长路线
    SQL Server2016升级前几点自检
    SQL Server 2016白皮书
    <译>通过PowerShell工具跨多台服务器执行SQL脚本
    /lib64/libc.so.6: version `GLIBC_2.17' not found
    /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found
    HGT高程数据文件格式解析
    DEM高程数据下载资源
  • 原文地址:https://www.cnblogs.com/kangyun/p/4356735.html
Copyright © 2020-2023  润新知