·單鏈表反轉
這次講單鏈表反轉,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;
}
}
鏈表反轉一般有三種方法,原地反轉,頭插法反轉,遞歸反轉。其中遞歸反轉最簡單簡潔,但是空間復雜度更高。下面分別介紹。
-
原地反轉
首先讓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; }
-
利用頭插法反轉
新建一個鏈表,遍歷原鏈表,用頭插法插入到新鏈表中。
值得注意的是,在遍歷開始前,還要斷開第一個結點和第二個結點之間的鏈。初始化工作做完后,從第二個結點開始遍歷鏈表,依次插入新鏈表中,即實現反轉。
帶頭節點的鏈表:
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; }
-
遞歸反轉
直接遞歸得到最后一個節點,然后每層就是將這個節點的下一個節點指向這個節點,這個節點指向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; }