【反转单链表】一篇就够了

·单链表反转

这次讲单链表反转,main方法:

public static void main(String[] args) {
    // 新建链表
    LinkNode l = getALinkList(5);
    LinkNode cur;

    // 若为带头节点的链表,取消这段注释
    // cur = new LinkNode(-1);
    // cur.next = l;
    // l = cur;

    cur = l;
    // 反转前打印
    while (cur != null){
        System.out.print(cur.val+" ");
        cur = cur.next;
    }
    // 反转		
    cur = reverse1(l);
    // 反转后打印
    System.out.println();
    while (cur != null){
        System.out.print(cur.val+" ");
        cur = cur.next;
    }
}

getALinkList方法:

// 创建有 len 个节点的链表,val 为0-99随机数
private static LinkNode getALinkList(int len){
    Random random = new Random();
    LinkNode l = new LinkNode(random.nextInt(99));
    LinkNode cur = l;
    for (int i = 0; i < len - 1 ; i++) {
        cur.next = new LinkNode(random.nextInt(99));
        cur = cur.next;
    }
    return l;
}

链表节点:

public class LinkNode {
    public int val;
    public LinkNode next = null;

    public LinkNode(int val){
        this.val = val;
    }
}

链表反转一般有三种方法,原地反转,头插法反转,递归反转。其中递归反转最简单简洁,但是空间复杂度更高。下面分别介绍。

  1. 原地反转

    首先让pre的next指向cur的next;再让cur的next指向头节点的下一个结点;这时已经反转了结点,此时链表第一个结点变成了当前反转的结点;再让头节点的next指向cur;最后移动cur到下一个要反转的结点。重复上述步骤,直到cur为null。此时头节点也指向最后一个节点了。

    带头节点的链表:

    static LinkNode reverse1(LinkNode l){
        if(l.next == null || l.next.next == null){
            return l;
        }
        LinkNode pre = l.next;  // pre 不动, 移动头节点
        LinkNode cur = pre.next;
        while(cur != null){
            pre.next = cur.next;
            cur.next = l.next;
            l.next = cur;
            cur = pre.next;
        }
        return l;
    }
    

    不带头结点的链表:

    一样的做法一个指向pre,一个指向cur。而且比有头节点的更加简单。

    public LinkNode reverse2(LinkNode l){
        LinkNode pre = l;
        LinkNode cur = pre.next;
        while(cur != null){
            LinkNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        l.next = null;  // 记得将最开始的头节点指向null,否则形成环路
        return pre;
    }
    
  2. 利用头插法反转

    新建一个链表,遍历原链表,用头插法插入到新链表中。

    值得注意的是,在遍历开始前,还要断开第一个结点和第二个结点之间的链。初始化工作做完后,从第二个结点开始遍历链表,依次插入新链表中,即实现反转。

    带头节点的链表:

    static LinkNode reverse3(LinkNode l){
        if(l.next == null || l.next.next == null){
            return l;
        }
        LinkNode cur = l.next.next;
        LinkNode next;
        l.next.next = null;
        while (cur != null){
            next = cur.next;
            cur.next = l.next;
            l.next = cur;
            cur = next;
        }
        return l;
    }
    

    不带头结点的链表:

    static LinkNode reverse4(LinkNode l){
        if(l == null || l.next == null){
            return l;
        }
        LinkNode cur = l.next;
        LinkNode next;
        l.next = null;
        while (cur != null){
            next = cur.next;
            cur.next = l;
            l = cur;
            cur = next;
        }
        return l;
    }
    
  3. 递归反转

    直接递归得到最后一个节点,然后每层就是将这个节点的下一个节点指向这个节点,这个节点指向null,最后返回末尾节点。(不带头节点)

    static LinkNode reverse5(LinkNode l){
        if(l == null || l.next == null){
            return l;
        }
        LinkNode p = reverse5(l.next);
        l.next.next = l;
        l.next = null;
        return p;
    }
    
原文地址:https://www.cnblogs.com/cpcpp/p/13374900.html