算法:归并排序

算法:归并排序

写在前面

  归并排序算法是基于一个简单的归并操作:合并两个有序数组来形成一个更大的有序数组。

  提炼归并的思想,归并排序就是将一个无序数组先划分成两个部分(递归地),对其分别排序,然后再进行合并。

  归并排序无论输入情况,时间复杂度为N*LogN,主要的缺点是使用了一个额外的大小为N的空间。

简单的归并操作:

  首先我们思考一下,如何将两个有序数组合并成一个有序数组?

    我们应该想到新建一个的新数组re,然后分别从两个数组的左边开始,依次比较两个数组中的元素,将数较小的元素先排入新数组中。算法可以如下:

    public static void merge(int[] re,int[] A,int[] B)
    {
        re = new int[100]; // 较大即可
        int i=0,j=0;
        int ptr=0;
        while(i<A.length&&j<B.length)
        {
            if(A[i]<=B[j])
                re[ptr++]=A[i++];
            else
                re[ptr++]=B[j++];
        }
        while(i<A.length)
            re[ptr++]=A[i++];
        while(j<B.length)
            re[ptr++]=B[j++];
        for(int t=0;t<ptr;t++)
            System.out.println(re[t]);
    }

根据上面的问题,我们这样想,要将一个无序数组排序可以(递归地)先将它分成两半分别排序,然后将结果归并起来。模式大概如下:

这就是我们所说的 归并排序。其实我们理解的重点是划分与归并,这里涉及递归的操作,为了便于理解,我们对代码进行分解并辅以实例分析一下。

代码分解与分析

划分操作

public static void sort(Comparable[] a) //这里是排序操作的入口
{
        aux= new Comparable[a.length]; //aux是我们定义的一个与a等大的数组!
        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);
}

说明:  

  E A S Y Q U E S T I O N

  E A S Y Q U         //先取左半部分

  E A S            //左半部分取出

  E A

  E

  A

  S

     Y  Q  U

     Y  Q

     Y

Q

U

         E S T I O N

         ....

  由于篇幅,我们不便补全,但是划分的效果我们可以看出,不断递归的划分,最后每一小段就只有一个元素(只有一个元素,默认有序呗),下来最关键的就是将这一小段一小段进行合并。

合并操作

  我们在这里的操作是原地归并,所谓原地归并就是在一个数组中,主观的将其划分为两个小数组(下文称为左、右数组),利用下标与大小关系进行合并操作。

public static void merge(Comparable[] a,int lo,int mid,int hi) {
        int i=lo,j=mid+1;         // i表示的是左数组的开始下标,j表示的是右数组的开始下标!
        for(int k=lo;k<=hi;k++)   // 我们先将待合并的元素放到一个临时数组aux中!
            aux[k]=a[k];

        for(int k=lo;k<=hi;k++)
        {
            if(i>mid)           //如果左数组的元素全部放入结果数组中,我们就把右数组剩下的元素放入结果数组中!
                a[k]=aux[j++];
            else if(j>hi)       //如果右数组的元素全部放入结果数组中,我们就把左数组剩下的元素放入结果数组中!
                a[k]=aux[i++];
            else if(less(aux[i], aux[j]))  //我们比较左右两个数组的元素,并将小的先放入结果数组中,同时将计数值右移!
                a[k]=aux[i++];         //第一种情况,左<右,放左
            else
                a[k]=aux[j++];          //第二种情况,左>右,放右
        }
    }

说明:

  

  我们研究此图的情况时,必须结合划分操作的实例图, A E是最先开始合并的,下来 AE 再和S合并。Y 与 Q 后合并,QY与U进行合并....

完整的归并代码  

public class MergeSort {
    private static Comparable aux[];

    public static void merge(Comparable[] a,int lo,int mid,int hi) {
        int i=lo,j=mid+1;
        for(int k=lo;k<=hi;k++)
            aux[k]=a[k];

        for(int k=lo;k<=hi;k++)
        {
            if(i>mid)
                a[k]=aux[j++];
            else if(j>hi)
                a[k]=aux[i++];
            else if(less(aux[i], aux[j]))
                a[k]=aux[i++];
            else
                a[k]=aux[j++];
        }
    }

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

    public static boolean less(Comparable v,Comparable w) {
        return v.compareTo(w)<0;
    }

}
时间: 2024-12-19 15:02:17

算法:归并排序的相关文章

排序算法——归并排序

归并排序是分治法的典型举例. 分治法的思想是,将原有问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治模式在每层递归时都有三个步骤: 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例. 解决这些子问题,递归地求解各子问题.然而,若子问题的规模足够小,则直接求解. 合并这些子问题的解成原问题的解. 归并排序算法完全遵循分治模式.直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列. 解决:使用

经典排序算法 - 归并排序Merge sort

经典排序算法 - 归并排序Merge sort 原理,把原始数组分成若干子数组,对每个子数组进行排序, 继续把子数组与子数组合并,合并后仍然有序,直到所有合并完,形成有序的数组 举例 无序数组[6 2 4 1 5 9] 先看一下每一个步骤下的状态,完了再看合并细节 第一步 [6 2 4 1 5 9]原始状态 第二步 [2 6] [1 4] [5 9]两两合并排序,排序细节后边介绍 第三步 [1 2 4 6] [5 9]继续两组两组合并 第四步 [1 2 4 5 6 9]合并完成,排序完成 输出结

Java实现算法归并排序(MergeSort)

归并排序 归并排序 (merge sort) 是一类与插入排序.交换排序.选择排序不同的另一种排序方法.归并的含义是将两个或两个以上的有序表合并成一个新的有序表.归并排序有多路归并排序.两路归并排序 , 可用于内排序,也可以用于外排序.这里仅对内排序的两路归并方法进行讨论. 1.两路归并排序算法思路 ①把 n 个记录看成 n 个长度为1的有序子表: ②进行两两归并使记录关键字有序,得到 n/2 个长度为 2 的有序子表: ③重复第②步直到所有记录归并成一个长度为 n 的有序表为止. 实例: 2.

[算法]——归并排序(Merge Sort)

归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序:然后将已经有序的两个子部分进行合并,最终完成排序.其时间复杂度与快速排序均为O(nlogn),但是归并排序除了递归调用间接使用了辅助空间栈,还需要额外的O(n)空间进行临时存储.从此角度归并排序略逊于快速排序,但是归并排序是一种稳定的排序算法,快速排序则不然. 所谓稳定排序,表示对于具有相同值的多个元素,其间的先后顺序保持不变.对于基本数据类型而言,一个排序算法是否稳定,影响很小,但是

我实现的第一个算法----归并排序

今天听了卜东坡老师的算法课,讲的是归并算法,那个动画演示,终于让我开窍了,于是乎,赶紧今天就编了个C++的程序.我知道可能这个程序还比较粗糙,但是这是第一次实现了算法导论上的东东,心里那个激动啊,,,哎,我也终于能实现个算法了,以前总认为自己很菜,其实真的很菜,,,算了,直接上程序吧,,, #include<iostream> using namespace std; int a[100]; int flag; int n; void vector_initial(); void print_

算法--归并排序(链表)

归并排序 http://blog.csdn.net/morewindows/article/details/6678165 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 归并操作: http://www.tuicool.com/articles/iy2QRn6 归并操作 归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法. 如:设有数列 [6,202,100,301,38,8,1]

python数据结构与算法——归并排序

归并排序: 原理与C语言实现 参考:白话经典算法系列之五 归并排序的实现 1. 容易对有序数组A,B进行排序. 2. 为了使得A,B组内数据有序:可以将A,B组各自再分成二组. 3. 经过不断分组,当分出来的小组只有一个数据时(有序),合并相邻二个小组. 这样通过先递归的分解数列,再合并数列就完成了归并排序. 代码摘自<Python Algorithm> 1 # 对数组seq进行归并排序 2 # 返回排序后数组 3 def mergesort(seq): 4 mid = len(seq)//2

算法-归并排序

归并排序是建立在归并操作上的一种有效的排序算法,算法主要采用分治法(Divide and Conquer)的一个非常典型的应用.归并排序的算法复杂度为O(N*logN),需要的额外的空间跟数组的长度N有关系,实现归并排序最简单的方法是将两个数组重新整合到第三个数组中.通常对于一个数组我们对前半部分进行排序,然后惊醒后半部分进行排序,实现原地归并操作,不过需要额外的空间存储数组.假设数据中有8个元素,先分为四组进行比较,之后分为两组进行比较,最后分为一组进行比较,这样就衍生出来两种方法,一种是自顶

算法—归并排序的改进及排序算法的极致

1.对小规模子数组使用插入排序 用不同的方法处理小规模问题能改进大多数递归算法的性能,因为递归会使小规模问题中方法的调用过于频繁,所以改进对它们的处理方法就能改进整个算法.对排序来说,我们已经知道插入排序(或者选择排序)非常简单,因此很可能在小数组上比归并排序更快.和之前一样,一幅可视轨迹图能够很好地说明归并排序的行为方式.图中的可视轨迹图显示的是改良后的归并排序的所有操作.使用插入排序处理小规模的子数组(比如长度小于15)一般可以将归并排序的运行时间缩短10%~15%. 2.测试数组是否已经有

[经典算法] 归并排序

题目说明: 归并排序是建立在归并操作上的一种有效的排序算法.该算法也是采用分治法(Divide and Conquer)的一个非常典型的应用.算法复杂度为O(N*logN). 题目解析: 归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列. 归并排序包括两个步骤: 1)划分子表 2)合并半子表 伪代码: 合并排序伪代码(使用哨兵): merge(A,p,q,r): n1 <-- q-p+1 n2 <-