在Java中自定义链表时,移除所有指定元素是一个常见的操作需求,需要兼顾头节点删除、中间节点删除等多种场景,处理的逻辑不当很容易导致链表断裂或者空指针异常。下面我们就一步步实现这个功能。

自定义链表的基础结构
首先我们需要先定义链表的基础节点类和链表类,节点类包含存储的数据和指向下一个节点的引用,链表类维护头节点。
// 链表节点类
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
// 自定义链表类
class MyLinkedList {
// 头节点
ListNode head;
public MyLinkedList() {
this.head = null;
}
// 向链表尾部添加节点的方法
public void add(int val) {
ListNode newNode = new ListNode(val);
if (head == null) {
head = newNode;
return;
}
ListNode cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = newNode;
}
}移除所有指定元素的核心实现
移除所有指定元素需要考虑两种核心场景:第一种是要删除的节点是头节点,需要更新头节点指向;第二种是要删除的节点在链表中间或者尾部,需要调整前驱节点的next引用。我们可以使用一个前驱节点指针来记录当前节点的前一个节点,方便处理删除逻辑。
实现步骤拆解
- 首先处理头节点连续等于目标值的情况,循环判断头节点不为空且头节点的值等于目标值,就将头节点后移
- 处理完头节点后,如果头节点为空,说明整个链表都被删除了,直接返回
- 定义前驱节点cur初始为头节点,遍历后续节点,如果当前节点的下一个节点的值等于目标值,就跳过下一个节点,让当前节点的next指向下下个节点
- 如果下一个节点的值不等于目标值,就将前驱节点后移一位,继续遍历
完整代码实现
class MyLinkedList {
ListNode head;
// 移除链表中所有值等于target的节点
public void removeAll(int target) {
// 处理头节点连续等于target的情况
while (head != null && head.val == target) {
head = head.next;
}
// 如果链表已经为空,直接返回
if (head == null) {
return;
}
// 前驱节点从head开始,遍历后续节点
ListNode cur = head;
while (cur.next != null) {
// 如果下一个节点的值等于target,删除下一个节点
if (cur.next.val == target) {
cur.next = cur.next.next;
} else {
// 否则前驱节点后移
cur = cur.next;
}
}
}
// 打印链表的方法,用于测试
public void printList() {
ListNode cur = head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
}测试验证
我们可以编写测试代码来验证方法的正确性,构造包含多个目标值的链表,调用移除方法后查看结果。
public class Test {
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
// 添加测试数据,包含多个需要删除的目标值2
list.add(2);
list.add(1);
list.add(2);
list.add(3);
list.add(2);
list.add(4);
list.add(2);
System.out.println("移除前链表:");
list.printList();
// 调用移除所有值为2的节点的方法
list.removeAll(2);
System.out.println("移除后链表:");
list.printList();
}
}运行上述测试代码,输出结果如下:
移除前链表:
2 1 2 3 2 4 2
移除后链表:
1 3 4
注意事项
在实现过程中需要注意几个容易出错的点:第一是不要忘记处理头节点删除的情况,如果只处理中间节点会导致头部等于目标值的节点无法被删除;第二是在删除节点时,不要直接移动当前节点指针,否则会跳过下一个节点的判断;第三是遍历结束的条件是当前节点的下一个节点不为空,避免空指针异常。只要按照上述逻辑处理,就能正确实现自定义链表中移除所有指定元素的功能。