Skip to main content

讨论 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 的字母,其中每个单词都在一个单独的列表中。

重要提示: 不能用字符串的切片,也不能用 splitfind 或者 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,它接受一个数字链接列表 sLink 实例或 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 开头的线性子列表,则构建一个包含 firstrest.first 的列表。
  • 否则,执行 complete(first, rest.rest)

这个 while 循环会为每两个可能的起始值创建一个 candidate 线性子列表,即 s.firstt.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 consresult 上,或者创建一个包含 firstresult 的新列表。

为了从 up 中正确调用 helper,需要构建一个仅包含 n 的最后一位数字的绳,即 (remainder n 10)

SQL

SELECT 语句描述了一个基于输入行的输出表。 要编写一个:

  1. 使用 FROMWHERE 子句描述输入行
  2. 分组这些行,并使用 GROUP BYHAVING 子句确定哪些组应显示为输出行。
  3. 使用 SELECTORDER BY 子句格式化和排序输出行和列。

SELECT (步骤 3) FROM (步骤 1) WHERE (步骤 1) GROUP BY (步骤 2) HAVING (步骤 2) ORDER BY (步骤 3); 步骤 1 可能包括使用逗号连接多个表,从而生成包含现有表中两行或多行数据的输入行。

WHEREGROUP BYHAVINGORDER 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 表与别名为 abcode 表连接起来,会生成类似这样的六列数据行:2|The|The|Happens|Happens|Go。其中,末尾的 Go 是解码后的消息片段。

时间安排: 这是最后一次讨论,但你们可以安排下周与你们的小组会面,为考试做准备。 如果你们想用,RRR 周期间你们平时的讨论室和时间应该仍然可以使用。

记录这一时刻

请大家填写出勤表 (每人每周提交一次).

重要: 请在离开前帮忙把房间里的家具放回原位。 谢谢!