一文轻松搞懂 链表反转

单链表反转(时间复杂度O(n), 空间复杂度O(1))的方法主要有以下三种:

  • 头插法:从第二个元素开始,依次把元素插到插入到头结点和第一个元素之间。
  • 指针逆转:把指向后面一个元素的指针指向前面一个元素
  • 递归法:本质上跟指针逆转相同

前情提要:
设置一个链表,带有头结点。元素为1->2->3->4
在这里插入图片描述
倒转过来应该是:
在这里插入图片描述

1.头插法

从第二个元素开始,每次选取一个元素插入到头结点和第一个节点之间。

第一步:把 2 插到 head1 之间
在这里插入图片描述
第二步:把 3 插入 head2 之间
在这里插入图片描述
第三步:把 4 插入 head3 之间
在这里插入图片描述
代码实现:

static ListNode reverseByHeadInsert(ListNode head){
        //如果一个元素没有或者仅有一个元素,那么可以直接返回
        if(head.next == null || head.next.next == null)
            return head;

        ListNode p = head.next; //指向第一个元素

        while(p.next != null)
        {
            ListNode q = p.next;    //指向第一个元素后面的元素
            p.next = q.next;
            q.next = head.next;
            head.next = q;
        }

        return head;
    }
2.指针逆转

原先next指针指向后面,把next指针指向前面,然后head指针指向最后一个元素即可。相当于 把指针方向掉了个 ,然后把head重新指向链表新的起点。

调转前
在这里插入图片描述

调转后
在这里插入图片描述
设置三个指针,分别指向 前一个元素p、后一个元素q、后一个元素后面的元素res
初始情况:
p 指向 1
q 指向 2

第一次循环:
res 指向 3
将 2 的next 指针指向 1(此时1的next仍然指向2,这个我们最后再调整也行)
p 指向 2
q 指向 3

第二次循环:
res 指向 4
将 3 的next指针指向2
p 指向 3
q 指向 4

第三次循环
res 指向null
将 4 的next指针指向3
p 指向 4
q 指向 null

q==null停止循环

static ListNode reverseByReversePoint(ListNode head){
        //如果一个元素没有或者仅有一个元素,那么可以直接返回
        if(head.next == null || head.next.next == null)
            return head;

        ListNode p = head.next; //指向前一个元素
        ListNode q = p.next;    //指向后一个元素
        while(q != null){       //当后一个元素不为空指向前一个元素 
            ListNode res = q.next;  // 用于记录后一个元素的后面,因为next指向前面元素后,需要保存后面的内容
            q.next = p;
            p = q;
            q = res;
        }
        head.next.next = null;
        head.next = p;

        return head;
    }
3.递归法:也是链表指针方向旋转

代码:

//这里不传入头结点,最终返回值也是最后一个元素
    static ListNode reverseByRecursion(ListNode node){
        //包括特殊情况
        if (node == null || node.next == null)
            return node;

        ListNode newHead = reverseByRecursion(node.next);//注意,此处的操作是一直循环到链表末尾
        node.next.next = node;//反转每个节点的指向
        node.next = null;

        return newHead;
    }
4.代码总结

把所有代码放在一起,包括ListNode的定义。



class ListNode{
    int value;
    ListNode next;
    ListNode(int value){
        this.value = value;
    }
}





public class ReverseList {

    static ListNode reverseByHeadInsert(ListNode head){
        //如果一个元素没有或者仅有一个元素,那么可以直接返回
        if(head.next == null || head.next.next == null)
            return head;

        ListNode p = head.next; //指向第一个元素

        while(p.next != null)
        {
            ListNode q = p.next;    //指向第一个元素后面的元素
            p.next = q.next;
            q.next = head.next;
            head.next = q;
        }

        return head;
    }

    static ListNode reverseByReversePoint(ListNode head){
        //如果一个元素没有或者仅有一个元素,那么可以直接返回
        if(head.next == null || head.next.next == null)
            return head;

        ListNode p = head.next; //指向前一个元素
        ListNode q = p.next;    //指向后一个元素

        while(q != null){       //当后一个元素不为空指向前一个元素
            ListNode res = q.next;  // 用于记录后一个元素的后面,因为next指向前面元素后,需要保存后面的内容
            q.next = p;
            p = q;
            q = res;
        }
        head.next.next = null;
        head.next = p;

        return head;
    }

    //这里不传入头结点,最终返回值也是最后一个元素
    static ListNode reverseByRecursion(ListNode node){
        //包括特殊情况
        if (node == null || node.next == null)
            return node;

        ListNode newHead = reverseByRecursion(node.next);//注意,此处的操作是一直循环到链表末尾
        node.next.next = node;//反转每个节点的指向
        node.next = null;

        return newHead;
    }


    static void printList(ListNode head){
        if(head.next == null){
            return;
        }
        ListNode p = head.next;
        while(p != null){
            System.out.print(p.value + " ");
            p = p.next;
        }
    }


    public static void main(String[] args) {
        ListNode head = new ListNode(0);  // 创建头结点
        ListNode cur = head;                    // 工作指针指向头结点,用于后面创建链表
        for(int i = 1; i <= 4; i++){            // 创建链表 1->2->3->4
            cur.next = new ListNode(i);
            cur = cur.next;
        }
        cur.next = null;

//        reverseByHeadInsert(head);
//        reverseByReversePoint(head);
        head.next = reverseByRecursion(head.next);
        printList(head);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值