码迷,mamicode.com
首页 > 编程语言 > 详细

归并排序法

时间:2015-07-24 16:19:50      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:

  • 归并排序法简介

许多有用的算法在结构上都是递归的,这些算法遵循分治法的思想。将原问题分解成几个规模较小的但类似于原问题的子问题,然后地柜地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。

分治模式在每层递归上都有三个步骤:

——分解原问题为若干子问题,这些子问题是原问题的规模较小的示例;

——解决这些子问题,递归地求解这些子问题。然后,若子问题的规模足够小,则直接求解;

——合并这些子问题的解成原问题的解。

归并排序算法的操作完全遵循分治模式,其操作如下:

分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列;

解决:使用归并排序递归地排序两个子序列;

合并:合并两个已经排好序的子序列以产生已排序的答案。

当待排序的序列长度为1时,递归“开始回升”,在这种情况下不要做任何工作,因为长度为1的每个序列都已经排好序。

归并排序有两种方法去实现,一种是使用哨兵牌,即在两个子数组中的末尾放置一个无穷大的哨兵牌,进而可以避免每次去判断是否已经越界;第二种方法就是需要每次去检查是否已经到达数组的边界了。

  • 归并排序法的C语言实现

    方法一:哨兵牌法

    merge.c

  • /*
      本程序是归并法排序数组的两个部分
    */
    #include<stdio.h>
    #include<stdlib.h>
    
    /*
      为了避免比较,定义两个子数组的最后一位为无穷大,使得它比数组中任意一个数都大
    */
    #define infinity 10000 
    
    /*
      排序A(p,...q)和A(p+1,...r)两个数组,其中它们各自均已排好序
    */
    void merge(int *A,int p,int q,int r)
    {
        int n1=q-p+1;
        int n2=r-q;
    
        int *L=malloc((n1+1)*sizeof(int));
        int *R=malloc((n2+1)*sizeof(int));
    
        int t,tmp1=0,tmp2=0;
        for(t=p;t<=q;t++) {
            *(L+tmp1)=*(A+t);
            tmp1++;
        }
        for(t=q+1;t<=r;t++) {
            *(R+tmp2)=*(A+t);
            tmp2++;
        }    
        *(L+n1)=infinity;
        *(R+n2)=infinity;
    
        int i=0,j=0;
        int k;
    
    /*
      依次从两个数字中取元素,将小的放入原数组中
    */    
        for(k=p;k<=r;k++) {
            if(*(L+i)<=*(R+j)) {
                *(A+k)=*(L+i);
                i++;
            }
            else {
                *(A+k)=*(R+j);
                j++;
            }
        }
        free(L);
        free(R);
    }

    mergeSort.c

  • #include<stdio.h>
    #include<stdlib.h>
    
    void mergeSort(int *A,int p,int r)
    {
        if(p<r) {
            int q=(p+r)/2;
            mergeSort(A,p,q);
            mergeSort(A,q+1,r);
            merge(A,p,q,r);
        }
    }
  • 方法二:每次检查数组是否越界

    mergeSort方法同方法一,这里仅仅列出merge.c的不同实现代码:

  • /*
      本程序是用来不用哨兵法来检查数组的边界,而是普通的通过每次询问来判断是否已经到达边界
    */
    void merge1(int *A,int p,int q,int r)
    {
        int n1=q-p+1;
        int n2=r-q;
        
        int *L=malloc(n1*sizeof(int));
        int *R=malloc(n2*sizeof(int));
    
        int i,tmp1=0,tmp2=0;
    
        for(i=p;i<=q;i++) {
            *(L+tmp1)=*(A+i);
            tmp1++;
        }
        for(i=q+1;i<=r;i++) {
            *(R+tmp2)=*(A+i);
            tmp2++;
        }
    
        int count;
            int j=0,k=0;
    
        for(count=p;count<=r;count++) {
            if(j==n1) {
                while(k<n2) {
                    *(A+count)=*(R+k);
                    count++;
                    k++;
                }
                break;
            }
            if(k==n2) {
                while(j<n1) {
                    *(A+count)=*(L+j);
                    count++;
                    j++;
                }
                break;
            }
            if(*(L+j)<=*(R+k)) {
                *(A+count)=*(L+j);
                j++;
            }
            else {
                *(A+count)=*(R+k);
                k++;
            }    
        }
    }
  • 总结

    归并排序算法的代价是nlgn,其分析流程可以使用递归树来分析。归并法可以是许多相似问题的解决算法,我们可以借此联想或稍作变形即可解决类似问题。

归并排序法

标签:

原文地址:http://my.oschina.net/zzw922cn/blog/483338

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!