单链表主类
思路
链表中有字段size是节点总个数
倒数第lastNum个节点就是正数第size-lastNum+1个节点,index=size-lastNum
删除操作需要拿到倒数第lastNum+1个节点来完成,即正数第size-lastNum个节点,index=size-lastNum-1
把该节点的next设置为该节点的next.next即可
代码
public void deleteByLastNum(int lastNum) {
if (lastNum <= 0 || lastNum > size) {
throw new IndexOutOfBoundsException("unSupport");
}
if (lastNum == size) {
// 删除第一个
SinglyLinkedNode<T> remove = this.getHeader();
this.setHeader(remove.getNext());
remove.setNext(null);
remove = null; // gc
size--;
return;
// 此种情形也处理了单节点,删除倒数第一个的情况,接下来的情形中,节点至少都有两个了
}
// 倒数第lastNum个节点,就是正数第size-lastNum+1个节点,如果从0开始用index标记则是size-lastNum
// 删除它就是把index=size-lastNum-1的next设置为index为size-lastNum的next
SinglyLinkedNode<T> current = this.getHeader();
int pos = 0;
while (pos != size - lastNum - 1) {
current = current.getNext();
pos++;
}
SinglyLinkedNode<T> remove = current.getNext();
current.setNext(remove.getNext());
remove.setNext(null);
remove = null; // gc
size--;
}
网络上看到的快慢指针法的思路
上述的解决方案其实依赖链表的长度size,如果链表没有size则需要先从header移动到尾部求出size
网络上看到的快慢指针法则不需要使用size
我自己理解这个挺笨拙的,就需要举个实际例子来明白

需要找的节点和上述的一致,如果要删掉倒数第lastNum个节点,需要拿到倒数第lastNum+1个节点
网络上的快慢指针法就是在定位该节点时用了一种很巧妙的方法
先让快指针从header开始向后移动lastNum步,这时候快指针在index=lastNum位置
接着慢指针也从header开始,和快指针以相同步长1向后移动,循环条件是快指针的current.getNext() != null。之所以不使用current != null是因为这样会拿到被删除节点本身,而这里需要拿到被删除节点的前一个节点
代码
public void deleteByLastNum2(int lastNum) {
SinglyLinkedNode<T> faster = this.getHeader();
for (int i = 0; i < lastNum; i++) {
if (faster == null) {
throw new IndexOutOfBoundsException("越界");
}
faster = faster.getNext();
}
if (faster == this.getHeader()) {
throw new IndexOutOfBoundsException("lastNum为负数,越界");
}
// 需要加一个对faster的空指针校验,不然后边会报错
if (faster == null) {
// 删除头,参看图解中,faster为null表示图解中的链表长度为3,那么删除倒数第3个就是删除掉header
SinglyLinkedNode<T> header = this.getHeader();
this.setHeader(header.getNext());
header.setNext(null);
header = null; // gc
this.size--;
return;
}
SinglyLinkedNode<T> lower = this.getHeader();
while (faster.getNext() != null) {
lower = lower.getNext();
faster = faster.getNext();
}
SinglyLinkedNode<T> remove = lower.getNext();
lower.setNext(remove.getNext());
remove.setNext(null);
remove = null; // gc
this.size--;
}
因为链表类中定义了size,代码里也相应处理了它,如果定义的链表类中没有该字段则不需要处理
本文介绍了如何使用Java删除单链表中的倒数第n个节点。通过链表节点总数,可以方便地获取到需要删除的节点。另外,还探讨了网络上常见的快慢指针法,这种方法不需要预先知道链表长度,通过两个指针的同步移动,巧妙地找到目标节点的前一个节点,从而实现删除操作。
1384

被折叠的 条评论
为什么被折叠?



