奔走在算法的大路上(一)排序之归并排序

归并排序(Merge sort)是创建在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

归并操作

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

算法描述

归并操作的过程如下:

申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

设定两个指针,最初位置分别为两个已经排序序列的起始位置

比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针到达序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

代码实现:

package Sort;

import java.util.Random;

/**
 * <p>
 * Description: 归并排序的各种实现方式
 * </p>
 * @author zhangjunshuai
 * @version 1.0
 * Create Date: 2015年4月14日 上午11:58:27
 * Project Name: ArithMetic
 *
 * <pre>
 * Modification History:
  *             Date                                Author                   Version          Description
 * -----------------------------------------------------------------------------------------------------------
 * LastChange: $Date:2015年4月14日            $      $Author: zhangjunshuai$          $Rev:1.0 $
 * </pre>
 *
 */
/**
 * <p>
 * Description:
 * </p>
 * @author zhangjunshuai
 * @version 1.0
 * Create Date: 2015年4月21日 下午5:54:09
 * Project Name: ArithMetic
 *
 * <pre>
 * Modification History:
  *             Date                                Author                   Version          Description
 * -----------------------------------------------------------------------------------------------------------
 * LastChange: $Date:2015年4月21日            $      $Author: zhangjunshuai$          $Rev:1.0 $
 * </pre>
 *
 */
public class Merger {
    /**
     * <p>
     * 打印输出
     * </p>
     * @author zhangjunshuai
     * @date 2015年4月3日 下午4:19:03
     * @param a
     */
    private static void show(Comparable[] a){
        for(int i = 0; i < a.length; i++){
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }
    /**
     * <p>
     * 原地归并排序,思想是:
     * 将带比较的数据先拷贝到另外的数组中b[Size]中,然后进行归并排序,再复制会a【】中
     * </p>
     * @author zhangjunshuai
     * @date 2015年4月14日 下午12:10:05
     * @param a
     * @param Size
     * @param start
     * @param end
     */

    private static void localMerge(Comparable[] a,int start,int middile,int end){
        //将a[start....middle]和a[middle+1....end]合并
        int length = end - start +1;
        Comparable[] b = new Comparable[length] ;
        for(int i = 0;i<length;i++){
            b[i] = a[start+i];
        }
        int h = 0,y = middile - start+1;
        for(int j = 0;j<length;j++){
            if(h>(middile - start)){
                a[start+j] = b[y++];
            }else{
                if(y>=b.length){
                    a[start+j] = b[h++];
                }else{
                    if(b[h].compareTo(b[y])<0)
                        a[start+j] = b[h++];
                    else
                        a[start+j] = b[y++];
                }
            }
        }
    }

    /**
     * <p>
     * 实现原地交换归并排序
     * </p>
     * @author zhangjunshuai
     * @date 2015年4月14日 下午4:49:14
     */
    private static void ShowLocalMerge(Comparable[] a){

        int Bsize =1;//步长
        do{
            int start = 0;
            int middile = 0;
            int end = 0;
            while(start < a.length){
                 middile = start + Bsize-1;
                 end = start +2*Bsize - 1;
                if(end >=a.length)//不要超过总长
                        end = a.length -1;
                if(middile < end)//防止最后只够一个数组的
                    localMerge(a,start,middile,end);
                start = end+1;
            }
            System.out.println("--------步长:"+Bsize);
            Bsize = 2*Bsize ;
        }while(Bsize<a.length);
        show(a);
    }

    /**
     * <p>
     * </p>
     * @author zhangjunshuai
     * @date 2015年4月14日 下午5:27:31
     * @param a
     * @param lo
     * @param hi
     */
    private static void TopEnd(Comparable[]a,int lo,int hi){
        if(hi <= lo) return;
        int mid = lo + (hi  -lo)/2;
        TopEnd(a,lo,mid);//将左半边排序
        TopEnd(a,mid+1,hi);//将右半边排序
        localMerge(a,lo,mid,hi);//归并结果
    }
    /**
     * <p>
     * 自下而上的排序
     * </p>
     * @author zhangjunshuai
     * @date 2015年4月21日 下午5:54:23
     * @param a
     */
    public static void EndToUp(Comparable[] a){
        int N = a.length;
        Comparable[] aux = new Comparable[N];
        for(int sz = 1;sz < N;sz = sz+sz){
            for(int lo = 0; lo < N -sz;lo+=sz+sz)
                localMerge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1, N-1));
        }
    }
    /**
     * <p>
     * </p>
     * @author zhangjunshuai
     * @date 2015年4月14日 下午4:48:36
     * @param args
     */
    public static void main(String[] args) {
        Random random = new Random();
        int rondomsize = random.nextInt(1000);
        Integer[] a = new Integer[rondomsize];
        for(int w =0;w<rondomsize;w++){
            a[w] = random.nextInt(rondomsize+w);
        }
        //ShowLocalMerge(a);
        EndToUp(a);
        show(a);
    }

}
时间: 2024-11-08 22:57:55

奔走在算法的大路上(一)排序之归并排序的相关文章

奔走在算法的大路上(一)排序之希尔排序

希尔排序是插入排序的一种更高效的改进版本.它的作法不是每次一个元素挨一个元素的比较.而是初期选用大跨步(增量较大)间隔比较,使记录跳跃式接近它的排序位置:然后增量缩小:最后增量为 1 ,这样记录移动次数大大减少,提高了排序效率.希尔排序对增量序列的选择没有严格规定. 希尔排序最关键的是选对增量,关于增量的选择,建议参考:http://zh.wikipedia.org/wiki/希尔排序  中的步长序列. 希尔排序的核心思想是:由一定规则将带排序的长序列切割成多个子序列,子序列进行内部插入排序,如

奔走在算法的大路上(一)排序之插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间. 其原理我感觉用一张图说明时最好的了 源码 package Sort; /** * <p> * Description: 插入排序 * </p> * @a

奔走在算法的大路上(一)排序之选择排序

首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换).再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置.如此往复,直到将整个数组排序.这种方法交租选择排序. 推荐维基百科的解释:选择排序 package Sort; /** * <p> * Description: 选择排序 * </p> * @author zhangjunshuai * @version 1.0 * Create Date: 201

数据结构实践——大数据集上排序算法性能的体验

本文是针对[数据结构基础系列(9):排序]的实践项目. [项目 - 大数据集上排序算法性能的体验] 设计一个函数,产生一个至少5万条记录的数据集合.在同一数据集上,用直接插入排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序等算法进行排序,记录所需要的时间,经过对比,得到对复杂度不同的各种算法在运行时间方面的感性认识. 提示1:这一项目需要整合多种排序算法,可以考虑先建设排序算法库,作为我们这门课算法库的收官之作: 提示2:本项目旨在获得对于复杂度不同算法的感性认识,由于数据分布

对大对象进行排序的算法

快速排序就是快速排序,谢尔排序就是谢尔排序.然而,直接应用基于这些算法的函数模板时,如果要排序的Comparable对象很大的话,有时效率会很低.问题就在于.问题就在于重新排列Comparable对象时,进行太多复制Comparable对象的工作.如果Comparable对象很大而且难于复制的话,其代价也会很高. 一般来说,这个问题的解决方案很简单:生成一个指向Comparable的指针数组,然后重新排列这些指针.一旦确定了元素应该在的位置,就可以直接将该元素放在相应的位置上,而不必进行过多的中

在路上---学习篇(一)Python 数据结构和算法 (4) --希尔排序、归并排序

独白: 希尔排序是经过优化的插入排序算法,之前所学的排序在空间上都是使用列表本身.而归并排序是利用增加新的空间,来换取时间复杂度的减少.这俩者理念完全不一样,注定造成的所消耗的时间不同以及空间上的不同. 归并排序涉及到递归的使用,需要理解其中精髓才能更好了解归并排序,以及其他应用到递归的算法.理解其本质才能更好的应用. 希尔排序 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该方法因DL.Shell于195

白话经典算法系列之四 直接选择排序及交换二个数据的正确实现

分类: 白话经典算法系列 2011-08-09 11:15 16682人阅读 评论(29) 收藏 举报 算法面试c 直接选择排序和直接插入排序类似,都将数据分为有序区和无序区,所不同的是直接播放排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后. 设数组为a[0…n-1]. 1.      初始时,数组全为无序区为a[0..n-1].令i=0 2.      在无序区a[i…n-1]中选取一个最小的元素,将其与a[i]交

啊哈!算法之快速排序与桶排序

啊哈!算法之快速排序与桶排序 1.快速排序算法 快速排序由 C. A. R. Hoare(东尼·霍尔,Charles Antony Richard Hoare)在1960 年提出,之后又有许多人做了进一步的优化.在数列种随机找出一个基准数,因为数列是杂乱的,所以取首项为基准数.从后往前找到比基准数大的位置,再从前往后找到比基准数小的位置,交换元素:右游标向前移动与左游标向后移动,它们相遇时用基准数的位置与相遇的位置交换.此时原来数列以相遇的位置被划分为了两个需要排序的数列,再次执行上述过程:当左

Java数据结构和算法之数组与简单排序

一.数组于简单排序 数组 数组(array)是相同类型变量的集合,可以使用共同的名字引用它.数组可被定义为任何类型,可以是一维或多维.数组中的一个特别要素是通过下标来访问它.数组提供了一种将有联系的信息分组的便利方法. 一维数组 一维数组(one‐dimensional array )实质上是相同类型变量列表.要创建一个数组,你必须首先定义数组变量所需的类型.通用的一维数组的声明格式是: type var‐name[ ]; 获得一个数组需要2步: 第一步,你必须定义变量所需的类型. 第二步,你必