查看: 23552| 回复: 50
跳转到指定楼层
上一主题 下一主题
收起左侧

[打卡]CS61B/61C

全局:
公开课
学校名称: UCB
Unit号: 2
开课时间: 2019-01-29
课程全名: CS 61B Data Structures
平台: 其他
URL: https://sp19.datastructur.es/

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x

国内有过五年 Web 前端经验,但实际上在工作过程中发现自己感兴趣的还是编译、构建、以及 Web 标准实现相关的事情。于是趁着登陆的这段没有工作的空窗期,开始自学 61B 与 61C,长期目标是把 CS 164 和 CS 162 做掉,并可以往 Node.js / V8 / Blink 项目贡献代码。

上周做完了 CS 61B 的 Project 0,这个项目特别棒,一步一步通过单元测试来验证功能,而由于脚手架的完备,使得你做完了算法层面的实现后就能有一个视觉的二维天体模拟器,成就感很强。

这周打算完成 61B 的 Week 3,61 C 的 Week 1 和 Week 2。

评分

参与人数 3大米 +8 收起 理由
yeehaah + 5 给你点个赞!
ericlee_ + 1 赞一个
debuger + 2 坚持!

查看全部评分


上一篇:【零基础转cs】刷CS61AB能用来加分申请吗
下一篇:udacity ab testing 打卡+总结
推荐
 楼主| convoi 2019-6-4 22:43:08 | 只看该作者
全局:
楼主,请问怎么可以下载到61c的lab和proj的code呢?


在课程 Lab1 的任务页面 https://cs61c.org/labs/lab01/ 这里翻到最后一节 Exercise 5,里面提到通过 GitHub Classroom 获取项目启动代码。这个 Classroom 不对你的身份做任何要求,只要有 GitHub 账号就可以加进去,GitHub 会自动生成一个你的账号结尾的私有仓库,然后在上面做作业。

还有61c有录视频嘛,我没有找到。


我也没有找到视频,所以这个课我是看课件和阅读材料的。

补充内容 (2019-6-4 23:15):
注意,如果你和我一样是旁听蹭课的,在加入 GitHub Classroom 的时候不要选上面的 Student ID (不然就冒领别人的学生身份了),直接 Skip this step 就可以了。
回复

使用道具 举报

推荐
 楼主| convoi 2019-6-6 11:30:40 | 只看该作者
全局:
今天听完了 CS 61B 的第七节 Testing,这一节主要是 Josh 以身示范(还戴上了一个棒球帽装学生)从一个学生的视角如何切入功能分解、单元测试、验证设计、重构这样一种高效的开发方式——也就是 TDD 测试驱动开发。在国内做业务的时候,TDD 其实用得不多,这里对于不同的人群,有两种原因:

- 大部分人不懂得如何写测试,团队项目里面也没有架构师搭建好测试框架
- 知道如何写测试的人会发现业务代码经常有许多的 IO/服务 的依赖,写单元测试需要对这些依赖进行 mock/stub,这一部分作为测试的基础设施,是需要时间去开发的。对,你需要开发测试用到的基础设施来保障业务的开发。

而对于算法教学来说,写单元测试非常高效。因为算法的输入输出非常明确,算法是业务代码的支撑。所以通过单元测试、反推函数设计的方式,可以一步一步把一个数据结构实现好。这和放纵人类的原始冲动实现一整个数据结构最后再来基于 log 测试要高效系统得多。但单元测试确实反人性,你需要对自己非常残忍。

这节课介绍的是 Java 常用的测试框架 JUnit。以前工作中用 JavaScript,测试框架是 Jest,总的来说这些测试框架实现的能力都差不多,Jest 命令行显示的 UE 要比 JUnit 好一些。但 JavaScript 在浏览器执行和在 Node 执行毕竟会有区别(JavaScript 是 ECMAScript 的超集)这就是 Java 这种纯后端语言的好处了。

如果你没有写程序的工作经验,推荐好好听第七节,一步一步照着走,思考单元测试是如何推动你的设计的。

最后做了 Proj 1a 的 Single Linked Dequeue。我依稀记得十年前实现双链表的时候花了一整天,就是我之前说的(按照人类本性写完了全部代码再来逐个逐个调试),从前年轻比较天真,想想也是蛮可爱的。十年后我终于只花了三个小时,其中一半时间都对着 iPad 在思考或者编写测试用例,最后再下手就稳多了,基本就是打键盘的苦力活。
回复

使用道具 举报

推荐
 楼主| convoi 2019-6-14 12:07:32 | 只看该作者
全局:
今天上午开始看 CS 61C 的第五节——终于开始讲 RISC-V 正题了,看了头几页幻灯片就开始觉得新东西有些多。跑到 Youtube 听了 MIT CS 6.004 的课 终于找到些感觉了。CS 6.004 的第二节也是 RISC-V 的介绍,但是浅显许多,但学生提的问题挺好的,例如为什么 RISC-V 的 operand 就要占掉 10bit ,但第二节因为才五十分钟,涵盖的没有 CS 61C 第五节多。听完了再回来看 CS 61C 第五节,理解清楚 Register-Register Operand / Register-Memory operand 之后事情就好多了,也意识到其实用 RISC-V 或者 MIPS 甚至 x86,本质还是要处理 CPU 的计算,CPU - 内存界面的数据交互的事情,那么用一个看起来优雅一些的架构,对于学习这门课本身来说,也还挺不错。这可能也是为什么 CS 61A 要使用 Python 的原因。

当看到这些平常稀松的 C 代码转成 RISC-V 之后,突然更理解为什么之前看到一些 ACMer 的代码这么喜欢循环的迭代器自减,敢情脑子里就是奔着汇编语言去的,只是把汇编语言翻译成 C 意思一下。

看到自己居然可以翻译出来一些 RISC-V 指令一度非常激动,我半个月前刚刚开始刷课的时候一定想不到半个月后的自己。

晚上提交了 eslint-plugin-ava 的 feature request,明天晚上该把时间给 babel 了。

今天,2019年6月13日,Raptors 夺冠了,人群欢呼。昨天东八区的人还在上演平行世界。

而我,眼里只有 RISC-V 和许许多多等着我的 Compiler Techniques。
回复

使用道具 举报

🔗
yii 2019-6-4 04:19:01 | 只看该作者
全局:
码住。也刚完成proj0,准备到这里来一起讨论
回复

使用道具 举报

🔗
ali1104 2019-6-4 22:21:56 | 只看该作者
全局:
楼主,请问怎么可以下载到61c的lab和proj的code呢?

补充内容 (2019-6-4 22:24):
还有61c有录视频嘛,我没有找到。。。
回复

使用道具 举报

🔗
 楼主| convoi 2019-6-4 22:56:14 | 只看该作者
全局:
昨天听完了 CS 61B 的第六节 ALists, Resizing, vs. SLists。ALists 就是以数组作为存储后台的列表,SLLists 则以单链表作为存储后台。

与 SLists 相比,ALists 的好处是可以像 Hash Table 一样在 O(1) 时间里获取到列表元素,但为了达到对任何一个元素都能方便地通过计算内存地址偏移来获取地址,ALists 要求每个元素类型相同,且 ALists 的存储占据的是连续的内存空间。而 SLists 像一串珍珠链,每个地址的内存块可大可小,因此 SLists 不需要要求每个元素类型相同。

因为连续的内存空间不可能无限大,ALists 需要根据容量进行扩容或者缩容。扩容和缩容都是另外开辟一个空间(通常是原来的两倍或者是一半),把现有的数据搬到新的内存地址。如果 SLists 是每次加元素就申请一次内存地址的话,ALists 则是累计一段时间再批量搬迁。

我非常推荐的学习方法是听到提问以后暂停视频,自己在 IDE/ 白纸里面去试一试,带着自己的回答,然后再继续听课。和学生时代相比,现在听公开课最好的一点是可以随时暂停,满足自己的学习习惯。

晚上手痒又去修了一个 babel 的 bug,上公开课和项目练手不冲突。推荐大家多多支持开源项目。
回复

使用道具 举报

🔗
ali1104 2019-6-5 21:31:48 | 只看该作者
全局:
convoi 发表于 2019-6-4 22:43
在课程 Lab1 的任务页面 https://cs61c.org/labs/lab01/ 这里翻到最后一节 Exercise 5,里面提到通过 G ...

好的,谢谢!!
回复

使用道具 举报

🔗
 楼主| convoi 2019-6-6 11:45:37 | 只看该作者
全局:
晚上又是惯例贡献开源代码的时间。我目前在 babel 项目中做这么一个问题:
在下面的 JavaScript 代码中
  1. let a = "outside";
  2. function f(g = () => a) {
  3.   let a = "inside";
  4.   return g();
  5. }
复制代码



如果使用 babel-traverse 的 rename 将变量 a 重命名成变量 z,那么目前的 babel 会将 () => a 也进行替换。实际上这个替换是错误的,因为这个时候 a 实际上引用的是上面的字符串 outside。

项目成员 Nicolo 告诉我的思路是在使用重命名访问器遍历之前检查参数列表,对这种情况,限制重命名的访问器只在函数体里遍历。所以一种简单的做法应该是:

1. 遍历参数列表,如果有这种情况,置一个状态变量 traverseBodyOnly 为 true

2. 如果有 traverseBodyOnly 为 true,只对函数 body 进行访问器遍历;否则,对整个函数进行访问器遍历

上面这种做法会导致参数列表在大部分情况下会被遍历两次,而我们希望只遍历一次整个函数,所以需要解决的问题是:

是否可以把遍历参数列表进行重命名与判断变量声明域结合?
遍历函数是否等价于遍历函数体以及遍历函数参数列表?

留到明天去思考吧,每天都可以专注一个开源项目真令人开心。各位晚安。
回复

使用道具 举报

🔗
 楼主| convoi 2019-6-7 12:14:31 | 只看该作者
全局:
今天听完了 CS 61C 的 Lecture 2 和 Lecture 3. 这两节基本上是 C 语言的 crash course。看第二讲的时候突然领悟到了指针是地址的容器这个观点,从前经常糊涂的指针也变得清晰起来。

第三讲中提到的程序地址空间的结构又是一个 Aha 的时刻。程序的地址空间分成 Stack, Heap, Static Data 和 Code,栈的内存地址会被不同的函数调用刷来刷去,所以不能在 C 里面这么写:

  1. int a[] = {1, 2, 3}
  2. return a;
复制代码


当函数结束以后,栈的内存地址就不一定还有效了。理解了地址空间的布局,这一段代码也就很自然清楚不可以这么写(尽管在 JavaScript 里面我们经常这么做)。

61C 的第一次 Project 就是写一个 61Ccc 编译器,让我们期待一下。
回复

使用道具 举报

🔗
 楼主| convoi 2019-6-8 11:43:08 | 只看该作者
全局:
今天听完了 CS 61B 的第八节 Inheritance, implements. 这一节介绍了 Java 的 Interface 继承与 Implementation 继承。后者是一个比较新的特性,在 Hackermoon 上面已经有人吐槽
其中一个难点在于编译时的类型和运行时类型可以有所区别,这样你可以初始化一个子类的实例,但声明它是一个父类的实例,当调用方法的时候,编译器会先到父类里面查询,看子类有没有 overrides 的,如果有就会选子类的同样方法。注意如果子类只是 overload 父类的方法(方法的 signature 不一样),那么这个时候是不会去调用子类的方法的。这也是这一页 PPT 的精华。

关于 Project 1a:之前已经完成了 LinkedList 为后台的 deque,发现 Array 后台的 deque 还挺有意思,把这个做完了以后就可以提交到 sp18 的 Autograder 上了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表