归并排序自顶向下和自底向上分析及实现

自顶向下

归并排序分为两步:划分和归并

划分

排序思路:通过递归调用不断地将原始数组进行左右划分,直到划分成只有一个元素时停止,然后return,然后开始合并,其实排序的实现还是在merge里面实现的

 public void sort(int [] a)
    {
        aux=new int[a.length];//一次性分配空间
        sort(a,0,a.length-1);//
    }
    public void sort(int a [],int low,int high)//排序
    {
        for(int i=low;i<=high;i++)
            System.out.print(a[i]+" ");
        System.out.println();
     if(high<=low)//划分得每个子数组只有一个元素了
         return;
     int mid=low+(high-low)/2;//再次确定划分得界限
        sort(a,low,mid);//将左半部分排序
        sort(a,mid+1,high);//将右边部分排序
        merge(a,low,mid,high);//开始合并
        System.out.print("merge:");
        for(int i=low;i<=high;i++)
            System.out.print(""+a[i]+" ");
        System.out.println();
    }

合并

进行合并的两个子数组本身已经是有序的了,在合并是采用一个额外的辅助数组先复制原数组的值,然后进行归并。先设置两个下标i,j,i指向左部第一个元素,j指向右部第一个元素,刚开始时第一个if和第二个if语句一般不满足条件,所以执行的是后面的两个if语句,以数据7 8 9 ‘ 1 2 3为例,右部的元素一直小于左部元素,因此前面取得就是 1 2 3,当右边的元素取完了,此时j>hi,所以第2个if语句条件满足,然后直接取左部元素7 8 9,最后的得到1 2 3 7 8 9。

public void merge(int a[],int low,int mid,int high)//归并
   {
       int i=low;
       int j=mid+1;
       for(int k=low;k<=high;k++)
           aux[k]=a[k];
       for(int k=low;k<=high;k++)
       {
           if(i>mid) //左边已经用尽,开始取右半边元素
               a[k]=aux[j++];
           else if(j>high)//右边已经用尽,开始取左半边元素
               a[k]=aux[i++];
           else if(aux[j]<aux[i])//右半边元素小于左半边元素,取右半边元素---升序
               a[k]=aux[j++];
           else //左半边元素小于右半边元素,取左半边元素---升序
               a[k]=aux[i++];
       }
   }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从运行结果中可以看出,刚开始一直划分,直到划分到单个元素 16 15时停止,然后归并成15 16,然后再将14 13划分成单个元素14 13,然后归并成13 14,然后再归并成13 14 15 16,接着同样的步骤处理12 11 10 9…

自底向上

不再像自顶向下那样逐次划分,直接对长度为1 2 4 8 …的子数组进行合并

 public void sort_from_bottom_to_top(int a[])
   {
       int N=a.length;
       aux=new int[a.length];//一次性分配空间
       for(int sz=1;sz<N;sz=sz+sz)//sz为子数组的大小
           for(int lo=0;lo<N-sz;lo+=sz+sz)//lo为子数组索引
               merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1,N-1));
   }

在这里插入图片描述
自底向上的归并排序会多次遍历整个数组,根据子数组的大小进行两两归并。子数组的大小sz的初始值为1,每次加倍。最后一个子数组的大小只有在数组的大小是sz的整数倍的时候才会等于sz,否则它会比sz小。

完整代码

public class test{
    int [] aux;//归并时所需的辅助数组
    public void sort(int [] a)
    {
        aux=new int[a.length];//一次性分配空间
        sort_from_top_to_bottom(a,0,a.length-1);//
    }
    public void sort_from_top_to_bottom(int a [],int low,int high)//排序
    {
        for(int i=low;i<=high;i++)
            System.out.print(a[i]+" ");
        System.out.println();
     if(high<=low)//划分得每个子数组只有一个元素了
         return;
     int mid=low+(high-low)/2;//再次确定划分得界限
        sort_from_top_to_bottom(a,low,mid);//将左半部分排序
        sort_from_top_to_bottom(a,mid+1,high);//将右边部分排序
        merge(a,low,mid,high);//开始合并
        System.out.print("merge:");
        for(int i=low;i<=high;i++)
            System.out.print(""+a[i]+" ");
        System.out.println();
    }

   public void merge(int a[],int low,int mid,int high)//归并
   {
       int i=low;
       int j=mid+1;
       for(int k=low;k<=high;k++)
           aux[k]=a[k];
       for(int k=low;k<=high;k++)
       {
           if(i>mid) //左边已经用尽,开始取右半边元素
               a[k]=aux[j++];
           else if(j>high)//右边已经用尽,开始取左半边元素
               a[k]=aux[i++];
           else if(aux[j]<aux[i])//右半边元素小于左半边元素,取右半边元素---升序
               a[k]=aux[j++];
           else //左半边元素小于右半边元素,取左半边元素---升序
               a[k]=aux[i++];
       }
   }
   public void sort_from_bottom_to_top(int a[])//自底向上
   {
       int N=a.length;
       aux=new int[a.length];//一次性分配空间
       for(int sz=1;sz<N;sz=sz+sz)//sz为子数组的大小
           for(int lo=0;lo<N-sz;lo+=sz+sz)//lo为子数组索引
           {
               merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1,N-1));
               for(int k=lo;k<=Math.min(lo+sz+sz-1,N-1);k++)
                   System.out.print(a[k]+" ");
               System.out.println();
           }
   }
   public static void main(String [] args)
   {
       int [] a={16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
       test t=new test();
       System.out.println("初始数组:");
       for(int i=0;i<16;i++)
           System.out.print(a[i]+" ");
       System.out.println();
       System.out.println("自顶向下实现:");
       t.sort(a);
       System.out.println("自底向上实现:");
       t.sort_from_bottom_to_top(a);
       for(int i=0;i<16;i++)
           System.out.print(a[i]+" ");
   }
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodePanda@GPF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值