【反轉單鏈表】一篇就夠了


·單鏈表反轉

這次講單鏈表反轉,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;
    }
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM