Raymond's Notebook
日拱一卒无有尽,功不唐捐终入海
MIT 算法导论(1) - 算法分析,学习记录

算法导论,是MIT非常经典的一门算法课程,之前也买过(CLRS)来看,但是一直没有坚持看完,里面有很多数学证明非常饶头 :(
这次找来视频,准备好好学习一遍。

1. MIT’s Introduction to Algorithms, Lectures 1 and 2: Analysis of Algorithms
首堂课的核心是算法分析,然而算法分析到底是什么?

算法分析 就是关于计算机性能和资源使用的理论研究
“Analysis of algorithms is the theoretical study of computer program performance and resource usage”.

第一讲给我的感觉就是,你真的需要记笔记,不懂的地方需要来回多看几次视频,主讲老师本身就是《算法导论》的作者,几乎句句经典没什么废话。
一上来就是切入主题,讲如何分析算法,并详述了渐进分析思路,被他成为:Big Idea,该分析方法的思想主要集中在如下几点:

  • 首先忽略掉那些依赖机器的常量;
  • 以及,不去检查算法实际运行时间,而是关注运行时间的增长;
    T(n), n -> ∞,也即,当 n 趋近于无穷大时,运行时间 T(n) 的增长(或者说,如何变化,比如有些算法突破某个点时,耗费时间是急剧增加,有些则是缓慢增长)

算法的选择实际上很多时候是依据具体情况做权衡,某些看上去很慢的算法,在数据量较小的时候,也许优于其他看似快速的算法。因为某些算法必需突破某个点时,才能显现其速度优势,但是这个点的规模也许已经大到计算机无法运行的地步,因此我们有时会对一些相对低速的算法感兴趣。

接下来,Charles E. Leiserson 教授采用渐进法,对插入排序(Insertion Sort)和 归并排序(Merge Sort)进行了完整的时间复杂度分析。具体分析过程大家可以看视频,我主要想说自己的几点感想:

  • 数学证明在算法分析上面确实可行,理解它对于帮助我们理解算法确实有很大帮助;
  • 伪代码确实可以帮助我们了解算法的理论,并且可以在一定程度指导我们如何编写实际的代码;
  • 理解算法的原理和是否能够写出算法的实现,真的是两码事,重要的事,我不想再说很多遍,这个真的不一样;你可以设计一个算法,你可以用数学不等式证明你算法的有效性,但是你不一定能够用一种语言正确的实现该算法。具体到代码层面,真的和工程实践有关,你必须不断练习,才能写出正确无误的代码。因此,当你上完课,仍然无法实现该算法的时候,不要灰心,我猜很多人都是如此。满脑理论,一写就废,不在少数。 据统计,去谷歌面试的工程师,能够现场写出正确无误的二分查找算法的人,连一半都没有 :)

最后,附上我用Golang实现 Insertion Sort 和 Merge Sort 的代码:
//Chapter 2.1, insertion sort, implement it by golang
//Author: Raymond Jiang
//Date:   2019-06-20

//Insertion Sort O(n*n)
func InsertionSort(arrs []int) {
    for i := 1; i < len(arrs); i++ {
        key := arrs[i]
        j := i - 1
        for j >= 0 && arrs[j] > key {
            arrs[j+1] = arrs[j]
            j--
        }
        arrs[j+1] = key
    }
}    
//Chapter 2.3, merge sort, implement it by golang
//Author: Raymond Jiang
//Date:   2019-06-25

//Merge sort O(n*lgn)
func MergeSort(arrs []int, p, r int) {
    if p < r-1 {
        q := (p + r) / 2

        MergeSort(arrs, p, q)
        MergeSort(arrs, q, r)
        Merge(arrs, p, q, r)
    }
}
func Merge(arrs []int, p, q, r int) {
    left := make([]int, q-p)
    copy(left, arrs[p:q])

    right := make([]int, r-q)
    copy(right, arrs[q:r])

    j := 0
    i := 0

    for k := p; k < r; k++ {
        if i == len(left) && j < len(right) {
            arrs[k] = right[j]
            j++
            continue
        }
        if j == len(right) && i < len(left) {
            arrs[k] = left[i]
            i++
            continue
        }
        if left[i] < right[j] {
            arrs[k] = left[i]
            i++

        } else {
            arrs[k] = right[j]
            j++
        }
    }
}

第1讲视频地址