归并排序和快速排序

Posted 勇士后卫头盔哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序和快速排序相关的知识,希望对你有一定的参考价值。

前言

之前文章提到过的希尔排序它有划时代的意义,打破了一个认知——排序算法的复杂度不可能超过O(n*n),之后各种各样更高效的排序算法就开始出现了,比如这次文章中提到的归并排序和快速排序

归并排序

基本思想:
两个或者两个以上的有序序列合并成一个新的有序序列,有序序列V[0]…V[m]和V[m+1]…V[n-1]合并成V[0]…V[n-1],这种归并方法称为2路归并,以此类推,将多个有序序列归并为一个新的有序序列,称为多路归并,特别注意的是,要归并的序列必须是有序的,如下图所示,归并排序其实是一个递归调用的过程,不断等分成2路压栈,到最后无路可分则合并出栈最后形成一个有序序列,递归出口为只有一个元素时,如80

归并排序的代码实现
可以看到无序序列被分成两有序部分,所以我们得开辟另一个数组来存放有序序列,首先8比16小,把8放在开辟数组的第一个元素,接着16比21小,把16放在开辟数组的第二个元素,然后21比37小,把21放在开辟数组的第三个元素…反复的进行,最后就在开辟的数组形成有序序列,最后将开辟的数组赋值到原来的无序数组

代码演示

  template <typename T>
static void Merge(T src[],T helper[],int begin,int mid,int end,bool min2max = true)
 
     int i=begin;
     int j=mid+1;
     int k=begin;
     /*将数据有序等存放到新数组helper*/
     while((i<=mid)&&(j<=end))
     
         if(min2max?src[i]<src[j]:src[i]>src[j])
         
             helper[k++] = src[i++];
         
         else
         
             helper[k++] = src[j++];
         
     
     /*若B部分先结束,则拷贝剩下的A部分到helper数组中*/
     while(i<=mid)
     
         helper[k++] = src[i++];
     
     /*若A部分先结束,则拷贝剩下的B部分到helper数组中*/
     while(j<=end)
     
        helper[k++] = src[j++];
     
     /*将helper数组拷贝到原来的数组*/
     for(i=begin;i<=end;i++)
     
         src[i] = helper[i];
     
 
 /*合并函数*/
 template <typename T>
 static void Merge(T src[],T helper[],int begin,int end,bool min2max = true)
 
     if(begin == end)
     
        return ;
     
     else
     
         int mid = (begin+end)/2;
         Merge(src,helper,begin,mid,min2max);//先递归2分,如图1的1-4的左边部分
         Merge(src,helper,mid+1,end,min2max);//先递归2分,如图1的1-4的右边部分
         Merge(src,helper,begin,mid,end,min2max);//合并最后的有序序列,如上图合并A,B部分
     
 
 /*合并函数*/
 template <typename T>
 static void Merge(T array[],int len,bool min2max = true)
 
     T* helper = new T[len];//申请有序序列数组
     if(helper != NULL)
     
         Merge(array,helper,0,len-1,min2max);//调用合并函数
     
     else
     
         delete []helper;
     

结果:

快速排序

基本思想
任取序列中的某个元素作为基准将整个序列划分为左右两个子序列,左侧子序列中所有元素都小于或等于j基准元素,右侧子序列中所有元素都大于基准元素,基准元素排在两个子序列中间,分别对这两个子序列重复进行划分,直到所有的数据元素都排在相应位置上为止,如下图所示,快速排序其实也是递归调用

下面为动画演示过程,首先我们选取21作为基准元素(pivot),比21小的元素放到21左边,比21大的元素放在21右边,此时就是基准就位了,继续左右两边的元素做快速排序…不断的递归快速排序直到找到递归出口,就是只剩下一个元素

代码演示

template <typename T>
/*基准算法*/
static int  Partition(T array[],int begin,int end,bool min2max)

    T pv = array[begin];
    while(begin<end)
    
        while((begin<end)&&(min2max?(array[end]>pv):(array[end]<pv)))
        
           end--;
        
        Swap(array[begin],array[end]);
        while((begin<end)&&(min2max?(array[begin]<=pv):(array[begin]>=pv)))
        
           begin++;
        
        Swap(array[begin],array[end]);
    
    array[begin] = pv;
    return begin;

/*排序函数,递归函数*/
template <typename T>
static void Quick(T array[],int begin,int end,bool min2max)

    if(begin<end)
    
        int pivot = Partition(array,begin,end,min2max);//调用基准函数划分
        Quick(array,begin,pivot-1,min2max);//快排基准左边
        Quick(array,pivot+1,end,min2max);//快排基准右边
    

template <typename T>
static void Quick(T array[],int len,bool min2max = true)

    Quick(array,0,len-1,min2max);

结果:

总结

归并排序需要额外的辅助空间才能完成,其空间复杂度为O(n),归并排序的时间复杂度为O(nlogn),是一种稳定的排序法,快速排序的时间复杂度为O(nlogn),一种不稳定的排序法

以上是关于归并排序和快速排序的主要内容,如果未能解决你的问题,请参考以下文章

python实现快速排序归并排序

python实现快速排序归并排序

python实现快速排序归并排序

排序 & 常用算法

js排序算法05——快速排序

Python实现希尔排序快速排序归并排序