归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。
归并排序算法依赖归并操作。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
归并排序在众多排序算法中既是稳定排序,效率也比较高,同时,归并排序不仅可以用于内排序,还可以用于外排序。

1.两个有序数列的合并

设两个有序数列放在同一向量中相邻的位置上:R[low..m],R[m+1..high],先将它们合并到一个局部的暂存向量 R1中,待合并完成后将 R1 复制回 R[low..high]中。
(1)合并过程
合并过程中,设置 i,j 和 p 三个指针,其初值分别指向这三个记录区的起始位置。

合并时依次比较 R[i]和 R[j]的关键字,取关键字较小的记录复制到 R1[p]中,然后将被复制记录的指针 i 或 j 加 1,以及指向复制位置的指针 p 加 1。

重复这一过程直至两个输入的子文件有一个已全部复制完毕,此时将另一非空的子文件中剩余记录依次复制到 R1 中即可。

(2)动态申请 R1
实现时,R1 是动态申请的,因为申请的空间可能很大,所以在工程上应用时,可能需要加入申请空间是否成功的处理。

2.归并排序的实现

(1)二路归并的思路
将数组划均分为两个子数组;
对两个字数组进行排序;
将排序好的两个字数组归并。
所谓 N路归并 是指将数组均分为N个子数组,将字数组排序后再归并。二路归并是归并排序的最一般的情况。


(2)归并排序实现的一般化过程
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
设定两个指针,最初位置分别为两个已经排序序列的起始位置
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针到达序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

(3)实现过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public class MergeSort {
     
    public static void main(String[] args){
        int[] arr=new int[]{8,7,6,5,4,3,2,1};
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+",");          
        }
        //想起引用传递和值传递的问题,数组是引用传递,不需要什么返回值
        sort(arr,arr.length);
        System.out.println("排序后"); 
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+",");          
        }
    }
     
    public static void sort(int[] arr,int n){
        if(arr==null || n<2){
            return;//边界情况
        }
        divide(arr,0,n-1);
    }
    /**
     *
     * @param arr 待排序数组
     * @param left 待排序区间左侧下标
     * @param right 待排序区间右侧下标
     */
    public static void divide(int[] arr,int left,int right){
         
        if(left>=right){
            return;
        }
        int m=(left+right)/2;//从中间开始分成两个区间进行归并
        divide(arr,left,m);//一直递归划分直到区间长度为1
        divide(arr,m+1,right);
        //开始逐级往上进行归并操作
        binaryMerge(arr,left,m,right);//第一次进行merge操作的递归栈最深层此时是merge(arr,0,0,1)
    }
     
    /**
     * 对数组arr[left...right]位置进行递归的归并排序
     * @param arr
     * @param left
     * @param rigtht
     * @param temp
     */
    public static void binaryMerge(int[] arr,int left,int m,int right){
        /**
         * 归并排序的时间复杂度为O(n),指的就是最大长度为n的临时数组
         */
        int[] temp=new int[right-left+1];
        int l=left;//
        int r=m+1;//
        int index=0;//
         
        while(l<=m && r<=right){
            if(arr[l]<arr[r]){
                temp[index]=arr[l];
                index++;
                l++;
            }else{
                temp[index]=arr[r];
                index++;
                r++;
            }
        }
         
        /**
         * 交换完了如果哪一侧数组还有剩余,则全部赋值
         * 实际的一次归并下面的两个while循环只会执行一个
         * warn!不要漏了等于的情况!否则会每两个元素丢失一个元素
         */
        while(l<=m){
            temp[index]=arr[l];
            index++;
            l++;
        }
         
        while(r<=right){
            temp[index]=arr[r];
            index++;
            r++;
        }
         
        /**
         * 用临时数组的部分排序的序列全部替换待排序数组中对应的部分
         * 这里应该用temp.length,不能用arr.length
         */
        for(int i=0;i<temp.length;i++){
            //注意是left,此时的l是已经变化了的
            arr[left+i]=temp[i];
        }
         
    }
     
}

  

(4)时间和空间复杂度
归并排序的最好、最坏和平均时间复杂度都是O(nlogn),而空间复杂度是O(n),
比较次数介于(nlogn)/2和(nlogn)-n+1,赋值操作的次数是(2nlogn)。因此可以看出,归并排序算法比较占用内存,但却是效率高且稳定的排序算法。

3.空间复杂度为O(1)的归并排序

归并排序的空间复杂度为O(N),
通过优化可以把空间复杂度降为O(1),通过手摇算法,
但实际上通过手摇算法后,此时的时间复杂度会上升。

4.多路归并排序

归并排序的思想可以用于外排序。
外排序是相对内排序而言的,在常规的小规模排序过程中,都是直接在内存中对数据进行排序处理的,而对于数据量极大的排序问题,这种方式是不现实的。

这个时候就要通过外排序来进行,先将数据划分成多个规模能在内存中处理的子集,对各个子集排序后存放在临时的磁盘文件上,然后再将这些子集归并到输出文件中。

这个过程要使用到多路归并。

本文转自邴越博客园博客,原文链接:http://www.cnblogs.com/binyue/p/3421123.html,如需转载请自行联系原作者

归并排序的分析与Java实现相关推荐

  1. java实现apriori算法_各种排序算法的分析及java实现(一)

    阅读本文约需要7分钟 大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈).上次老师跟大家分享了下用Navicat for Mysql导入.sql文件的 ...

  2. dv算法java实现_各种排序算法的分析及java实现(二)

    更多精彩,请点击上方蓝字关注我们! 上次跟大家分享了下各种排序算法的分析及java实现(一)的相关知识,今天跟大家分享各种排序算法的分析及java实现(二)的知识.昨天我们讲到了选择排序,今天我们继续 ...

  3. Binder源码分析之Java层(原)

    前面的几节中我们介绍了Native层Binder通讯的原理和用法,那么在Java层如何使用Binder通讯呢?其原理又与Native层的Binder有什么关系呢?         与Native层的S ...

  4. Twitter的分布式自增ID算法Snowflake实现分析及其Java、Php和Python版

    在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12 ...

  5. 分析:Java的好处究竟在哪里?

    大多数人选择Java可能只是因为听说Java前景好.Java比较好找工作.Java语言在TIOBE排行榜上一直位于前三等等之类的原因,但是Java具体好在哪里,心里却是没有什么概念的.其实我选择Jav ...

  6. java中Mark接口_JVM源码分析之Java对象头实现

    原标题:JVM源码分析之Java对象头实现 原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 "365篇原创计划"第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Ja ...

  7. php 解析java map,java_java遍历Map的几种方法分析,本文实例分析了java遍历Map的几 - phpStudy...

    java遍历Map的几种方法分析 本文实例分析了java遍历Map的几种方法.分享给大家供大家参考,具体如下: Java代码: Map map=new HashMap(); map.put(" ...

  8. 仿Windows记事本简要分析 (Java)

    仿Windows记事本简要分析 (Java) 学Java的同学大部分都会做过一个小练习 ,用Java 做出一个记事本 .其中主要涉及的是界面和 io流 方面的知识 . 学完之后我在这做一个小总结,以下 ...

  9. java共识算法_PBFT共识算法详细分析及Java实现

    PBFT共识算法详细分析及Java实现 为什么写这个 最近研究了区块链相关的一些东西,其实就三大块: 分布式存储(去中心) 共识机制 安全加密 分布式存储,就是一个分布式数据库,每个节点都保存一份副本 ...

最新文章

  1. django框架-DRF工程之认证功能
  2. 在CSDN中增加图片版权保护的方法
  3. ai为什么要栅格化_英语学习为什么不能“碎片化”?要想学好英语,系统化是关键...
  4. Keepalived+nginx造成流量异常
  5. 公差基本偏差代号_螺纹基础知识学习,螺纹公差标准的结构,螺纹公差带与旋合长度...
  6. element-UI响应式(布局原理)讲解 - 贴文篇
  7. 【C语言】文件操作及输入输出格式(文件常用的库函数)
  8. 十进制转任意进制-数论
  9. MongoDB数据库(二):增删查改
  10. junit junit_JUnit显示名称– @DisplayName
  11. python关机怎样保存seek_在Python中操作文件之seek()方法的使用教程
  12. animate支持的css属性
  13. sqlplus连接Oracle的正确语法
  14. PostgreSQL如何导入SJIS字符集的文件
  15. 实战小例子 | Python实现用手势控制电脑音量
  16. mac触控板 鼠标中键_如何在Mac的触控板上添加中键
  17. ios- 音乐播放器(1)
  18. UI 移动端设计尺寸
  19. 【想法】滴滴更新迭代功能
  20. Unity热更新机制

热门文章

  1. docker拷贝文件
  2. 用Docker构建LNMP环境(上)
  3. IIS识别Json文件
  4. linux svn 常用命令
  5. 转:Singleton模式
  6. android recovery模式及ROM制作
  7. MySQL操作实战(三):表联结
  8. Axure - 破解
  9. 校验金额、大小写字母、大写字母、合法uri、email
  10. 利用Crawlspider爬取腾讯招聘数据(全站,深度)