Featured image of post CS61B week12 学习笔记

CS61B week12 学习笔记

包括第十二周讲座内容

lec29 Basic Sorts

排序的性质

需要满足两点:

  • 三段论:如果 a<b, a=b,那么 b<a
  • 传递性:如果 a<b, b<c,那么 a<c

从另一个观点来看,排序就是让数组中的逆序的数量变为 0。

排序

选择排序

简单的算法。每次从数组中选择最小的元素放到前面,那么前面就是从小到大的。重复这个步骤。时间复杂度为 $\Theta(n^2)$。

初始的堆排序

将所有的元素插入 max 堆中,然后重复 N 次:

  • 从堆中删除最大的元素
  • 将最大的元素放在输出数组未使用的后方

插入总共耗费 $O(n\log(n))$,选择最大元素耗费 $\Theta(1)$,移除最大元素 n 次,每次消耗 $O(\log(n))$。所以总的时间复杂度为 $O(n\log(n))$。

这个方法除了初始数组,还需要新建两个数组:一个为了代表 max 堆,另一个为了储存输出元素。显然,这样对空间的消耗较大。

就地的堆排序

考虑不使用其他数组,而是在输入的基础上使用堆排序。首先,看成是没有排序的堆。因此,需要不断让靠后的元素向上,保证堆的性质。

接着,每次删除最大元素,也就是移除第一个元素,然后将最后一个元素放到第一个元素,下沉。最后消耗 $O(n\log(n))$ 的时间。因为不新建数组,所以空间复杂度为 $\Theta(1)$。

归并排序

将数组分成两部分。分别递归让左右排序好,然后新建数组,分别去除两个有序数组的最小项。时间复杂度为 $\Theta(n\log(n))$,空间复杂度为 $\Theta(n)$。

插入排序

每次对于未排序的第一个元素,在排序的元素中比较,向前交换,直到顺序正确。时间复杂度最低为 $\Omega(n)$,最高为 $O(n^2)$。

如果有一个几乎排序好的数组,那么插入排序很快。

总结

lec29-1.png

lec30 Quick Sort

插入排序

如果有一个排序好的数组。随机选择一个数字,改变该数字。这时候,最好的算法是什么?答案是插入排序。插入排序的时间消耗正比于逆序的数量。

同时,对于较小的数组,例如数量小于 15,插入排序也很快。

快速排序

背景

假设有一个字典,对应英文和俄文。需要将英文句子里的每个单词翻译成对应的俄文。字典中英文是排序好的,这时候利用二分查找需要 $O(\log(n))$ 的时间。然而,在 60 年代只有磁带来储存,并没有 RAM 的随机读取性能,所以没有二分查找的性能。

所以,可以先排序句子,然后扫描一次磁带。然而,这又涉及到排序句子的问题。

Partitioning

找到数组中某个元素 x,然后移动到位置 j,保证左侧的元素都小于等于 x,右侧的元素都大于等于 x。

可以三次扫描数组,第一次将小于 x 的元素放到新的数组中,第二次找到 x,第三次将大于 x 的元素放入新数组。也可以用双向队列实现。

实现

当选择一个元素,进行 partitioning 后,这个元素已经到了正确的位置。接下来,可以利用递归处理剩下的左右两个部分。

性能

快速排序的性能主要取决于 partition 的操作。在理想的情况下,表现为 $\Theta(n\log(n))$;如果本来就是顺序的,那么此时表现很差,为 $\Theta(n^2)$。

快速排序和 BST 的思想很像。可以利用概率论证明,绝大多数情况下,快速排序的性能是 $\Theta(n\log(n))$。

lec30-1.png

lec31 Software Engineering II

复杂的代码

复杂的代码有两大特征:

  • 依赖性:一块代码不能独自地阅读、理解和修改
  • 迷惑性:重要的信息不显然

模块化设计

使用模块化设计可以有效减少复杂性,例如使用帮助函数和帮助类。模块一词可以指代很多东西,例如类、包、一段代码等等。模块之间不可能完全独立,但是需要处理好如何在模块之间传递信息。理想情况下,目标就是尽可能减少模块之间的依赖性。

最好的模块同时具有简单的接口和复杂的实现方式。通过简单的接口,可以简化调用,并且也方便修改。这就实现了隐藏内部的复杂性。例如,利用红黑树实现 Map,就做到了这一点,外界完全不用知道红黑树是怎么实现的。

信息隐藏的反面就是信息暴露。如果在较高的抽象层直接从很低的抽象层操纵事务,就会导致复杂性很高。软件工程师的必要技能之一就是敏锐地察觉到信息暴露的情况。

推荐的做法:

  • 创造类和接口,实现封装复杂性。
  • 创造 ‘deep’ 的模块,拥有简单的接口和复杂的实现方式。
  • 不要过度依赖“暂时分解模块”。
  • 战略性,而不是战术性。
  • 为你自己隐藏信息。

团队协作

有些团队在各种工作中都做得很好,有的相反。这就引出了团队智力。但是,团队智力并不是个体智力的平均值或最高值。

团队智力与社会关系的敏感度有关,以及成员之间是否充分参与。团队协作和人际关系高度相关。

接受反馈有时候会感觉糟糕。不过,要认识到建设性的反馈肯定是有益的。同时,也要学会正确地提供反馈。

使用 Hugo 构建
主题 StackJimmy 设计