链表

链表

中等

简介

你正在参与一个项目,为繁忙的铁路网开发一套列车调度系统。

有人请你为调度系统中的列车路线开发一个原型。每条路线由一串火车站组成,某趟列车会依次停靠这些车站。

说明

你的团队决定用双向链表来表示时刻表中的每条火车路线。 火车路线沿途的每个车站都由链表中的一个节点表示。

你不需要操心各个车站的到达和出发时间。 每个车站只用一个数字表示就好。

路线可以延长,在路线的开头或末尾增加车站。 也可以从路线的开头或末尾移除车站来缩短。

有时某个车站会关闭,这时即使它不在路线的开头或末尾,也需要把它从路线中移除。

路线的大小不是以火车行驶的距离来衡量,而是以它停靠的车站数量来衡量。

Note

链表是计算机科学中的一种基础数据结构,常用来实现其他数据结构。 顾名思义,它是一串链接在一起的节点。 它是一串“节点”,其中每个节点都链接到它的一个或多个相邻节点。 在单向链表中,每个节点只链接到它后面的那个节点。 在双向链表中,每个节点既链接到它前面的节点,也链接到它后面的节点。

如果你想深入了解链表,可以看看这篇文章,它用漂亮的图示做了讲解。

本练习在 Python 中的结构

链表可以用各种方式实现,底层也可以使用各种数据结构,但这里我们要求你用面向对象的方式来实现链表。

在存根文件中,你会看到Node类和LinkedList类的开头部分。 你的Node类应该记录自己的值,以及前后相邻的节点。 push、pop、shift、unshift以及len对应的特殊方法,都应该在LinkedList类中实现。 你会发现,实现一个用于迭代的特殊iter方法可能也很有用。

与核心练习不同,我们会通过对空的LinkedLists调用pop和shift来测试错误情况,所以你需要恰当地raise错误。

最后,除了上面列出的方法,我们还希望你实现delete。 delete接受一个实参,即要从链表中移除的值。 如果这个值出现多次,只应移除第一个。


异常消息

有时需要抛出异常。这样做时,你应该始终附上一条有意义的错误消息,说明错误的来源是什么。 这能让你的代码更易读,对调试也有很大帮助。 如果你知道错误来源属于某个特定类型,可以选择抛出内置错误类型中的一种,但仍然应该附上有意义的消息。

本练习要求:当链表中找不到正被delete()的节点值时,使用 raise 语句“抛出”ValueError。 此外,如果没有节点可供pop(),应该抛出IndexError。 只有既raise这些exceptions又附带消息,测试才会通过。

要抛出带消息的ValueError,请把消息写成该exception类型的实参:

# When the value passed to `delete()` is not found.
if not found:
    raise ValueError("Value not found")

要抛出带消息的IndexError,请把消息写成该exception类型的实参:

# When pop() is called and there are no nodes left in the linked list
if self.length == 0:
    raise IndexError("List is empty")

Python 中的特殊方法

本练习的测试还会对你的LinkedList调用len()。 为了让len()正常工作,你需要创建一个__len__特殊方法。 关于在 Python 中实现特殊方法(即“dunder”方法)的详情,请参阅 Python 文档:基本对象定制 和 Python 文档:object.len(self)。

我们还建议创建一个特殊的__iter__方法,帮助你遍历链表。



来源

经典的计算机科学主题
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Python Exercism

准备好开始 链表 了吗?

注册 Exercism,借助 17 个概念146 个练习 和真人导师指导,学习并掌握 Python,全部免费。