算法分析(4)-排序-归并排序

1简单释义

less和exch可以查看上一章:算法分析(3)-简单排序总结(选择,插入,希尔含图解)——Comparable接口

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

  • 归并排序能够保证将任意长度为 N N N的数组排序所需时间和 N l o g N NlogN NlogN成正比;
  • 归并排序的主要缺点是其所需的额外空间与 N N N成正比。

2 自顶向下的归并排序

2.1图解

自顶向下其实是先完成左侧数组然后完成右侧数组的排序规则:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2 原地归并抽象方法的解释

实现归并的一种方式就是直接将两个有序数组归并到第三个数组中,图示如下:

  1. 首先将左右序列排序好的数组 a [ k ] a[k] a[k]所有元素复制到 a u x [ k ] aux[k] aux[k]中:

在这里插入图片描述
2. 然后将 a u x [ k ] aux[k] aux[k]中的元素归并到 a [ k ] a[k] a[k]中。

  • 如果右方元素较小将 a u x [ j ] aux[j] aux[j]中的元素归并到 a [ k ] a[k] a[k]中,
  • 如果左方元素较小将 a u x [ i ] aux[i] aux[i]中的元素归并到 a [ k ] a[k] a[k]中。
    在这里插入图片描述
    在这里插入图片描述
    左边用尽直接将后半部分 a u x [ j ] aux[j] aux[j]复制到 a [ k ] a[k] a[k]

在这里插入图片描述
原地归并算法如下:
这里的 l e s s less less可以查看上一章算法分析(3)-简单排序总结(选择,插入,希尔含图解)

//lo第一个元素,hi最后一个元素
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi)
{
 	for (int k = lo; k <= hi; k++)
 		aux[k] = a[k];
	int i = lo, j = mid+1;
 	for (int k = lo; k <= hi; k++) 
 	{
 		if (i > mid) a[k] = aux[j++];//左边用尽直接将后半部分复制到a[k]
 		else if (j > hi) a[k] = aux[i++];//右边用尽直接将前半部分复制到a[k]
 		else if (less(aux[j], aux[i])) a[k] = aux[j++];//右方元素较小,复制到a[k],
 		else a[k] = aux[i++];//左方元素较小,复杂到a[k]
 }
}

使用以上的抽象方法可以使用递归的方式完成递归排序。

2.3自顶向下的归并排序

首先上代码:

//递归的实现归并排序
public class Merge {
	private static Comparable[] aux;//归并所需的辅助数组
	public class void sort(Comparable[] a)
	{
		aux=new Comparable[a.length];//为辅助数组分配空间
		sort(a,0,a.length-1);//递归过程
	}
	//排序
    private static void sort(Comparable[] a, int lo, int hi) {
        
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a,lo, mid);//排序左侧
        sort(a,mid + 1, hi);//排序右侧
        merge(a,lo, mid, hi);//归并过程,见上方抽象方法说明
    }
}

其实 s o r t sort sort的的作用只是对 m e r g e merge merge执行的顺序完成合理调用。
在这里插入图片描述
这里直接给出对于长度为 N N N的数组,自顶向下的归并排序的比较次数: 1 / 2 N l g N 1/2NlgN 1/2NlgN~ N l g N NlgN NlgN
访问数组的次数(最多): 6 N l g N 6NlgN 6NlgN
关于算法规模的计算以及数学分析的相关证明,会在本专栏之后进行更新。

2.4自顶向下的归并排序优化建议

代码后期会在github上更新,目前博主的git在商用,暂时不放优化代码

  1. 对小规模子数组使用插入排序
  2. 对子数组随时检测是否有序
  3. 不讲元素复制到辅助数组

3 自底向上的归并排序

3.1图解

自底向上其实就是从所有数组中最小分组进行归并排序
首先进行分解(这里的分解其实使用递归即可):在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
当分解到最简元素时进行原地归并:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.2代码

//递归的实现归并排序
public class Merge {
    private static Comparable[] aux;//归并所需的辅助数组
    public static void sort(Comparable[] a)
    {
        int N=a.length;
        aux=new Comparable[N];//为辅助数组分配空间
        for(int sz=1;sz<N;sz=sz+sz)
          for(int lo=0;lo<N-sz;lo+=sz+sz)
              merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1,N-1));//见上方抽象方法说明
    }

}

这里直接给出对于长度为 N N N的数组,自顶向下的归并排序的比较次数: 1 / 2 N l g N 1/2NlgN 1/2NlgN~ N l g N NlgN NlgN
访问数组的次数(最多): 6 N l g N 6NlgN 6NlgN

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

苦走一口田

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

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

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

打赏作者

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

抵扣说明:

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

余额充值