这是一门UCB开设的 CS 专业核心基础课程。
其前身是针对课程及课本:SICP: Structures and Interpretation of Computer Programs 的一门课程。能够学习到基本的编程概念,软件工程概念,程序设计概念。主要练习了 Python 编程,函数式编程,面向对象编程,LISP Scheme 语言。适合大一学习。我是在大二上学期才学的。。。历时3个月业余时间 (懒 + 过年…,大概百来个小时差不多)。有很多具备反馈的 lab 和交互式的 homework,有几个好玩的 project,最后一个 project 是用 python 实现一个 scheme 解释器很有意思,为后续各种学习都能做一个导论,比学校大一开的谭浩强c 语言指针都讲不到的PPT reading计导课不知道高到哪里去了,后悔没有早点跟这个学习。
课程具体的开发环境是 linux 下,hw、lab 都具备 ok 程序可以用来评判代码,使用时加 --local 禁止打开网页输入邮箱即可。
把总结学到的内容的概要放上来方便自己回顾。也能分享这门课能学到什么给有需要的人,可以观看下面的大纲初步了解这门课的一些内容。
学习课程链接:CS 61A Fall 2020
HOF
- 函数第一公民, dependency injection, 依赖注入(指函数作为参数)
- 熟悉lambda函数
- 柯里化的原理
- 装饰器(包装一个函数), 重点学习trace包装器和后面学到的尾递归优化包装器
- 变量的immutability
- scope与environment的概念
- 掌握GCD的递归解法 (辗转相除/减)
- 掌握牛顿法逼近零点(以及数值的求导)
递归和迭代的熟悉
- 掌握两种递归: 尾递归和先递归
- 编写递归的心情: 只关心什么关系(不用想太多)
- 掌握递归的immutable var 和 迭代的mutable var 区别
- helper 的作用
- Mutual recursion, 关注轮流的情况, 经典例子是fgh函数序列
- Tree recursion, Tree recursion 无法优化, 经典是DP的递归基练习, 找钱问题
- 迭代可以把不变量转为参数从而转为递归
设计准则
- 能抽象, 有必要抽象(封装等手段)请抽象, 本课程关注函数抽象
- 名词和动词的使用
- TDD
抽象
- 构造器和数据选择器
- 理解selectors 和properties 的区别(应当提供抽象和接口而不是内置实现)
- 行为和实现的隔离
- 理解函数也可以表示数据
非线性结构
- 广义列表就是树, 理解层次结构, 广义表是FP术语
- 理解数据的闭包属性(递归定义), 对比函数式的闭包(即通过变量生成函数内常量的方法)
- 熟悉了树形递归的base case编写
- 了解剪枝是什么(prune)
- 掌握permutation, 全排列的树状递归和剪枝
打字游戏编写
- 理解函数抽象对思考解决大问题的帮助
- 理解权值打分机制对程序自动决策的作用
- 掌握MED, 最小编辑距离的递归写法, 熟悉Leetcode的同题目的迭代/DP写法, 后面学习尾递归优化后, 练习尾递归写法
CS导论杂项
- 阅读了编码,
- 理解晶体管是什么, 掌握继电器版本的计算机构造法(略),
- 了解ASCII是有规律的0x3x是数字.
可变操作和可变数据和可变函数
- 理解副作用和引用透明
- 理解函数式编程的lazy computaion
- 了解了区间计算中的两个数据有依赖的难题(interval computation)
- 理解了为什么要有environment 和non-local 等区分.
通过迭代器理解迭代抽象
- 理解一次性导致的迭代器不应该在递归出现
OOP, OOD 以及通用的
- HAS-A, IS-A, LIKE-A 应该使用的OOP实现方法
- 学习了EMAIL服务器和客户端的十分粗糙的OOP模型
- 蚂蚁打蜜蜂项目: 深入理解抽象, 不能打破抽象,
- 理解什么应该抽象, 怎么抽象(复习大一JAVA课程)
- 基类方法对继承类来说很重要, 即使使用空的基类方法
- 掌握现代OOP语言中的迭代器的删除问题(十年前的面试题?)
- 练习分解问题的思维(decomposition)
- 吃一堑: while/if/else中出现的提前结束一定要return/break!
学习了链表和树结构的一些处理, 包括遍历等等.
- 链表继续熟悉 (都是老生常谈,对常规的问题再研究一些follow up 问题)
- 树要掌握一些树的遍历操作(复习一下二叉树表示的普通树的操作方法, 怎么通过操作访问二叉树去操作访问树)
- 复习了一遍has_cycle, 现在应该能写has_cycle和找entry的follow up了
数学思维与抽象, 代价评估
- 理解同构是什么
- 学习了算法和问题也有同构的思想方法(神奇的卡特兰数)
- 掌握使用二分法求指数的方法
LISP 语言语法学习
- LISP (list processing) 的精髓是所有东西都是一个 list, procedure 和 data 都是 list.
- Symbolic Programing, 理解用程序编写程序的思想方法, 程序生成程序也就是 meta programing
- 所有的 while 都可以转换成一个带参数递归函数来编写
- 再次复习引用透明的含义以及Cherch-rosser theorem, 无论是 call by value (参数先计算) 还是 call by name (procedure 名 先计算), 都有参数先计算再计算 procedure 值的顺序 (参数在被传入 procedure 计算时先求得参数的值).
控制流的概念
- 对于连续的控制流, 没有中断和跳转
- 错误的种类 等
- runtime
- syntax
- value
- type
程序解释
- 元语言抽象 metalinguistic abstraction 是化解复杂度的方法, 通过创建一个DSL或者 tailored script 来继续简化表达.
- 区分语法syntax和语义semantics, 一个是建立语法树的结构形式, 没有内容, 语义是拥有含义的语法, 语义错误可能是执行错误或者类型错误.
- 一门语言必须有一个canonical implementation 作为标准, 就是一个标准解释器.
- 解释过程经过lexical 文法分析分离关键字, syntactic 语法分析tokens得到表达式(描述语句的结构).
- token 解析的时候使用 buffer 抽象一个从输入中获取行和过滤的方法, 避免直接操作字符输入缓冲区.
- 了解递归语法分析和递归下降语法分析, 这要求语言是LL(1)文法, 具备一个递归结构.
- Homoiconic 同像的概念, Lisp 就是同像的把数据和程序共用一种列表表述.
- 语法上可以把表达式分为 primitive expression 和 call expression, 符合递归的分类.
- 用语法树来表达分析结果符合递归的表达式.
- 递归下降法解释程序, 使用 eval 和 apply 实现, 两个函数相互调用, 这是因为 eval 的表达式中可能需要 apply, apply 要实现又必须 eval 所有的参数以及 proceudre 名字.
- 栈的实现, 怎么继承命名空间, 最简单的是通过一个字典副本.
基本 SQL
课程中练习到的一些编程经验归纳方便回顾
算法解题
- GCD 计算方法, 大数减/模小数, 小数和结果迭代
- 牛顿迭代求零点, 用于开方可证明. xn+1 = xn - f(xn) - f'(xn)
- Count-partition 分区递归基础及DP转换, 学习状态转移方程, 不关心怎么做. 递归解题中 helper 的作用.
- MED, 最小编辑距离, 递归解法和 DP 解法, 不遗漏的分类以及等价类简化.
- Permutaion 学习回溯法中的 state restore
- Catalan Number 与同构问题分析法.
- 二分法求指数以及memo fib, 学习时空复杂度的优化.
- 链表判断 has cycle 的双指针法
编程要点
- dependency injection 实现模块分离.
- decorator 思想来添加功能, 继承的思想, 中间层思想, 兼容思想.
- 轮流递归 Mutual recursion 的用法, 可以实现分类的递归.
- Data/Function Abstraction 通过抽象减少程序编写的复杂度, 有必要抽象就抽象.
- 命名方法, noun & verb
- TDD 减少 Debug 烦躁
- Selectors & properties 辨析, properties 不应该直接访问, 违反了 barrier. 隔离 isolation 的实现
- 权值评估机制, 如打字游戏 accuracy 定义和 wpm 定义, autocorrect 中 grade system 以及 MED 最小编辑距离. 评分机制能用来实现决策.
- 决策上限 limit , 对于涉及复杂计算的决策过程, 或者是最优化过程, 可以限制最优化程度, 达到一个平衡, 平衡最优和性价比.
- Tree 结构的子树 pruning 剪枝算法, 以及剪枝对于算法优化, 问题解决的过程中的一个尽早抛弃思想.
- Email server 的 CS 模式, 以及 OOP 编写一个 CS 系统的 toy.
- 模块化设计 modular design 的思想, 减少编写的复杂度, 降低耦合. (模块内高内聚)
- OOP 类设计的一些方法:
- 类抽象, 需要用什么样的类来表达什么概念, 各种类各自要解决什么样的问题, 进行什么样的动作.
- Attributes 的选择, 哪些 atributes 是可变的, 哪些是固有的, 决定是类的变量还是实例的变量. 属性是类内的数据形式, 对外应该展现为选择器.
- 基类应该尽可能地提供通用的方法, 甚至是提供空的方法, 让子类 inherit 或者 override.
BUG FREE 要点
- TDD
- while 里面提前 break 或者 continue (原来我不论在哪都犯这个错误)