2

扯淡

之前听说过google面试反转链表的梗,也尝试着自己实现了一次,算是比较简单的问题。但在纸上手写代码的时候,思维就很乱,可能是隔的时间长忘记了,或者之前就跟本没有理清思路,所以被虐的很惨。
这篇文章的目的就是梳理一下思路,加深印象。如果有更好的算法,留言求虐啊~


描述

这是一个普通的链表,由ABCD4个节点组成,每个节点都包含数据区-data和指向下一个节点的引用-next
链表

反转链表,顾名思义就是将链表每个节点的next引用反过来,如ABCD,变为DCBA。当然,前提是我们只持有头节点的引用,且称为Node a,那么链表反转后的头节点,就是Node d。

分析

要将此链表反转,我们核心的需求是:修改每一个节点的next引用,将next指向前一个节点,将原来的头节点A中的next,指向null

既然每一个节点都需要操作,那就考虑循环吧,设一个索引(或者称为游标)node(可以利用节点A的引用),从节点A跑到节点D,当它再往后移动指向null时,循环结束。那么循环边界条件则为

while(node != null){
//do something
}

然后我们再看看每个节点做一次反转(即每次循环),都需要做什么事情

  1. 在修改当前节点的next引用之前,要先保存其值,为了避免丢失下一个节点(即Node next)的引用。

  2. 进行反转,修改当前节点的next,使之指向上一个节点(即Node last

  3. 要保存当前节点的引用,为了提供给下一次循环时,对下个节点进行反转

  4. 为了保证while循环可以从头节点A遍历到尾节点D,那么游标node在循环体最后要向后移动一个节点,即指向下一个节点。

代码

Node reversalLinkedList(Node node){
    Node last = null;
    Node next = null;
    while(node != null){
        next = node.getNext();//1 拿到下个节点的引用,为了提供给第4步使node向链表后方移动
        node.setNext(last);//2 将当前节点指向上一个节点
        last = node;//3 将last指向当前节点,提供给下次循环的第2步
        node = next;//4 将当前节点的引用(即游标)指向下一个节点        
    }
    /*
    * 循环完成后,node和next都指向了原节点D的next指向的位置,即null
    * 而last指向了上述null前面的位置,即节点D
    * 将last返回,则得到链表ABCD反转后链表DCBA的头节点D
    */
    return last;
}

逻辑其实很简单,需要注意的就是每次循环时需要暂存的引用 -- next,last

图解

每次循环其实就是修改当前节点next的引用+三个引用(last,node,next)的后移,如下图

第一次循环前
第一次循环前
第一次循环的过程
第一次循环时
第一次循环结束后
第一次循环结束后

最后全部反转后
图片描述

总结

  1. 保存当前节点,上一个节点,下一个节点的引用

  2. 每次循环最后,当前节点向后移动


guodage
206 声望9 粉丝

永远不要害怕失败。