算法入门教程-归并排序

关于上节的快速排序,我们知道了它的本质是对冒泡排序的优化,通过时间的执行效率的测试,10W条数据,我们发现快速排序确实比冒泡排序效率高很多,关于快速排序的算法我们不在多说了,这节我们来学习另外一种算法:归并排序,首先来介绍下什么是归并排序?

归并排序介绍

归并排序是利用经典的分治策略来实现的算法的过程,分治:将问题分成很小的问题然后递归去解决,治:治的阶段则将分的阶段的得到的结果进行合并的过程.

上述抽象的概念很难理解,我们来看张图,这样可以更加直观的理解分和治的过程,如图:

分治的思想.png
  • 从图中来看我们发现在分的过程中其实所做的事情不过,其核心点是在治的过程中,结合此图大家可以好好地想象下这个过程.

接下来我们采用图解的方式来更好的理解上图中的这个过程

  • 由于是我们的核心是治的阶段,假设我这里待排序的元素是[4,5,7,8] 和[1,2,3,6]也就是上图中的治的阶段.
示意图.png

简单的说一下该过程的步骤:
上图中的temp为临时数组,用来存储比较后的元素,其中i为左边[4,5,7,8]的(下标)索引,j为右边元素[1,2,3,6]的(下标)索引

  • 第一步: 右边的所有元素跟左边的比较,且将较小的数暂时存放在temp中,然后让j++
  • 让j++对应元素继续比较也就是(2<4)成立,将2存放在temp中,j++
  • 重复上述的过程,也就是(3<4)成立,将3存放在temp中,j++
  • 注意:此时我们的右边元素为6即(6<4)不成立,我们将4存放在temp中,此时j不能在+1了,我们让i+1
  • 还是重复上述过程,(5<6)成立,将5存放在temp中,让i++
  • 此时我们发现7>6的,我们将6存放在temp中,这样我们右边的元素也就是[1,2,3,6]全部治的过程已经完成了,左边还剩7和8了,我们直接将剩余的添加到temp即可
  • 最后一步,我们将temp中元素拷贝到我们原来的数组中就可以了,也就是说最后的排序结果为[1,2,3,4,5,6,7,8]

结合图和步骤相信大多数猿友们已经理解了,接下来我们用代码来实现

代码实现

我们还是采用图中的案例来测试我们的代码,这里先说明下,我们的代码分两部分完成即分和治的过程,我们先写治的代码:

//合并的方法

/**
 *
 * @param arr 待排序的原始数组
 * @param left 左边有序序列的初始索引
 * @param middle 中间索引
 * @param right 右边有序序列的初始索引
 * @param temp 临时存储元素的数组
 */
public static void merge(int[] arr,int left, int middle,int right,int[] temp){

    int i = left; //定义临时的变量来记录我们左边有序序列的初始索引
    int j = middle +1; //定义临时的变量来记录我们右边有序序列的初始索引
    int t = 0; //定义临时的变量来记录temp数组的当前索引

    //步骤1:
    //首先把左右两边的有序序列的元素填充到temp数组中,直到左右两边有序序列中有一边填充完毕为止

    //满足该条件继续循环
    while (i <= middle && j<= right){
        //如果左边当前下标为i的元素小于右边有序序列下表为j的元素
        //我们需要做处理
        if (arr[i] <= arr[j]){
            //1.1 将左边有序序列的索引为i的元素填充到temp数组中
            temp[t] = arr[i];
            //1.2 移动左边的索引
            i ++;
            //1.3 同时移动temp的索引
            t ++;
        }else { //这里表示需要将右边有序序列中的元素填充到temp数组中
            temp[t] = arr[j];
            j ++;
            t ++;
        }
    }


    //步骤2:
    //将有剩余数据的一边的数据填充到temp中
    //该条件成立,表示左边有序序列中元素有剩余的情况,我们需要将剩余的元素全部填充到temp数组中
    while (i <= middle){
        temp[t] = arr[i];
        t ++;
        i ++;
    }
    //假如剩余是右边的有序序列
    while (j <= right){
        temp[t] = arr[j];
        t ++;
        j ++;
    }

    //步骤3:
    //将temp中的元素拷贝到原数组arr中
    //这里有个小技巧,在拷贝时,不是每次都拷贝所有的
    //首先我们认为t是从0开始的
    t = 0;
    //定义一个临时索引,且让初始化为左右有序序列的left索引
    //在我们看到的那张图中,第一次合并后 tempLeft是为0的,right = 1;
    //第二次是: tempLeft = 2; right = 3;
    //第三次是: tempLeft = 0; right  =3;
    //最后一次是: tempLeft = 0; right = 7;
    int tempLeft = left;
    //System.out.println("tempLeft="+tempLeft+ "<------------>"  +"right="+right);
    while (tempLeft <= right){
        arr[tempLeft] = temp[t];
        t ++;
        tempLeft ++;
    }

}

代码注释很详细,其实代码并不多,想看的可以自己看看,我们接着来看看分的过程代码:

//分+合并的方法

/**
 *
 * @param arr 待排序的数组
 * @param left 左边有序序列的下标
 * @param right 右边有序序列的下标
 * @param temp 临时的数组
 */
public static void mergeSort(int[] arr, int left, int right, int[] temp){
    //只要满足这个条件
    if (left < right){
        int mid = (left + right) /2; //中间索引的计算过程
        //向左递归分解
        mergeSort(arr,left,mid,temp);
        //向右递归分解
        //mid +1 表示: 右边的第一个
        mergeSort(arr,mid +1,right,temp);
        //合并
        merge(arr,left,mid,right,temp);
    }

}

采用的递归去处理,我们最后来测试一把,测试代码如下:

/**
 * 算法学习-归并排序
 */
public class MergeSort {

public static void main(String[] args) {
    int [] arr = {8,4,5,7,1,3,6,2};
    int [] temp = new int[arr.length];
    mergeSort(arr,0,arr.length -1,temp);
    System.out.println("归并排序后的结果为:");
    System.out.println(Arrays.toString(arr));

测试结果:

测试结果.png

从测试结果来看,我们完成了排序,最后一点我们来测试一把排序10w数据的执行时间效率,代码如下:

 //归并排序的时间复杂度测试
    int [] arr = new int[10000000];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = (int)(Math.random() * 10000000); //随机生成[0,100000)的数
    }

    Date date1 = new Date();
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format = dateFormat.format(date1);
    System.out.println("排序前的时间为:"+format);
    //进行排序
    int [] temp = new int[arr.length];
    mergeSort(arr,0,arr.length -1,temp);
    Date date2 = new Date();
    SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format2 = dateFormat.format(date2);
    System.out.println("排序后的时间为:"+format2);

执行结果如下:

执行时间.png

可以从图中的测试结果来看,归并排序的执行效率是蛮高的,那么关于它的学习就到这里了....

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容

  • 总结一下常见的排序算法。 排序分内排序和外排序。内排序:指在排序期间数据对象全部存放在内存的排序。外排序:指在排序...
    jiangliang阅读 1,337评论 0 1
  • 3、排序算法 1)内部排序: 归并排序、交换排序(冒泡排序、快排)、选择排序、插入排序 冒泡排序 (1)比较相邻的...
    脆皮鸡大虾阅读 318评论 0 0
  • 7种常用的排序算法总结 2016.04.30PoetryAlgorithm 排序算法:一种能将一串数据依照特定的排...
    raining_804f阅读 786评论 0 0
  • 概述 因为健忘,加上对各种排序算法理解不深刻,过段时间面对排序就蒙了。所以决定对我们常见的这几种排序算法进行统一总...
    清风之心阅读 694评论 0 1
  • 排序算法说明 (1)排序的定义:对一序列对象根据某个关键字进行排序; 输入:n个数:a1,a2,a3,…,an 输...
    code武阅读 655评论 0 0