删除单链表中倒数第n个节点(JAVA)

本文介绍了如何使用Java删除单链表中的倒数第n个节点。通过链表节点总数,可以方便地获取到需要删除的节点。另外,还探讨了网络上常见的快慢指针法,这种方法不需要预先知道链表长度,通过两个指针的同步移动,巧妙地找到目标节点的前一个节点,从而实现删除操作。

单链表主类

参考单链表反转中的主类代码

思路

链表中有字段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,代码里也相应处理了它,如果定义的链表类中没有该字段则不需要处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值