算法(第4版)-2.2 归并排序

归并:将两个有序的数组归并成一个更大的有序数组。

归并算法:先(递归地)将它分为两半分别排序,然后将结果归并起来。

· 优点:保证将任意长度为N的数组排序所需时间和NlogN成正比;

· 缺点:所需的额外空间和N成正比。

2.2.1 原地归并的抽象方法

    public static void merge(Comparable[] a, int lo, int mid, int hi) {
        // 将a[lo..mid]和a[mid+1..hi]归并
        int i = lo, j = mid + 1;

        for (int k = lo; k <= hi; k++) {    // 将a[lo..hi]复制到aux[lo..hi]
            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 (less(aux[j], aux[i]))    a[k] = aux[j++];    // 右 < 左
            else                                                        a[k] = aux[i++];    // 右 > 左
        }
    }

merge

2.2.2 自顶向下的归并排序

public class Merge {
    private static Comparable[] aux;    // 归并所需的辅助数组

    public static void sort(Comparable[] a) {
        aux = new Comparable[a.length];    // 一次性分配空间
        sort(a, 0, a.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        // 将数组a[lo..hi]排序
        if (hi <= lo)    return;
        int mid = lo + (hi - lo) / 2;
        sort(a, lo, mid);                // 将左半边排序
        sort(a, mid + 1, hi);        // 将右半边排序
        merge(a, lo, mid, hi);    // 归并结果
    }

    public static void merge(Comparable[] a, int lo, int mid, int hi) {
        // 将a[lo..mid]和a[mid+1..hi]归并
        int i = lo, j = mid + 1;

        for (int k = lo; k <= hi; k++) {    // 将a[lo..hi]复制到aux[lo..hi]
            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 (less(aux[j], aux[i]))    a[k] = aux[j++];    // 右 < 左
            else                                                        a[k] = aux[i++];    // 右 > 左
        }
    }

    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    private static void show(Comparable[] a) {
        // 在单行中打印数组
        for (int i = 0; i < a.length; i++)
            StdOut.print(a[i] + " ");
        StdOut.println();
    }

    public static boolean isSorted(Comparable[] a) {
        // 测试数组元素是否有序
        for (int i = 1; i < a.length; i++)
            if (less(a[i], a[i - 1]))    return false;
        return true;
    }

    public static void main(String[] args) {
        // 从标准输入读取字符串,将它们排序并输出
        String[] a = In.readStrings();
        sort(a);
        assert isSorted(a);
        show(a);
    }
}

Merge

1. sort()方法的作用其实在于安排多次merge()方法调用的正确顺序。

2. 对于长度为N的任意数组,自顶向下的归并排序需要1/2NlgN至NlgN次比较,最多需要访问数组6NlgN次。

3. 通过以下方式我们还可能大幅度缩短归并排序的运行时间:

· 对小规模子数组使用插入排序

· 测试数组是否已经有序

· 不将元素复制到辅助数组

2.2.3 自底向上的归并排序

import java.lang.Math;

public class MergeBU {
    private static Comparable[] aux;    // 归并所需的辅助数组

    public static void sort(Comparable[] a) {
        // 进行lgN次两两归并
        int N = a.length;
        aux = new Comparable[N];
        for (int sz = 1; sz < N; sz = sz + sz)
            for (int lo = 0; lo < N - sz; lo += sz +sz)
                merge(a, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, N - 1));
    }

    public static void merge(Comparable[] a, int lo, int mid, int hi) {
        // 将a[lo..mid]和a[mid+1..hi]归并
        int i = lo, j = mid + 1;

        for (int k = lo; k <= hi; k++) {    // 将a[lo..hi]复制到aux[lo..hi]
            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 (less(aux[j], aux[i]))    a[k] = aux[j++];    // 右 < 左
            else                                                        a[k] = aux[i++];    // 右 > 左
        }
    }

    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    private static void show(Comparable[] a) {
        // 在单行中打印数组
        for (int i = 0; i < a.length; i++)
            StdOut.print(a[i] + " ");
        StdOut.println();
    }

    public static boolean isSorted(Comparable[] a) {
        // 测试数组元素是否有序
        for (int i = 1; i < a.length; i++)
            if (less(a[i], a[i - 1]))    return false;
        return true;
    }

    public static void main(String[] args) {
        // 从标准输入读取字符串,将它们排序并输出
        String[] a = In.readStrings();
        sort(a);
        assert isSorted(a);
        show(a);
    }
}

MergeBU

1. 首先我们进行的是两两归并(把每个元素想象成一个大小为1的数组),然后是四四归并(将两个大小为2的数组归并成一个有4个元素的数组),然后是八八的归并,一直下去。在每一轮归并中,最后一次归并的第二个子数组可能比第一个子数组要小(但这对merge()方法不是问题),如果不是的话所有的归并中两个数组大小都应该一样,而在下一轮中子数组的大小会翻倍。

2. 对于长度为N的任意数组,自底向上的归并排序需要1/2NlgN至NlgN次比较,最多需要访问数组6NlgN次。

· 当数组长度为2的幂时,自顶向下和自底向上的归并排序所用的比较次数和数组访问次数正好相同,只是顺序不同;

· 其他时候,两种方法的比较和数组访问的次序会有所不同。

3. 自底向上的归并排序比较适合用链表组织的数据。

2.2.4 排序算法的复杂度

1. 没有任何基于比较的算法能够保证使用少于lg(N!)~NlgN次比较将长度为N的数组排序。

即最好情况至少是lg(N!),最坏情况至少是NlgN。

2. 归并排序在最坏情况下的比较次数和任意基于比较的排序算法所需的最少比较次数都是~NlgN。

时间: 2024-09-29 18:28:38

算法(第4版)-2.2 归并排序的相关文章

可视化对比十多种排序算法(C#版)

本文由 伯乐在线 - smilesisi 翻译自 Kanasz Robert.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. 在这篇文章中,我会向大家展示一些排序算法的可视化过程.我还写了一个工具,大家可对比查看某两种排序算法. 下载源码 – 75.7 KB 下载示例 – 27.1 KB 引言 首先,我认为是最重要的是要理解什么是“排序算法”.根据维基百科,排序算法(Sorting algorithm)是一种能将一串数据依照特定排序方式进行排列的一种算法.最常用到的排序方式是数值顺序以及字典

常见排序算法(JS版)

常见排序算法(JS版)包括: 内置排序,冒泡排序,选择排序,插入排序,希尔排序,快速排序(递归 & 堆栈),归并排序,堆排序,以及分析每种排序算法的执行时间. index.html 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>twobin 常见排序算法 (JS版) </title> 5 <meta http-equiv="content-type" content=&

程序员必须掌握的8大排序算法(Java版)

程序员必须掌握的8大排序算法(Java版) 提交 我的评论 加载中 已评论 程序员必须掌握的8大排序算法(Java版) 2015-07-28 极客学院 极客学院 极客学院 微信号 jikexueyuan00 功能介绍 极客学院官方帐号,最新课程.活动发布.欢迎大家反馈问题哟^_^ 本文由网络资料整理而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配排序(基数排序) 所需辅助空

算法第四版-文字版-下载地址-Robert Sedgewick

下载地址:https://download.csdn.net/download/moshenglv/10777447 算法第四版,文字版,可复制,方便copy代码 目录: 第1章 基 础 ....................... . ..........................11.1 基础编程模型 ..................................... 41.1.1 Java程序的基本结构 ................. 41.1.2原始数据类型与表达式

【JavaScript】【算法】JavaScript版排序算法

JavaScript版排序算法:冒泡排序.快速排序.插入排序.希尔排序(小数据时,希尔排序会比快排快哦) 1 //排序算法 2 window.onload = function(){ 3 var array = [0,1,2,44,4, 4 324,5,65,6,6, 5 34,4,5,6,2, 6 43,5,6,62,43, 7 5,1,4,51,56, 8 76,7,7,2,1, 9 45,4,6,7,8]; 10 //var array = [4,2,5,1,0,3]; 11 array

算法第四版 在Eclipse中调用Algs4库

首先下载Eclipse,我选择的是Eclipse IDE for Java Developers64位版本,下载下来之后解压缩到喜欢的位置然后双击Eclipse.exe启动 然后开始新建项目,File -> New Java Project,项目名随便写,如下图 右键src文件夹,Add -> New Java Class,这里需要注意Name一栏里填写的内容就是类名,这里我写了TestAlgs4,为了测试「算法 第四版」作者给的那个测试样例 代码如下: import edu.princeto

算法导论笔记1 - 插入排序 vs 归并排序

import random import time __author__ = 'Administrator' LENGTH = 3000 base = [] for i in range(0, LENGTH): base.append(random.randint(0, LENGTH)) def ins_sort(array): for border in range(1, len(array)): j = border - 1 key = array[border] while j >= 0

算法(第四版)学习笔记之java实现选择排序

选择排序步骤: 1.找到数组中参与遍历比较的所有元素中的最小元素的下标: 2.将最小元素与数组中参与遍历比较的第一个元素进行交换(如果第一个元素就是最小元素的话,那么也会进行一次交换): 3.若数组中还有需要参与遍历比较的元素,则跳转到步骤1:否则排序结束. 在算法第四版中给出的所有排序均是适用于任意实现了Comparable接口的数据类型,若要将数字作为测试用例,请勿使用基本数据类型,改用Integer等实现了Comparable接口的对象. 选择排序代码如下: /** * * @author

经典排序算法(Java版)

经典排序算法(Java版)  转载 1.冒泡排序 Bubble Sort最简单的排序方法是冒泡排序方法.这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮.在冒泡排序算法中我们要对这个“气泡”序列处理若干遍.所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确.如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置.显然,处理一遍之后,“最轻”的元素就浮到了最高位置:处理二遍之后,“次轻”的元素就浮到了次高位

分享《自然语言处理理论与实战》PDF及代码+唐聃+《深入浅出Python机器学习》PDF及代码+段小手+《深度学习实践:计算机视觉》PDF+缪鹏+《最优化理论与算法第2版》高清PDF+习题解答PDF+《推荐系统与深度学习》PDF及代码学习

<自然语言处理理论与实战>高清PDF,362页,带书签目录,文字可以复制:配套源代码.唐聃等著. <大数据智能互联网时代的机器学习和自然语言处理技术>PDF,293页,带书签目录,文字可以复制,彩色配图.刘知远等著.  下载: https://pan.baidu.com/s/1waP6C086-32_Lv0Du3BbNw 提取码: 1ctr <自然语言处理理论与实战>讲述自然语言处理相关学科知识和理论基础,并介绍使用这些知识的应用和工具,以及如何在实际环境中使用它们.由