这篇博文分为四个部分:

  1. 归并排序基本思想
  2. 基础代码实现与解析
  3. 代码一次优化
  4. 代码二次优化(自底向上的归并排序)
1.归并排序基本思想
* 3)
* [归并排序] :小到大排序
* 1.循环的将每一个部分都分为原来的一半,直到最后每一部分只剩下一个元素
* 2.循环的将每两个部分进行合并并且排序,直到最后全部合并
* O(n*log n)
2.基础代码实现与解析
static int[] mergeSort(int[] arr) {return __mergeSort(arr, 0, arr.length - 1);
}
private static int[] __mergeSort(int[] arr, int left, int right) {if (left >= right) {return arr;
    }
    //得到中点位置的下标middle,注意这里最好不要使用 int middle = (right + left) / 2 ,防止 right + left 数据太大造成溢出
    int mid = (right - left) / 2 + left;
    //1.循环的将每一个部分都分为原来的一半,直到最后每一部分只剩下一个元素
    __mergeSort(arr, left, mid);
    __mergeSort(arr, mid + 1, right);
    //2.循环的将每两个部分进行合并并且排序,直到最后全部合并
    // if 条件判断当这两部分需要排序时(即前一部分的最大值要比后一部分的最小值大时),进行排序,否则直接合并即可
    if (arr[mid] > arr[mid + 1]) {__merge(arr, left, mid, right);
    }return arr;
}
private static int[] __mergeSort(int[] arr, int left, int right) {if (left >= right) {return arr;
    }//得到中点位置的下标middle,注意这里最好不要使用 int middle = (right + left) / 2 ,防止 right + left 数据太大造成溢出
    int mid = (right - left) / 2 + left;
    //1.循环的将每一个部分都分为原来的一半,直到最后每一部分只剩下一个元素
    __mergeSort(arr, left, mid);
    __mergeSort(arr, mid + 1, right);
    //2.循环的将每两个部分进行合并并且排序,直到最后全部合并
    // if 条件判断当这两部分需要排序时(即前一部分的最大值要比后一部分的最小值大时),进行排序,否则直接合并即可
    if (arr[mid] > arr[mid + 1]) {__merge(arr, left, mid, right);
    }return arr;
}// arr[left....mid]  arr[mid + 1....right] 两个部分进行归并
private static int[] __merge(int[] arr, int left, int mid, int right) {int[] temarr = new int[right + 1 - left]; //开辟新的空间,这个空间是用来进行排序
    //  arr 中所有元素复制一份, temarr ,注意这里 arr 是从下标 left 开始的, temarr 是从下标 0 开始的
    for (int i = left; i < right + 1; i++) {temarr[i - left] = arr[i];
    }int i = left;  //作为前一部分将要排序的元素的下标
    int j = mid + 1;    //作为后一部分将要排序的元素的下标
    for (int k = left; k <= right; k++) {  //karr数组中本轮归并中最小值将要覆盖掉的下标
        //防止越界,要保证i始终属于前一部分,j始终属于后一部分
        if (i > mid) {  //表明前一部分已经遍历结束,只需要把后一部分的值依次填入即可
            arr[k] = temarr[j - left];
            j++;
        } else if (j > right) {arr[k] = temarr[i - left]; //同理,后一部分已经遍历完毕,只需依次填入前一部分即可
            i++;
        }//一般情况 : 遍历整个数组,比较 temarr[i - left]  temarr[j - left] 的大小,将小的直接覆盖原数组arr,将它排到前面,并且将排完序的下标后移
        else if (temarr[i - left] < temarr[j - left]) {arr[k] = temarr[i - left];
            i++;
        } else {arr[k] = temarr[j - left];
            j++;
        }}return temarr;
}
3.代码一次优化
由于最初归并排序分割到最后会只剩下一个元素,然后这一个元素不断的通过递归的方式合并合并再合并,因此这里可以不递归切分到底,而在只剩下10个元素的时候,使用插入排序对它进行排序,然后直接向上合并.
这种做法权衡了性能的消耗.
在这里只需要修改 __mergeSort(int[] arr,int left,int right) 这个方法:
private static int[] __mergeSort(int[] arr, int left, int right) {
//优化        if (left >= right) {
//优化            return arr;
//优化        }
        /*优化开始*/
        if (right - left <= 10) {int[] temparr = new int[right - left + 1];
            for (int i = left; i <= right; i++) {temparr[i - left] = arr[i];
            }//使用插入排序进行底层的排序,优化归并排序不断递归到底的消耗
            temparr = InsertionSort.insertionSort_3(temparr);
            for (int i = left; i <= right; i++) {// temparr 再回填回到 arr                 arr[i] = temparr[i - left];
            }return arr;
        }/*优化结束*/
        //得到中点位置的下标middle,注意这里最好不要使用 int middle = (right + left) / 2 ,防止 right + left 数据太大造成溢出
        int mid = (right - left) / 2 + left;
        //1.循环的将每一个部分都分为原来的一半,直到最后每一部分只剩下一个元素
        __mergeSort(arr, left, mid);
        __mergeSort(arr, mid + 1, right);
        //2.循环的将每两个部分进行合并并且排序,直到最后全部合并
        // if 条件判断当这两部分需要排序时(即前一部分的最大值要比后一部分的最小值大时),进行排序,否则直接合并即可
        if (arr[mid] > arr[mid + 1]) {__merge(arr, left, mid, right);
        }return arr;
    }
4.代码二次优化(自底向上的归并排序)
注意看归并排序的第一步:将每个大的部分都切分为原来的一半,直到最后只剩下一个元素.
如果是从计算机本身的视角来看,他始终是同一个数组,因此循环的二分操作可以帮助我们理解原理,但是对计算机来说却无异于徒增负担,所以这里就没有必要执行切分操作.
[思路]:我们可以直接把它看做是已经切分成了多个小部分,直接归并就好
我们直接修改 mergeSort(int[] arr) 这个方法就好:
static int[] mergeSort(int[] arr) {for (int part = 1; part <= arr.length; part += part) {for (int i = 0; i + part < arr.length; i += 2 * part) {if ((i + 2 * part - 1 > arr.length - 1)) {__merge(arr, i, i + part - 1, arr.length - 1);
            } else {__merge(arr, i, i + part - 1, i + 2 * part - 1);
            }}}return arr;
}

经过这一步的优化,我们甚至都不需要

__mergeSort(int[] arr, int left, int right)
这个方法,就可以实现归并排序

排序算法(3)----归并排序相关推荐

  1. 排序算法:归并排序、快速排序

    相关博客: 排序算法:冒泡排序.插入排序.选择排序.希尔排序 排序算法:归并排序.快速排序 排序算法:桶排序.计数排序.基数排序 排序算法:堆排序 十大排序算法小结 一.归并排序: 1.工作原理: 归 ...

  2. 排序算法之--归并排序(好玩的一个算法o。o)快速入门

    排序算法之--归并排序(好玩的一个算法o.o) 下面是归并操作的基本思路(注意:是归并操作哦,不是归并排序哦) 归并操作的工作原理如下: 第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存 ...

  3. NOI提高级:排序算法之归并排序、快速排序

    图解排序算法(四)之归并排序 图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 小学生图解排序算法:⑥归并排序 小学生图解排序算法:⑥归并排序_纯文笔记-CSDN博客_图解 ...

  4. 数据结构与算法:十大排序算法之归并排序

    数据结构与算法:十大排序算法之归并排序 package TopTenSortingAlgorithms;/*** 归并排序:Java** @author skywang* @date 2014/03/ ...

  5. [Alg]排序算法之归并排序

    [Alg]排序算法之归并排序 作者:屎壳郎 miaosg01@163.com 日期:Aug 2021 版次:初版 简介: 归并排序是一类在任何情况下都能保证Nlg⁡(N)N\lg(N)Nlg(N)的排 ...

  6. 【排序算法】归并排序(C语言)

    [排序算法]-- 归并排序(C语言) 目录 一.归并排序的原理 二.两个有序数组排序和合并 1. 原地排序 2. 创建临时空间 二.递归实现 三.非递归实现 1. 实现思路 2. 数组边界问题 3. ...

  7. 排序算法中——归并排序和快速排序

    冒泡排序.插入排序.选择排序这三种算法的时间复杂度都为 $O(n^2)$,只适合小规模的数据.今天,我们来认识两种时间复杂度为 $O(nlogn)$ 的排序算法--归并排序(Merge Sort)和快 ...

  8. 【DS】排序算法之归并排序(Merge Sort)

    一.算法思想 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法的一个非常典型的应用,指的是将两个已经排序的序列合并成一个序列的操作.其归并思想如下: 1)申请空间,使其大小为两个已经 ...

  9. c语言归并排序代码详细注释,C语言实现排序算法之归并排序详解

    排序算法中的归并排序(Merge Sort)是利用"归并"技术来进行排序.归并是指将若干个已排序的子文件合并成一个有序的文件. 一.实现原理: 1.算法基本思路 设两个有序的子文件 ...

  10. 排序算法-07归并排序(python实现)

    归并排序 概述 以归并操作为基础的排序算法,底层算法设计为分治法. 所谓分治法,就是讲问题分解为多个子问题递归求解,再将子问题答案合并. 算法实现 将待排序序列分解为两个,四个,,,n个子部分. 两两 ...

最新文章

  1. python输入输出流详解_输入输出流的概念
  2. ISA CMAK 网络访问隔离区
  3. 《C与指针》第七章练习
  4. 前端问题记录1:debounce is not a function
  5. JAVA不同类型数组重载_方法的重载;数组 (Java Day05)
  6. 史上最全 yum 入门使用教程和常见错误解决办法
  7. linux c 网络事件 通知,深入理解Linux网络技术内幕—通知链
  8. 风变python培训_风变python学习小结
  9. 18 比较数组找出最大两个数
  10. C#信息采集系统,常见控件练习
  11. 黄俊:电商系统的一些心得分享
  12. MySQL – iBatis – 文件存储
  13. 情感读本杂志情感读本杂志社情感读本编辑部2022年第23期目录
  14. 不用任何工具重装Win7系统
  15. 中长焦投影仪买哪款好,当贝X3高流明热销你值得看
  16. VC++界面编程之--实现工具栏自定义皮肤
  17. Redis从入门到入坟系列文章(一): keys 命令
  18. pmp培训机构哪个比较好,求推荐?
  19. 计算机组成原理(静态随机存取存取器)
  20. 带你一文读懂SaaS版多租户商城系统对多品牌企业的应用价值

热门文章

  1. sqlite 模糊匹配日期_SQLite模糊查找(like) | 学步园
  2. 使用Visual Studio开发游戏——微软宣布与Unity、Unreal Engine和Cocos展开全新合作
  3. 掘金外链即将失效?论如何用脚本一次性下载/替换失效的外链图片
  4. megacli组建raid
  5. 老男孩教育每日一题-124天:当我们使用ssh-keygen命令的时候,如何一键非交互生产密钥对呢?...
  6. android在activity中锁屏解锁后重走OnCreate的问题的解决办法
  7. 如何解决无法显示隐藏文件文件夹
  8. 然后是几点 c语言,2-2. 然后是几点
  9. android广告页白屏_Android 启动页面与广告页面的实现-Go语言中文社区
  10. python数据分析是什么意思_选择python进行数据分析的理由和优势