那些年我们纠结过的手撕链表反转

想必对于每一个初学链表的人来说,链表反转都是绕不过去的一道题。在面试算法中,更是长期霸榜TOP1。本期就让我们来好好分析分析,链表反转,是不是真的有那么难。

单链表反转的根本,我将其总结为4点:

1.结点指针域的变动   2.while循环中指针的移步操作  3.while循环的退出条件  4.返回值如何确定

掌握这四点,你将再也不会忘记单链表反转,从而战无不胜!

在接下来文章介绍的方法中,你一定会看到这四点的影子。

链表反转的题目大致如下:

image.png

 给你一个单链表的头结点head,要你实现链表反转,并返回反转后链表的头结点。

下面我们来介绍链表反转的两种常用做法:

1.不借助虚拟头结点直接反转

首先将这句话牢牢记在心中:

没有虚拟头结点反转单链表,需要三个指针pre,cur和next。首先保存原链表的cur.next为next,再将cur的next域指向pre。最后,cur和pre都向后移动一步开启下一轮。

代码如下:

public static ListNode reverseList(ListNode head){
    ListNode cur = head;
    ListNode pre = null;
    while (cur != null){
        ListNode next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}

接着我们来分析为什么这么做:

第一,循环中保存cur.next为next一定要在其他所有步骤之前 。因为原链表中cur的后继结点只有cur.next一个引用。

1 <-- 2      3 --> 4 --> 5

如上,如果你还没有保存4的引用就让3的next指向2,那么4就会没有引用,我们就无法获得这个节点了。而我们需要这个节点来改变cur的引用,以实现循环。

所以,保存cur.next (4)才能确保while循环中指针移步正常进行。

第二,让cur.next指向pre,实现指针域的反转。即,让3的next指向2。

最后一步,我们改变cur和pre的位置,继续反转下一个节点的指针域。 

第三,考虑退出循环的条件。我们在代码中看到,我们实现反转,是通过操作cur的next指针域实现的。所以cur指向原链表最后一个节点时,也需要修改指针域,这时还不能退出循环。所以,cur再移步,cur==null的时候,我们才能退出循环。

第四,返回值。cur == null的时候退出循环,这时pre的状态是什么呢?因为pre是cur的前驱结点,所以pre这时指向原链表最后一个节点,即,反转链表的头结点。所以我们返回pre。

这个图请牢牢记在心中:

image.png

2.借助虚拟头结点,使用头插法完成链表反转。

我们首先建立虚拟头结点。然后,每次从原链表上拆一个节点下来接在虚拟头结点后面。

先上图: 

image.png

 首先我们需要明白,1节点的next域原来是不为null的,所以在反转链表的时候,一定要记住先把1节点的next域置空,这样它才能成为反转链表尾结点。

public static ListNode reverseList1(ListNode head){
    if (head == null || head.next == null){
        System.out.println("链表长度必须大于等于2才能反转!");
        return null;
    }
    ListNode temp = new ListNode(-1);
    temp.next = head;//虚拟头结点及连接temp.next到head
    ListNode node = head.next;//node指向第二节点(把这里的node理解成图里的cur)
    head.next = null;//将原第一节点的next赋值为null,因为它是反转链表尾结点
    while (node != null){
        ListNode next = node.next;//同上,先保存下一个待修改指向的节点
        node.next = temp.next;
        temp.next = node;//把node节点接入到temp后面
        node = next;//node指向下一个待修改节点
    }
    return temp.next;
}

也是同第一种方法一样,直到node == null我们才退出循环。然后返回值的话,就直接返回temp.next。

你看,掌握节点指针域如何变动,移步操作的进行,while循环的退出条件,返回值的把握,单链表反转你还会忘记吗?希望本文对您有所帮助!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值