`

算法回顾之七:归并排序

 
阅读更多

算法回顾系列第七篇:归并排序

------------------------------------

归并排序

 

基本原理:

利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后通过递归步骤将排好序的半子表合并成为越来越大的有序序列。

归并排序包括两个步骤,分别为:1、划分子表。2、合并半子表。

该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

 

程序实现:

public void sort(int[] data){
        int[] temp = new int[data.length];
        mergeSort(data,temp,0,data.length-1);
    }
    
    /**
     * @param 待排序数组
     * @param 辅助排序数组
     * @param 起始位置
     * @param 结束位置
     */
    private void mergeSort(int[] data,int[] temp,int l,int r){
        int mid=(l+r)/2;
        if(l==r) return ;
        //分治:递归划分左半个子表
        mergeSort(data,temp,l,mid);
        //分治:递归划分右半个子表
        mergeSort(data,temp,mid+1,r);
        System.out.println("begin merge ...");
        /**
         * 合并子表:
         * 左半个子表和右半个子表标记(mid为中间位置)两个指针各指向头元素,
         * 选择相对小的元素放入到合并空间,并移动指针到下一位置。
         * 重复步骤上面步骤直到左(或右)某一指针达到序列尾,
         * 将右(或左)剩下的所有元素直接复制到合并序列尾。
         */
        System.out.println("data:"+Arrays.toString(data)+" temp:"+Arrays.toString(temp));
    	System.out.println("l:"+l+" r:"+r+" mid:"+mid);
    	//复制data中l到r内区域的数到temp的对应位置.
        for(int i=l;i<=r;i++){
            temp[i]=data[i];
        }
        System.out.println("copy data:"+Arrays.toString(data)+" copy temp:"+Arrays.toString(temp));
        //声明2个指针:i1左子表头,i2右子表头,指针作用于temp,合并后的值写入data.
        int i1=l;//指针:mid左边元素坐标位置(起始为l).
        int i2=mid+1;//指针:mid右边元素坐标位置(起始为mid右边第一个元素).
        //遍历l到r区域之间的数据(从l的最左边元素向右遍历直到r).
        for(int cur=l;cur<=r;cur++){
            if(i1==mid+1){//如果i1已经遍历到mid以右(mid为边界).
            	System.out.println("i1==mid+1");
                data[cur]=temp[i2];//将tmp的mid以右坐标位置的元素写入data当前位置.
                i2++;//mid右子表指针移动(mid右边元素坐标+1)
            }else if(i2>r){//如果mid以右元素已经遍历超过r(r为边界).
            	System.out.println("i2>r");
            	data[cur]=temp[i1];//将tmp的mid以左坐标位置的元素写入data当前位置.
            	i1++;//mid左子表指针移动(mid左边元素坐标+1)
            }else if(temp[i1]<temp[i2]){//如果tmp的mid以左坐标位置元素值小于tmp的mid以右的坐标位置元素值.
            	System.out.println("temp[i1]<temp[i2]");
            	data[cur]=temp[i1];//将较小的元素值写入data当前位置.
            	i1++;//mid左子表指针移动(mid左边元素坐标+1)
            }else{//mid以左大于mid以右.
            	System.out.println("else");
            	data[cur]=temp[i2];//将tmp的mid以右坐标位置的元素值写入data当前位置.
            	i2++;//mid右子表指针移动(mid右边元素坐标+1)
            }
            System.out.println("swap data:"+Arrays.toString(data)+" swap temp:"+Arrays.toString(temp));
        }
        //System.out.println("last data:"+Arrays.toString(data)+" last temp:"+Arrays.toString(temp));
        //System.out.println("l:"+l+" r:"+r);
    }
    
    public static void main(String[] args){
    	//int[] arrays = new int[]{10,2,4,8,5,1,6,3,7,9};
    	int[] arrays = new int[]{10,9,8,7,6,5,4,3,2,1};
    	new MergeSort().sort(arrays);
    	System.out.println(Arrays.toString(arrays));
    }

上面程序中:

1、首先通过递归将待排序数组data划分为若干个子序列,

2、合并某个data子序列时将该子序列内元素的复制到temp对应位置。

每个子序列有l,r,mid三个位置,分别对应它的:起始位置、结束位置、中间位置。

从l到mid(包含)为左子表,从mid+1到r(包含)为右子表。

声明两个指针(或标记)分别指向temp的:i1左子表头(l)位置、i2右子表头(mid+1)位置。

比较这两个位置的元素值,如果:

(1)左子表元素值小于右子表元素值,将左子表元素写入data当前位置。左子表指针右移,data当前位置右移。

(2)右子表元素值小于左子表元素值,将右子表元素写入data当前位置。右子表指针右移,data当前位置右移。

(3)左子表遍历完,即i1到达mid+1的位置。将右子表元素写入data当前位置。右子表指针右移,data当前位置右移,相当于把右子表内的剩余元素直接写入data中。

(4)右子表遍历完,即i2到达r+1的位置。将左子表元素写入data当前位置。左子表指针右移,data当前位置右移,相当于把做子表内的剩余元素直接写入到data中。

3、重复以上步骤合并每个子序列,最后通过递归步骤将排好序的子序列合并成为越来越大的有序序列。

 

性能分析:

平均时间复杂度是O(nlogn) 。

速度仅次于快速排序(且为稳定排序算法)。

 

空间复杂度:O(n)。

稳定性:稳定。

 

PS:另外有改进算法如下,有时间研究一下:

http://www.cnblogs.com/zhanglanyun/archive/2012/09/03/2669416.html

In-place Merge Sort (原地归并排序)

即时间复杂度还是O(nlogn),但空间复杂度为O(1)的归并排序算法。

 

分享到:
评论

相关推荐

    《C算法》((美国)Robert Sedgewick)清晰版[DJVU] 第一卷

    法,归并和归并排序方法、优先队列与堆排序方法、基数排序方法以及特殊目的排序方法,并比较了各种 排序方法的性能特征。第四部分“搜索”(第12~16章)在进一步讲解符号表、树等抽象数据类型的基础 上,重点讨论...

    《C算法》((美国)Robert Sedgewick)清晰版[DJVU] 第二卷

    法,归并和归并排序方法、优先队列与堆排序方法、基数排序方法以及特殊目的排序方法,并比较了各种 排序方法的性能特征。第四部分“搜索”(第12~16章)在进一步讲解符号表、树等抽象数据类型的基础 上,重点讨论...

    数据结构、算法与应用:C++语言描述(原书第2版)第二部分

    18.2.2 归并排序 18.2.3 快速排序 18.2.4 选择 18.2.5 相距最近的点对 18.3 解递归方程 18.4 复杂度的下限 18.4.1 最小最大问题的下限 18.4.2 排序算法的下限 第19章 动态规划 19.1 算法思想 19.2 应用 19.2.1 0/1...

    小甲鱼_数据结构与算法(98集全)

    道01数据结构和算法绪论.... mp4 立98总结回顾.mp4画65_最短路径(迪杰斯特拉算法).mp466_最短路径( 弗洛伊德算法) . mp4口67拓扑排序. mp4二68关键路径.mp4口69_查找算法. mp4 画69关键路径(代码讲解).mp4

    leetcode分配-learning.github.io:学习.github.io

    leetcode 分配欢迎来到我的 learning_path 页面 仍然按照我最初的坚持,您在我网站上的足迹不会被...一些基本算法/方法:归并排序 这部分是Python/R编程的骨架介绍; 外甥启蒙的一个小实践 运筹学与数据分析课程学习

    数据结构与算法:C++描述

    14.2.2 归并排序 443 14.2.3 快速排序 447 14.2.4 选择 452 14.2.5 距离最近的点对 454 14.3 解递归方程 462 14.4 复杂性的下限 463 14.4.1 最小最大问题的下限 464 14.4.2 排序算法的下限 465 第15章 动态规划 467 ...

    Learn_some_algorithm_and_data_structure:从零开始回顾一下最简单最基础的算法与数据结构

    一起来学习数据结构与算法吧一些常用经典算法和数据结构的回顾首先是最经典的排序问题排序选择排序(Selection Sort)复杂度O(n ^ 2)找到最小的元素然后与当前位置交换插入排序(Insertion Sort)复杂度O(n ^ 2)...

    leetcode中国-practice:每日伸展运动

    归并排序 k排序? 基数排序 插入排序 TODO:尾调用优化空间? 大型系统分布式系统 不同排序算法的比较 问题: nodejs 中可能存在 ** 兼容性问题 类别: 树动态规划回溯 排序图 学习资源 动态规划 涵盖的问题 二维 DP...

    数据结构算法与应用-C++语言描述

    14.2.2 归并排序 443 14.2.3 快速排序 447 14.2.4 选择 452 14.2.5 距离最近的点对 454 14.3 解递归方程 462 14.4 复杂性的下限 463 14.4.1 最小最大问题的下限 464 14.4.2 排序算法的下限 465 第15章 动态规划 467 ...

    数据结构算法与应用-C__语言描述

    14.2.2 归并排序 443 14.2.3 快速排序 447 14.2.4 选择 452 14.2.5 距离最近的点对 454 14.3 解递归方程 462 14.4 复杂性的下限 463 14.4.1 最小最大问题的下限 464 14.4.2 排序算法的下限 465 第15章 动态规划 467 ...

    数据库系统实现

    2.3.4 两阶段多路归并排序 2.3.5 扩展多路归并以排序更大的关系 习题 2.4 改善辅助存储器的访问时间 2.4.1 按柱面组织数据 2.4.2 使用多个磁盘 2.4.3 磁盘镜像 2.4.4 磁盘调度和电梯算法 2.4.5 ...

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料;本资料仅用于学习。 【课程内容】 第1周 开课介绍 python发展介绍 第一个python程序 ...归并排序 希尔排序 算法练习 栈和队列 数据结构其他

    leetcode中文版-fundamentalsreview:基本面回顾

    归并排序 导演 无向 邻接矩阵 邻接表 遍历:BFS、DFS (如果你有4年以上的经验) ---------------- 此点以下的所有内容都是可选的 ---------------- 其他资源 AVL 树 张开的树 红/黑树 2-3 搜索树 2-3-4 棵树(又名 ...

    传智播客扫地僧视频讲义源码

    06_学员学习标准_排序及问题抛出 07_数组做函数参数退化问题剖析_传智扫地僧 08_数据类型基础提高 09_数据类型引申和思考 10_变量本质剖析和内存四区模型引出_传智扫地僧 11_c的学习重理解到位_对初学者_传智扫地僧 ...

    C++数据抽象和问题求解(第6版).[美]Frank M. Carrano(带详细书签).pdf

    11.2.1 归并排序 307 11.2.2 快速排序 312 11.2.3 基数排序 319 11.3 各种排序算法的比较 321 C++片段4 类关系和重用 325 C4.1 回顾继承 326 C4.1.1 类的公有、私有和受保护部分 331 C4.1.2 公有、私有和受...

    leetcode二维数组-segment-tree:段树

    使用归并排序的分区算法将数组划分为片段 分区后,我们将从叶子返回值到父 段树将被构建如下 使用数组存储段树,类似于Heap 构建段树 构造线段树的算法 段树理论 查找范围总和 有三种重叠类型 查找范围和流 查找范围...

Global site tag (gtag.js) - Google Analytics