入门简介-排序-算法第4版

0、序言

排序就是将一组对象按照某种逻辑顺序重新排列的过程,学习排序算法实际意义:

  • 对排序算法的分析有助于你全面理解比较算法性能的方法
  • 类似的技术也能有效解决其他类型的问题
  • 排序算法常常是我们解决其他问题的第一步

初级排序算法,作为对排序算法领域的第一次探索,深入学习的原因在于:

  1. 我们将通过它们熟悉一些术语和简单的技巧
  2. 这些简单的算法在某些情况下比我们之后将会讨论的复杂算法更有效
  3. 集合你会发现,它们有助于我们改进复杂算法的效率

1、通用模板

我们关注的主要对象是重新排列数组元素的算法,其中每个元素都有一个主键。排序算法的目标是将所有元素的主键按照某种方式排列(通常是按照大小或者是字母顺序)。拍下后所有较大的主键大于等于索引较小的主键。元素和主键的具体性质在不同的应用中千差万别。在Java中,元素通常是对象,对主键的抽象描述规则是通过一直内置的机制(Comparable接口)来完成的。

“排序算法类模板”中Example类展示了我们的习惯约定:我们会将排序代码防在类的sort()方法中,该类还将包含函数less()和exch()以及一个示例用例main()。Example类还包含了一些早起调试使用的代码:测试用例main()将标准输入得到的字符串排序,并用私有方法show()打印字符数组的内容。为了区别不同的排序算法,我们为相应的类取了不同的名字,用例可以根据名字调用不同的实现,例如Insertino.sort()、Merge.sort()、Quick.sort()等。

大多数情况下,我们的排序代码只会通过两个方法操作数据:less()方法对元素进行比较,exch()方法交互元素的位置。将数据操作现在在这两个方法中使得代码的可读性和可移植性更好,更容易验证代码的正确性、分析性能以及排序算法直接的比较。

import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;

/**
 * 排序算分类模板
 */
public class Example {

    /**
     * 排序方法
     * @param a     实现了Comparable接口的待排序数组
     */
    public static void sort(Comparable[] a) {

    }

    /**
     * 比较大小
     * @param a     目标a
     * @param b     目标b
     * @return      返回布尔值
     */
    private static  boolean less(Comparable a, Comparable b) {
        return a.compareTo(b) < 0;
    }

    /**
     * 交换数组元素
     * @param a     数组
     * @param i     索引
     * @param j     索引
     */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

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

    /**
     * 测试数组是否已经有序
     * @param a     带测试数组
     * @return      测试结果: true-数组有序;false-数组无序
     */
    public static boolean isSorted(Comparable[] a) {
        // 测试数组是否已经有序
        for (int i = 0; i < a.length; i++) {
            if (less(a[i], a[i-1])) return false;
        }
        return  true;
    }

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

  • 其中导入jar包可到书中指定地址获取,还可以到我的百度云获取,链接:https://pan.baidu.com/s/14k_i0b5n6_lURh7PDtoSsw 提取码:0rim

这个类展示是数组排序实现的框架。对于我们学习的每种排序算法,我们都会为这样一个类的实现一个sort()方法并将Example改为算法的名称。

2、验证

无论数组的初始状态是什么,排序算法都能成功吗?谨慎起见,我们会在测试代码中添加一条语句assert isSorted(a);来确认排序后数组元素都是有序的。尽管一般都会测试代码并从数学上证明算法的正确性,单在实现每个排序算法时加上这条语句仍然是有必要的。需要注意的是,如果我们只使用exch()来交换数组的元素,这个测试就足够了。当我们直接将值存入数组中时,这条语句无法提供足够的保证(例如,把初始输入数组的元素全部置为相同的值也能通过这个测试)。

3、运行时间

我们还要评估算法的性能,首先,要计算各个排序算法在不同的随机输入下的基本操作的次数(包括比较和交换,或者是读写数组的次数)。然后,我们用这些数据来估算算法的相对性能并介绍在实验中验证这些猜想所使用的工具。对应大多数实现,代码风格一致会使我们更容易做出对性能的合理猜想。

排序成本模型。在研究排序算法时,我们需要计算比较和交换的次数。对应不交换元素的算法,我们会计算访问数组的次数。

4、额外的内存使用

排序算法的额外内存开销和运行时间的同等重要的。排序算法可以分为两类:除了函数调用所需的栈和固定数目的实例变量之外无需额外内存的原地排序算法,以及需要额外内存空间来存储另一份数组副本的其他排序算法。

5、数据类型

我们的排序算法模板适用于任何实现了Comparable接口的数据类型。遵循Java惯例的好处是很多你希望排序 的数据类型都实现了Comparable接口。例如java中封装数字的类型Integer和Double,以及String和其他其他许多高级数据类型(如File和URL)都实现了Comparable接口。因此你可以直接用这些类型 的数组作为参数调用我们的排序方法。

在创建自己的数据类型的时候,我们只有实现Comparable接口就能够保证用例代码可以将其排序。要做到这一点,只需要实现该接口的CompareTo()方法来定义目标类型对象的自然次序。

对于v<w、v=w和v>w三种情况,Java的习惯在v.compare(w)被调用时分别返回一个负整数、零和正整数(一般是-1、0和1)。如果v和w无法比较或者两者之一是null,v.compareTo(w)将会抛出一个异常。此外compareTo()必须实现一个全序关系,即

  • 自反性:对于所有的v,v=v
  • 反对称性:对于所有的v<w都有v>w,且v=w时,w=v
  • 传递性:对于所有的v、w和x,如果v<=w且w<=x,则v<=x

从数学上说这些规则都很标准和自然,遵循他们应该不难。总之,CompareTo()实现了我们的主键抽象-它给出了实现了Comparable接口的任意数据类型的对象大小顺序的定义。需要注意是的CompareTo()方法不一定会用到进行比较的实例的所有实例变量,比较数组元素的主键很可能只是每个元素的一小部分

本章剩余篇幅将会讨论对一组自然次序的对象进行排序的各种算法。为了比较和对照各种算法,我们会检查他们的许多性质,包括在各种输入下它们比较和交换数组元素的次数以及额外内存的使用量。通过这些我们能够对它们的性能做出猜想,而这些猜想在过去的数十年间已经在无数的计算机上被验证过了。所有的实现都是需要通过验证的,所有我们也会讨论相关的工具。

现在开始我们跟着《Algorithms Fourth Editon》即算法第4版学习,欢迎一起交流学习QQ:806797785

仓库地址:https://gitee.com/gaogzhen/algorithm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值