zoukankan      html  css  js  c++  java
  • 排序——归并排序(分治法)

    在写归并排序之前,首先谈一谈分治的思想,

    所谓分治:就是将一个比较复杂的问题分解为若干个规模较小的但是类似原问题的子问题,(解决)递归地求解这些这些子问题,再合并这些子问题的解来求解原问题

    可分为三步:

    分解:将原问题分解为若干个规模较小的但是类似原问题的子问题

    求解:递归地求解这些这些子问题,然而若子问题规模足够小,可直接求解

    合并:合并这些子问题的解来求解原问题

    接下来,终于可以写归并排序了

    分解:将一个有N个数的数列分解为2个分别有n/2个数的2个子数列

    求解:使用归并排序递归地分别排序两个子数列;

    合并:将两个子数列合并并排好序

    根据上面的思路,归并排序的思路如下

    分解:N可能为奇数可能为偶数,要充分考虑到,mergesort函数如下

    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);
        }
        
    }

    注意,要考虑到p=r(p为一个数组中将要排序的起始项下标,r为一个数组中将要排序的终止项下标),若p=r,则根本不需要排序

    ,接下来,就是负责合并两个有序数列(注意:这里是一个循环不变式,先假设两个子数列都以排好序,起始:只有一个数,已排好序,不变:合并排序函数merge保证他们排好序,终止:递归结束),这里有两种方法:哨兵法和非哨兵法

    哨兵法:所谓哨兵就是在L数列和R数列尾部分别添加一个近乎无穷大的数防止在判断L[i]和[j]时越界

        int n1=q-p+1;
        int n2=r-q;
    
        int *L=(int*)malloc((n1+1)*sizeof(int));
        int *R=(int*)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)=ShaoBing;
        *(R+n2)=ShaoBing;
    
        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);

    非哨兵法:没有哨兵防止越界,就只能分    int n1=q-p+1    int n2=r-q    int *L=(int*)malloc((n1+1)*sizeof(int));    int *R=(int*)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)=ShaoBing;
        *(R+n2)=ShaoBing;
    
        int i=0,j=0;
        int k;
    
    /*
      依次从两个数字中取元素,将小的放入原数组中
    */    
        for(k=p;k<=r;k++) {
         if(i==n1)
          {
            while(j<n2)
            {
              *(A+k)=*(R+j);
                j++;
                k++;
            }
            break;
          }
        if(j==n2)
          {
            while(i<n1)
            {
              *(A+k)=*(L+i);
              i++;
              k++;
            }
            break;
          }
          
    if(*(L+i)<=*(R+j)) { *(A+k)=*(L+i); i++; } else { *(A+k)=*(R+j); j++; } } free(L); free(R);

    以上是我的思考路程,附上一篇博文,归并写得比较好,参考

    亲爱的听众朋友我是你的代班DJ
  • 相关阅读:
    grub.conf文件说明
    grub手动引导win7
    手动grub引导redhat
    grub的三种安装方式
    试题系列五(公鸡5元一只,母鸡3元一只,小鸡1元3只,求100元刚好买100只鸡的可能)
    试题系列四(袋中有6红球 3黄球 3绿球,从中取6个球,求所有拿到球的颜色的可能 c(12,6))
    试题系列三(求任意两个数的最大公约数)
    试题系列二(求1000内的完数)
    试题系列一(求4,5,6,7所有四位数的排列组合)
    pthread_cleanup_push和pthread_cleanup_pop清除函数是否执行的说明
  • 原文地址:https://www.cnblogs.com/YTYMblog/p/5342536.html
Copyright © 2011-2022 走看看