持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情。
链表的结构
在上一篇中我们根据链表的结构开始设计List(链表) 类,并分别为其构建了从头节点插入的头插法
和从末位节点插入的尾插法
,本篇也将继续与大家构建设计List(链表) 类。
public calss List{
public Node head; // 头节点属性
public List() // 构造器方法,初始化一个空链表
public void add(int value) // 头插法
public void append(int value) // 尾插法
}
### 链表的删除
上一篇我们着重设计了List(链表) 的插入方法,那么本篇中将为List(链表) 设计特定位置插入、删除及链表置空的方法。
与顺序表相比,链表的删除元素要更加便捷,我们只需要操作被删除节点的前一个元素,将其的next
属性设置为null
。这样被删除节点没有被指向,就会被JVM(java虚拟机) 自动回收,也就达成了我们删除元素节点的目的。
这种方法在删除尾部节点时格外的好用,但如果我们需要删除的节点在链表中间,那被删除节点之后的节点也会一并被删除了。这不是我们想看到的,我们要求在删除特定节点后,其余节点都能保留下来。
同样的,我们还是修改被删除节点的前驱节点的next
属性,但这次我们不是将其设置为null
,而是将其修改为被删除节点的next
,这样我们就可以在丢弃其他节点的情况下,删除链表中的某一特定节点了。
public void delete(int index) // 删除链表中的第 index 个节点
{
Node p = this.head;
for(int i = 0; i < index-1 ; i++)
p = p.next;
p.next = p.next.next;
}
但这样的修改同样不能令我们满意,假如传入的index
比链表现有的元素要多怎么办?
所以我们需要稍微优化一下我们现有的链表结构,如果我们的链表能多出以一个用来表示链表现有元素数量的属性那就方便多了。刚好,在前面介绍链表结构时提到过:在单链表中头节点通常不存放数据。既然头节点不用来存放元素,那我们正好可以将头节点利用起来,把链表的长度length
存储到头节点的value
属性中,这样我们即不需要创建新的属性来占用内存空间,又能把头节点的value
利用起来,一举两得。
这里我们来优化一下链表原有的构造器
、插入
、删除
方法。
public calss List{
public Node head; // 链表的头节点
public List() // 构造器方法,初始化一个空链表
{
this.head = new Node(0); // 初始化头节点,并设置当前链表长度为0
}
public void add(int value) // 头插法
{
Node newNode = new Node(value);
newNode.addNext(this.head.next);
this.head.addNext(newNode);
this.head.value++;
}
public void append(int value) // 尾插法
{
Node p = this.head;
for(int i = 0; i < this.head.value; i++)
p = p.next;
p.addNode(new Node(value));
this.head.value++;
}
public void delete(int index) // 删除链表中的第 index 个节点
{
Node p = this.head;
for(int i = 0; i < index-1 && i < this.head.value; i++)
p = p.next;
p.next = p.next.next;
this.head.value--;
}
public int length()
{
return this.head.value;
}
}
前面在设计删除方法时,我们注意到如果一个节点不再被引用,那么JVM(java虚拟机)
就会自动将这个节点清理掉,所以当我们想要清空一个链表时,只需要将head(头节点)
的next
属性设置为null
,并将head.value
设置成0
,就迅速将一个链表置空了。
public void setNull(){
this.head.next = null;
this.head.value = 0;
}
小结
本章主要讲解了链表的基本构成,以及链表是怎么添加元素的。
天天学习,加速成长!
希望与各位一起变得越来越强!