JAVA 实现 归并排序算法

什么是合并?

与很多有用的算法类似,合并排序基于这样一个技巧:将 2 个大小为 N/2 的已排序序列合并为一个 N 元素已排序序列仅需要 N 次操作。这个方法叫做合并

我们用个简单的例子来看看这是什么意思:

12112529_HYy6.jpg

通过此图你可以看到,在 2 个 4元素序列里你只需要迭代一次,就能构建最终的8元素已排序序列,因为两个4元素序列已经排好序了:

  • 1) 在两个序列中,比较当前元素(当前=头一次出现的第一个)
  • 2) 然后取出最小的元素放进8元素序列中
  • 3) 找到(两个)序列的下一个元素,(比较后)取出最小的
  • 重复1、2、3步骤,直到其中一个序列中的最后一个元素
  • 然后取出另一个序列剩余的元素放入8元素序列中。

这个方法之所以有效,是因为两个4元素序列都已经排好序,你不需要再『回到』序列中查找比较。

                                   12112529_QP7U.gif

  • 拆分阶段,将序列分为更小的序列合并排序是把问题拆分为小问题,通过解决小问题来解决最初的问题(注:这种算法叫分治法,即『分而治之、各个击破』)
  • 排序阶段,把小的序列合在一起(使用合并算法)来构成更大的序列

拆分阶段

12112529_KffN.jpg

在拆分阶段过程中,使用3个步骤将序列分为一元序列。步骤数量的值是 log(N) (因为 N=8, log(N)=3)。【译者注:底数为2,下文有说明】

我怎么知道这个的?

我是天才!一句话:数学。道理是每一步都把原序列的长度除以2,步骤数就是你能把原序列长度除以2的次数。这正好是对数的定义(在底数为2时)。

排序阶段

12112529_HPhC.jpg

在排序阶段,你从一元序列开始。在每一个步骤中,你应用多次合并操作,成本一共是 N=8 次运算。

  • 第一步,4 次合并,每次成本是 2 次运算。
  • 第二步,2 次合并,每次成本是 4 次运算。
  • 第三步,1 次合并,成本是 8 次运算。

因为有 log(N) 个步骤,整体成本是 N*log(N) 次运算

                 12112529_E3wE.gif

合并排序的强大之处

为什么这个算法如此强大?

因为:

  • 你可以更改算法,以便于节省内存空间,方法是不创建新的序列而是直接修改输入序列。

               注:这种算法叫『原地算法』(in-place algorithm)

  • 你可以更改算法,以便于同时使用磁盘空间和少量内存而避免巨量磁盘 I/O。方法是只向内存中加载当前处理的部分。在仅仅100MB的内存缓冲区内排序一个几个GB的表时,这是个很重要的技巧。

                注:这种算法叫『外部排序』(external sorting)。

  • 你可以更改算法,以便于在 多处理器/多线程/多服务器 上运行。

                比如,分布式合并排序是Hadoop(那个著名的大数据框架)的关键组件之一。

  • 这个算法可以点石成金(事实如此!)

这个排序算法在大多数(如果不是全部的话)数据库中使用,但是它并不是唯一算法。如果你想多了解一些,你可以看看 这篇论文,探讨的是数据库中常用排序算法的优势和劣势。

算法代码

我实现的归并算法的java 代码:

	    /**
	     * 归并算法
	     * @param list
	     * @param first
	     * @param last
	     */
	    public static void mergeSort(int[] list, int first, int last){
	    	if(null == list || list.length < 0 || first == last){
	    		return;
	    	}
            //这个几行代码可以省略 如果省略 那么当只有2个元素的时候还需要调用此方法递归 
            //那么其实只有一个元素当作mergeSort入参 其实没什么意义
            //加上这几行仅仅是减少几次函数调用 对结果无影响 强迫症者 可删除。
	    	if(last - first == 1){
	    		sort(list, first, (last + first)/2, last);
	    		return;
	    	}
	    	mergeSort(list, first, (last + first)/2);
	    	mergeSort(list, (last + first)/2 + 1, last);
	    	sort(list, first, (last + first)/2, last);
	    	
	    }
	    
        //这个方法是合并两个有序数组 temp数组可以不需要,直接对list 相应位置的元素操作即可
        //那么这么做合并元素就好像直接插入排序算法一样,前半部分数组不动,后半部分数组比较插入
	    public static void sort(int[] list, int first, int mid, int last ){
	    	int[] temp = new int[last - first + 1];
	    	int i = 0;
	    	int j = 0;
	    	int index = 0;
			while(i < mid - first + 1 && j < last - mid){
				if(list[first + i] >= list[mid + 1 + j]){
					temp[index] = list[mid + 1 + j];
					j++;
					index++;
				} else {
					temp[index] = list[first + i];
					i++;
					index++;
				}
			}
			while(i < mid - first + 1){
				temp[index] = list[first + i];
				index++;
				i++;
			}
			while(j < last - mid){
				temp[index] = list[mid + 1 + j];
				index++;
				j++;
			}
			for(int k = first, n = 0; k <= last; k++, n++){
				list[k] = temp[n];
			}
			System.out.println(Arrays.toString(list));
	    		
	    }
	    

 

转载于:https://my.oschina.net/xiaomianyang/blog/736299

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值