算法 —— 排序 —— 归并排序

原创 2018年04月15日 19:38:05

“分治”策略

分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。在计算机科学中,分治法就是运用分治思想的一种很重要的算法。分治法是很多高效算法的基础,如排序算法(快速排序,归并排序)等。

这里写图片描述

通俗来说就是把一个大的方案,分解成一个一个小方案,再组织起来。

例如对100个元素排序,可以分解成 2 组50个元素的排序,再分解成 4 组25个元素的排序…最后分解成 50 组 2个元素的排序。最后再对已经有序的元素进行整合。

这里写图片描述



归并

如上所示,归并算法是基于“分治”策略。即:要将一个数组排序,先(递归)将它分成两半分别排序,然后将结果归并起来。

归并过程中,我们需要把两个已经有序(同一数组的前半部分和后半部分)的元素排列,归并成一个有序的元素排列。

这里写图片描述

    public static void main(String[] args) {
        int[] a=new int[]{1,2,8,9,  3,4,5,7};
        aux=new int[a.length];//初始化辅助数组

        merge(a,0,a.length/2-1,a.length-1);
    }

    private static int[] aux;//需要辅助数组,用来作比较

    private static void merge(int[] a, int lo, int mid, int hi) {
        int i = lo;
        int j = mid + 1;

        for (int k = 0; k < a.length; 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 (aux[i] < aux[j]) {//比较元素,放入数组a[],下标+1
                a[k] = aux[i++];
            } else {
                a[k] = aux[j++];
            }
        }

    }



上面的代码和图文即归并排序中的“归并”部分。将一个无序的数组从 分解 归并 直至成为一个有序的数组,基于归并思想,有两种实现方法,分别是自顶向下的归并排序和自底向上的归并排序。




自顶向下(递归)

递归实现的归并排序是算法设计中分治策略的典型应用。

自顶向下的实现方式和Android View的绘制机制measure()方法很相似,这里穿插一下知识点:

measure过程是后根遍历(DecorView最后setMeasureDiemension()),所以子控件的测量结果影响父控件的测量结果。

这里写图片描述



下面摘选《算法4》中的图片来加深印象。

这里写图片描述

要对子数组a[lo..hi]进行排序,先将它分为a[lo..mid]a[mid+1..hi]两部分,分别通过递归调用将它们单独排序,最后将有序的子数组归并为最终的排序结果。

    public static void main(String[] args) {
        int[] a = new int[] { 1, 2, 8, 9, 3, 4, 5, 7 };
        sort(a);
    }

    private static int[] aux;// 需要辅助数组,用来作比较

    private static void sort(int[] a) {
        aux = new int[a.length];
        sort(a, 0, a.length - 1);
    }

    private static void sort(int[] a, int lo, int hi) {
        if (lo >= hi) {
            return;
        }
        int mid = lo + (hi - lo) / 2;
        sort(a, lo, mid);// 左半边排序,里面可能递归sort和merge方法
        sort(a, mid + 1, hi);// 右半边排序
        merge(a, lo, mid, hi);// 归并,merge方法如上
    }




自底向上(遍历)

  • 自顶向上 : 我们将一个大问题分割成小问题分别解决,然后用所有小问题的答案来解决整个大问题。尽管我们考虑的问题是归并两个大数组,实际上我们归并的数组大多数都非常小。

  • 自底向上 : 实现归并排序的另一种方法是先归并那些微型数组,然后再成对归并得到的数组,如此这般,直到我们将整个数组归并在一次。


1.首先我们把每个元素想象成一个大小为 1 的数组。(两两归并)
2.然后将两个大小为2的数组归并成一个有4个元素的数组。(四四归并)
3.然后再将2个大小为4的数组归并(八八归并),如此下去。

这里写图片描述

    public static void main(String[] args) {
        int[] a = new int[] { 1, 2, 8, 9, 3, 4, 5, 7 };
        sort(a);
    }

    private static void sort(int[] a) {
        int LEN = a.length - 1;
        aux = new int[a.length];

        for (int sz = 1; sz <= LEN; sz *= 2) {// 1,2,4,8,16...

            for (int lo = 0; lo < sz; lo += 2 * sz) {
                //(0,2)(2,4)(4,6)...
                //(0,4)(4,8)(8,12)...
                //(0,8)(8,16)(16,24)...
                merge(a, lo, lo + sz - 1, Math.min(LEN, lo + 2 * sz - 1));
            }
        }
    }

这里写图片描述





归并排序是稳定排序,速度仅次于快速排序,一般用于对总体无序,但是各子项相对有序的数列。

版权声明:本文为博主原创文章,欢迎转载,转载需标明出处。 https://blog.csdn.net/qian520ao/article/details/79950052

白话经典算法系列之五 归并排序的实现(讲的真好)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较...
  • yuehailin
  • yuehailin
  • 2017-04-03 16:25:48
  • 38349

比较排序之插入和归并排序

排序之插入和归并插入排序: 对于少量的元素的排序,插入排序是一个很有效的算法。其原理很简单,类似于我们打扑克的时候,开始时,我们左手为空并且桌上的牌面向下,然后,我们每次从桌子上拿走一张牌并将它...
  • tao2035333
  • tao2035333
  • 2016-09-17 21:01:12
  • 957

PHP实现排序算法----归并排序(Merging Sort)

基本思想:归并排序:就是利用归并(合并)的思想实现的排序方法。它的原理是假设初始序列含有 n 个元素,则可以看成是 n 个有序的子序列,每个子序列的长度为 1,然后两两归并,得到 ⌈ n / 2⌉ (...
  • baidu_30000217
  • baidu_30000217
  • 2016-11-27 13:47:14
  • 3158

排序算法系列:归并排序算法

上一篇我们说了一个非常简单的排序算法——选择排序。其复杂程序完全是冒泡级的,甚至比冒泡还要简单。今天要说的是一个相对比较复杂的排序算法——归并排序。复杂的原因不仅在于归并排序分成了两个部分进行解决问题...
  • u013761665
  • u013761665
  • 2016-05-27 16:32:19
  • 13561

C++——算法基础之排序——二路归并排序

今天,大白跟大家说一说,二路归并排序 二路归并排序:是一种比较快的排序方法。 思想:将序列切半分开,然后对左右进行递归切半,直至最小单元序列内元素个数为1。然后依次将两个序列有序合并为一个序列,...
  • QLY1798LOVE
  • QLY1798LOVE
  • 2016-09-14 10:49:00
  • 922

数据结构--排序算法(归并排序&&基数排序&&桶排序)

在前面我们说了快速排序等排序方法,如有同学想看则请查阅往期博: 插入排序,选择排序:http://blog.csdn.net/sayhello_world/article/details/619270...
  • sayhello_world
  • sayhello_world
  • 2017-03-24 16:52:03
  • 546

高效链表排序-归并算法

排序算法应该是最基础的了,快速、归并、选择、堆排序等等对于数组而言可以随机访问,那么对于链表呢,比如快排,两个指针分别网后往前走,而没有前驱指针的单向链表,无法完成这样的操作,当然了可以采用快慢指针的...
  • wejoncy
  • wejoncy
  • 2016-05-03 11:45:41
  • 2521

java 实现二分归并排序

首先 解释一下什么是归并排序的精髓就是把一个乱序数组划分成小的数组来排序,然后再把小的数组合并成大的小组,下面的这张图能够明确说明什么是归并排序 虽然看图感觉二路归并排序很简单,但是实际操作起来还是...
  • qq_33048603
  • qq_33048603
  • 2016-04-10 17:23:51
  • 4916

数据结构实验之排序五:归并求逆序数(讲解归并排序算法)

Problem Description 对于数列a1,a2,a3…中的任意两个数ai,aj (i  aj,那么我们就说这两个数构成了一个逆序对;在一个数列中逆序对的总数称之为逆序数,如数列 1 6 ...
  • Ameir_yang
  • Ameir_yang
  • 2016-12-11 22:09:25
  • 1172

算法系列(四)排序算法中篇--归并排序和快速排序

在算法系列(三)排序算法上篇 一文中,介绍了冒泡排序,插入排序和选择排序算法。这篇文章继续讲解排序算法。 概述 冒泡排序,插入排序和选择排序算法这些算法的时间复杂度都是O(N^2),是否有更高效的排序...
  • robertcpp
  • robertcpp
  • 2016-05-30 23:04:57
  • 4730
收藏助手
不良信息举报
您举报文章:算法 —— 排序 —— 归并排序
举报原因:
原因补充:

(最多只允许输入30个字)