归并排序

归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

归并操作

归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

如 设有数列{6,202,100,301,38,8,1}

初始状态:6,202,100,301,38,8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

总的比较次数为:3+4+4=11,;

逆序数为14;

用途

排序

(速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列,应用见2011年普及复赛第3瑞士轮的标程)

求逆序对数

具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数(也可以用树状数组来求解).

对于原始的数组2,1,3,8,5,7,6,4,10,在整个过程执行的是顺序是途中红色编号1-20。虽然我们描述中说的是程序先分解,再归并,但实际过程是一边分解一边归并,前半部分分先排好序,后半部分再排好,最后整个归并为一个完整的序列,途中的merge过程它所在层的两个序列的merge过程:下图展示了每个merge过程对作用于数组的哪部分(红色)。

整个过程就像一个动态的树,执行顺序就是对树的先序遍历顺序。

 

C代码:

#include <stdio.h>

#include <stdlib.h>

 

void MergeArray(int a[], int temp[] , int start , int middle , int end)

{

     int i,j,s,m,e;

     i=start;

     s = start ;

     m = middle+1 ;

     e = end ;

    

     while((s <= middle)&&(m <= end))//因为包含开始和结束字符,所以用 <=

     {

         if(a[s] < a[m])

         {

              temp[i++] = a[s++] ;

         }

        

         else

         {

              temp[i++] = a[m++] ;

         }

     }

    

     while(s <= middle)

     {

         temp[i++] = a[s++] ;

     }

    

     while(m <= end)

     {

         temp[i++] = a[m++] ;

     }

    

     for(j = start ; j <= end ; j++)

     {

         a[j] = temp[j];

     }   

}

 

void MergeSort(int a[],int temp[],int start ,int end)

{

     int middle ;

     if(start < end)

     {

         middle = (start + end)/2 ;

         MergeSort(a , temp , start , middle);//通过递归层层划分,使左边有序

         MergeSort(a , temp , middle+1 , end);//右边有序

         MergeArray(a, temp , start , middle , end);//序列合并

     }

}

 

int main(int argc, char *argv[])

{

     int a[9] = {2,1,3,8,5,7,6,4,10};

     int temp[9] ;

     int i;

     MergeSort(a , temp , 0 ,8);

     for(i = 0 ; i <= 8 ; i ++)

     {

         printf("%d ",a[i]);

     }

     return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值