本文内容为重写上一节课中的单链表,将其重构成更易于用户利用的链表,实现多种操作链表的方法。
1. 重构单链表SLList
在上一节课中编写的 IntList 类是裸露递归的形式,在 Java 中一样平常不会这么定义,因为如许用户大概必要非常了解引用,而且可以大概递归地思考,才能利用这个类。
因此我们必要实现一个更容易利用的单链表(Singly Linked List),首先我们定义节点类 IntNode:
- package CS61B.Lecture4;
- public class IntNode {
- public int val;
- public IntNode next;
- public IntNode(int val, IntNode next) {
- this.val = val;
- this.next = next;
- }
- }
复制代码 现在就可以创建单链表类 SLList:
- package CS61B.Lecture4;
- public class SLList {
- private IntNode head;
- public SLList(int val) {
- this.head = new IntNode(val, null);
- }
- public static void main(String[] args) {
- SLList L = new SLList(5);
- }
- }
复制代码 之前用户利用单链表必要如许定义:IntList L = new IntList(5, null);,他必要有递归考虑的思想,必须指定所指向的下一个链表的空值。
由于 IntNode 类只有在 SLList 类中利用才有意义,且用户一样平常不会单独去利用 IntNode 类,因此可以将其作为嵌套类放入 SLList 中,而且可以利用 private 关键字控制其权限:
- package CS61B.Lecture4;
- public class SLList {
- private static class IntNode {
- public int val;
- public IntNode next;
- public IntNode(int val, IntNode next) {
- this.val = val;
- this.next = next;
- }
- }
- private IntNode head;
- public SLList(int val) {
- this.head = new IntNode(val, null);
- }
- public static void main(String[] args) {
- SLList L = new SLList(5);
- }
- }
复制代码 注意到我们还将 IntNode 类定义为静态的,静态嵌套类与外部类的实例无关,它更像是一个独立的类,但逻辑上仍然属于外部类的范畴,静态嵌套类可以直接访问外部类的静态字段和方法,但不能直接访问外部类的实例字段和方法(除非通过外部类的实例),因此静态嵌套类通常用于逻辑上与外部类相关,但不必要依靠外部类实例的场景。
2. 实现操作链表的方法
现在我们实现操作链表的几种方法:
必要重点思考的是如何用递归的方式求解链表的长度,我们利用的是构造一个辅助方法 size(IntNode p) 使得用户可以通过 size() 方法直接获取链表长度。
3. 优化效率
我们现在关注 size() 方法,发现每次用户必要查看链表长度时都必要遍历一次链表,因此我们可以用一个变量实时记录链表的长度,也就是用空间换时间,如许每次查询只必要 O ( 1 ) O(1) O(1) 的时间复杂度,这也是上一节课中直接裸露递归的类 IntList 所无法实现的:
4. 修复addLast()
首先我们写一个无参的构造方法,如许用户可以大概创建一个空链表:
- public SLList() {
- this.head = null;
- this.size = 0;
- }
复制代码 现在我们尝试创建空链表,并用 addLast() 方法添加节点:
- SLList L = new SLList();
- L.addLast(10);
- System.out.println(L);
复制代码 会发现步伐报错了,因为空链表的 this.head 就为 null,在执行 while (p.next != null) 时无法获取 p.next,因此我们可以如许修改 addLast() 方法:
- // 在尾部添加节点
- public void addLast(int val) {
- if (this.head == null) this.head = new IntNode(val, null);
- else {
- IntNode p = this.head;
- while (p.next != null) p = p.next;
- p.next = new IntNode(val, null);
- }
- this.size++;
- }
复制代码 5. 虚拟头节点
现在观察代码会发现有些方法里做了形如 if (this.head == null) 的特判,当工程代码量变大时如果风俗这么写会导致代码冗余复杂。
我们可以添加一个虚拟头节点,如许就不会存在头节点为空的情况,这种虚拟头节点也称哨兵节点,而且修改 remove 方法使其不返回节点值,因为可以通过 get 方法获取节点值。末了本节课的完整实当代码如下:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |