讨论 12 | CS 61A 2024 春季学期
讨论 12:期末复习
提醒: 使用 Discord 与课程工作人员进行语音聊天。随时在 Discord 的 #discuss-queue 频道中向 @discuss 发送消息,课程工作人员会加入您小组的语音频道。
小组里派个人加入 Discord。 多人加入也可以,但一个人就足够了。
现在切换到 Pensieve:
- 所有人:访问 discuss.pensieve.co 并使用您的 @berkeley.edu 电子邮件地址登录,然后输入您的小组号码。(您的小组号码是您的 Discord 频道号码。)
进入 Pensieve 后,就不用再回到这个页面了;Pensieve 具有所有相同的内容(但具有更多功能)。如果由于某种原因 Pensieve 无法工作,请返回此页面并继续讨论。
如果您遇到问题,请在 Discord 上的 #help 频道中求助。
小提示: 你们中的任何人都可以在您小组的 Discord 频道文本聊天 中输入问题,并带有 @discuss 标签,会有课上的 staff 来解答。
开始
如果您的团队中只有 1 或 2 个人,您可以加入房间里的其他团队。
破冰游戏: 大家轮流介绍一下自己,再说说下学期最期待的非 CS/EECS 的课。
列表
列表最常见的两个修改操作是项目赋值和 append 方法。
>>> s = [1, 3, 4]
>>> t = s # 同一个列表的另一个名字
>>> t[0] = 2 # 这会将列表的第一个元素更改为 2,影响 s 和 t
>>> s
[2, 3, 4]
>>> s.append(5) # 这会将 5 添加到列表的末尾,影响 s 和 t
>>> t
[2, 3, 4, 5]
还有很多其他的列表操作方法:
append(elem):将elem添加到列表的末尾。返回None。extend(s):将可迭代对象s的所有元素添加到列表的末尾。返回None。insert(i, elem):在索引i处插入elem。如果i大于或等于列表的长度,则将elem插入到末尾。这不会替换任何现有元素,而只会添加新元素elem。返回None。remove(elem):删除列表中elem的第一次出现。返回None。如果elem不在列表中,则会出错。pop(i):删除并返回索引i处的元素。pop():删除并返回最后一个元素。
Q1:单词绳索
定义: Python 中的绳索是一个仅包含单字母字符串的列表,但最后一个元素除外,最后一个元素可以是单字母字符串或绳索。
实现 word_rope,这是一个 Python 函数,它接受一个非空字符串 s,该字符串仅包含字母和空格,并且不以空格开头或结尾。它返回一个绳索,其中包含 s 的字母,其中每个单词都在一个单独的列表中。
重要提示: 不能用字符串的切片,也不能用 split、find 或者 index 这些方法。使用列表操作解决问题。
提醒: s[-1] 的计算结果为序列 s 的最后一个元素。
你的答案
在 61A 代码中运行
解决方案
def word_rope(s):
"""返回字符串 s 中单词的绳索。
>>> word_rope('the last week')
['t', 'h', 'e', ['l', 'a', 's', 't', ['w', 'e', 'e', 'k']]]
"""
assert s and s[0] != ' ' and s[-1] != [ ]
result = []
word = result
for x in s:
if x == ' ':
word.append([])
word = word[-1]
else:
word.append(x)
return result
在这个实现中,result 代表一个绳索结构,而 word 则是在这个绳索结构中正在被构建的列表。当 x 为空格时,在 word 的末尾添加一个空列表,然后将 word 指向这个新的空列表。否则,将 x 添加至 word 的末尾。
链接列表
链接列表是一个 Link 对象或 Link.empty。
你可以通过以下两种方式修改 Link 对象 s:
- 使用
s.first = ...改变第一个元素 - 使用
s.rest = ...改变剩余的元素
你可以通过调用 Link 来创建一个新的 Link 对象:
Link(4)创建一个长度为 1 且包含 4 的链接列表。Link(4, s)创建一个以 4 开头,后跟链接列表s的元素的链接列表。
class Link:
"""A linked list is either a Link object or Link.empty
>>> s = Link(3, Link(4, Link(5)))
>>> s.rest
Link(4, Link(5))
>>> s.rest.rest.rest is Link.empty
True
>>> s.rest.first * 2
8
>>> print(s)
<3 4 5>
"""
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __repr__(self):
if self.rest:
rest_repr = ', ' + repr(self.rest)
else:
rest_repr = ''
return 'Link(' + repr(self.first) + rest_repr + ')'
def __str__(self):
string = '<'
while self.rest is not Link.empty:
string += str(self.first) + ' '
self = self.rest
return string + str(self.first) + '>'
Q2:线性子列表
定义: 链接列表 s 的 子列表 是 s 中一些元素的有序链接列表。例如,<3 6 2 5 1 7> 具有子列表 <3 2 1> 和 <6 2 7>,但不具有 <5 6 7>。
定义: 数字链接列表 s 的 线性子列表 是相邻数字之间的差始终相同的子列表。例如,<2 4 6 8> 是 <1 2 3 4 6 9 1 8 5> 的线性子列表,因为每对相邻元素之间的差为 2。
实现 linear,它接受一个数字链接列表 s(Link 实例或 Link.empty)。它返回 s 的最长线性子列表。如果两个线性子列表的长度相同,则返回其中任何一个。
你的答案
在 61A 代码中运行
解决方案
def linear(s):
"""返回链接列表 s 的最长线性子列表。
>>> s = Link(9, Link(4, Link(6, Link(7, Link(8, Link(10))))))
>>> linear(s)
Link(4, Link(6, Link(8, Link(10))))
>>> linear(Link(4, Link(5, s)))
Link(4, Link(5, Link(6, Link(7, Link(8)))))
>>> linear(Link(4, Link(5, Link(4, Link(7, Link(3, Link(2, Link(8))))))))
Link(5, Link(4, Link(3, Link(2))))
"""
def complete(first, rest):
"The longest linear sublist of Link(first, rest) with difference d."
if rest is Link.empty:
return Link(first, rest)
elif rest.first - first == d:
return Link(first, complete(rest.first, rest.rest))
else:
return complete(first, rest.rest)
if s is Link.empty:
return s
longest = Link(s.first) # The longest linear sublist found so far
while s is not Link.empty:
t = s.rest
while t is not Link.empty:
d = t.first - s.first
candidate = Link(s.first, complete(t.first, t.rest))
if length(candidate) > length(longest):
longest = candidate
t = t.rest
s = s.rest
return longest
def length(s):
if s is Link.empty:
return 0
else:
return 1 + length(s.rest)
以下是三种情况:
- 如果
rest为空,则返回仅包含first的单元素列表。 - 如果
rest.first属于以first开头的线性子列表,则构建一个包含first和rest.first的列表。 - 否则,执行
complete(first, rest.rest)。
这个 while 循环会为每两个可能的起始值创建一个 candidate 线性子列表,即 s.first 和 t.first。线性子列表的其余部分必须在 t.rest 中。
Scheme
Q3: 递增绳
定义: Scheme 中的绳(rope)是一个非空列表,其中除了最后一个元素外,只包含数字,最后一个元素可以是数字或绳。请注意,此处的“绳 (rope)”是一种特殊的、非常规的数据结构。
实现 up,这是一个接受正整数 n 的 Scheme 过程。它返回一个包含 n 的数字的绳,该绳是最短的绳,其中同一列表中每对相邻的数字都按递增顺序排列。
提醒: quotient 过程执行向下取整除法,类似于 Python 中的 //。 remainder 过程类似于 Python 中的 %。
你的答案
在 61A 代码中运行
解决方案
(define (up n)
(define (helper n result)
(if (zero? n) result
(helper
(quotient n 10)
(let ((first (remainder n 10)))
(if (< first (car result))
(cons first result)
(list first result))
))))
(helper
(quotient n 10)
(list (remainder n 10))
))
(expect (up 314152667899) '(3 (1 4 (1 5 (2 6 (6 7 8 9 (9)))))))
通过比较 first 和 (car result),来决定是否将值 first cons 到 result 上,或者创建一个包含 first 和 result 的新列表。
为了从 up 中正确调用 helper,需要构建一个仅包含 n 的最后一位数字的绳,即 (remainder n 10)。
SQL
SELECT 语句描述了一个基于输入行的输出表。 要编写一个:
- 使用
FROM和WHERE子句描述输入行。 - 分组这些行,并使用
GROUP BY和HAVING子句确定哪些组应显示为输出行。 - 使用
SELECT和ORDER BY子句格式化和排序输出行和列。
SELECT (步骤 3) FROM (步骤 1) WHERE (步骤 1) GROUP BY (步骤 2) HAVING (步骤 2) ORDER BY (步骤 3);
步骤 1 可能包括使用逗号连接多个表,从而生成包含现有表中两行或多行数据的输入行。
WHERE、GROUP BY、HAVING 和 ORDER BY 子句是可选的。
Q4:一条秘密消息
替换密码用表中的另一个单词替换每个单词,以加密消息。 要解码加密消息,请将每个单词 x 替换为代码表中相应的 y。
编写一个 select 语句,使用 code 表解码 original 消息 It's The End。
你的答案
在 61A 代码中运行
解决方案
CREATE TABLE original AS
SELECT 1 AS n, "It's" AS word UNION
SELECT 2 , "The" UNION
SELECT 3 , "End";
CREATE TABLE code AS
SELECT "Up" AS x, "Down" AS y UNION
SELECT "Now" , "Home" UNION
SELECT "It's" , "What" UNION
SELECT "See" , "Do" UNION
SELECT "Can" , "See" UNION
SELECT "End" , "Now" UNION
SELECT "What" , "You" UNION
SELECT "The" , "Happens" UNION
SELECT "Love" , "Scheme" UNION
SELECT "Not" , "Mess" UNION
SELECT "Happens", "Go";
SELECT y FROM original, code WHERE word=x ORDER BY n;
连接 original 表和 code 表,确保连接后的行中,word 列和 x 列的值相同。
接下来该怎么做? 编写另一个 select 语句,使用相同的 code 表解码此加密消息。
你的答案
在 61A 代码中运行
解决方案
CREATE TABLE original AS
SELECT 1 AS n, "It's" AS word UNION
SELECT 2 , "The" UNION
SELECT 3 , "End";
CREATE TABLE code AS
SELECT "Up" AS x, "Down" AS y UNION
SELECT "Now" , "Home" UNION
SELECT "It's" , "What" UNION
SELECT "See" , "Do" UNION
SELECT "Can" , "See" UNION
SELECT "End" , "Now" UNION
SELECT "What" , "You" UNION
SELECT "The" , "Happens" UNION
SELECT "Love" , "Scheme" UNION
SELECT "Not" , "Mess" UNION
SELECT "Happens", "Go";
SELECT b.y
FROM original, code AS a, code AS b
WHERE word=a.x AND a.y=b.x
ORDER BY n;
将 original 表与别名为 a 和 b 的 code 表连接起来,会生成类似这样的六列数据行:2|The|The|Happens|Happens|Go。其中,末尾的 Go 是解码后的消息片段。
时间安排: 这是最后一次讨论,但你们可以安排下周与你们的小组会面,为考试做准备。 如果你们想用,RRR 周期间你们平时的讨论室和时间应该仍然可以使用。
记录这一时刻
请大家填写出勤表 (每人每周提交一次).
重要: 请在离开前帮忙把房间里的家具放回原位。 谢谢!