【CS61B】LEC4 SLLists, Nested Classes, Sentinel Nodes
SLLists, Nested Classes, Sentinel Nodes
裸数据结构Naked Data Structure IntLists
很难使用。为了正确使用 IntLists
,即使对于简单的列表相关任务,程序员也必须理解并利用递归。
Adding Clothes 我们首先将 IntList
类转变为 IntNode
类。然后我们将删除IntNode类中的所有方法,接下来我们将创建一个名为 SLList
的新类,该类首先包含实例变量,并且该变量的类型应为 IntNode
。本质上我们已经用 SLList
包装了我们的IntNode。
使用SLList 作为 SLList
的用户,要创建一个列表,我调用 SLList
的构造函数,并且希望填充列表的数字。然后,SLList
构造函数将使用该数字调用 IntNode
构造函数,并首先设置其指向刚创建的 IntNode
。
改进 注意当创建一个有一个值的列表时,我们谢了 SLList list = new SLList(1);
。我们不必担心像我们的IntList那样传递空值,本质上,SLList类充当列表用户和裸 IntList
之间的中间人。
Public vs Private 我们希望用户仅通过SLList
方法修改列表,而不要直接修改first
。我们可以通过变量访问权限设置为private来防止至其他用户这样做。编写 private IntNode first;
来防止其它类中的代码首先访问和修改(而该类中的代码仍然可以这么做)。
嵌套类Nested Classes 我们还可以将类移入类以创建嵌套类!您也可以将嵌套类声明为私有类。这样,其他类将永远无法使用此嵌套类。
静态嵌套类Static Nested Classes 如果 IntNode
类从不使用 SLList
类的任何变量或方法,我们可以通过添加 static
关键字将其变为静态。
递归帮助器方法Recursive Helper Methods 如果要在 SLList
中编写递归方法,我们将如何去做呢?毕竟,SLList
不是像 IntNode
这样的自然递归数据结构。一个常见的想法是编写一个用户可以调用的外部方法。此方法调用一个以 IntNode
作为参数的私有帮助器方法。然后,此辅助方法将执行递归,并将答案返回给外部方法。
缓存Caching 以前,我们通过返回 1+其余列表的大小来递归计算 IntList
的大小。如果列表很大,这将变得很慢,并且我们反复调用我们的 size
方法。现在我们有了一个 SLList
,让我们简单地将列表的大小作为实例变量进行缓存!请注意,在没有 IntList
之前我们无法做到这一点。
空列表 使用一个 SLList
,我们现在可以表示一个空列表。我们只需将 first
设置为 null
并将 size
设置为 0
。即,因为first现在为null,所以任何尝试访问first属性的方法(例如first.item)都将返回NullPointerException。当然,我们可以通过编写处理这种特殊情况的代码来解决此错误。但是可能会有很多特殊情况。有更好的解决方案吗?
前哨节点Sentinel Nodes 使所有 SLList
对象(甚至是空列表)都相同。为此,给每个 SLList
一个前哨节点,一个始终存在的节点。实际元素位于前哨节点之后,并且我们所有的方法都应尊重哨兵始终是列表中第一个元素的想法。
不变式Invariants 不变式是关于保证是正确的数据结构的事实(假设您的代码中没有错误)。每当我们向数据结构中添加功能时,这便为我们提供了一个方便的清单。还向用户保证将保留他们信任的某些属性。例如,带有前哨节点的SLList至少具有以下不变量:
- 前哨引用始终指向前哨节点。
- 前项(如果存在)始终位于
sentinel.next.item
。 size
变量始终是已添加的 items 总数。
- 原文作者:jchen
- 原文链接:http://jchenTech.github.io/post/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/CS61BLEC4/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。