讨论 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 周期间你们平时的讨论室和时间应该仍然可以使用。
记录这一时刻
请大家填写出勤表 (每人每周提交一次).
重要: 请在离开前帮忙把房间里的家具放回原位。 谢谢!