五種常見操作
以下代碼都是針對引入哨兵的帶頭鏈表
1、單鏈表反轉
原地反轉
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node prev = head.next;
Node pcur = prev.next;
while(pcur != null){
prev.next = pcur.next;
pcur.next = head.next;
head.next = pcur;
pcur = prev.next;
}
return head;
}
頭插法反轉
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node newHead = new Node();
Node pcur = head.next;
Node curNextTmp = null;
while(pcur != null){
curNextTmp = pcur.next;
pcur.next = newHead.next;
newHead.next = pcur;
pcur = curNextTmp;
}
return newHead;
}
2、鏈表中環檢測
快慢指針法
- 兩個指針同時從第一個數據節點開始,pFast每次移到兩個節點,pSlow每次移到一個節點
- pFast先到尾部即pFast == null,說明沒有閉環
- 如果有閉環 則最終兩個指針會相遇即 pFast==pSlow
public static boolean hasLoop(Node head){
if(head.next==null){
return false;
}
Node pFast = head.next;
Node pSlow = head.next;
while (pFast!=null&&pSlow!=null){
pFast = pFast.next.next;
pSlow = pSlow.next;
if(pFast==null){
//這個判斷不能少,否則可能會陷入死循環
return false;
}else if(pFast==pSlow){
return true;
}
}
return false;
}
3、兩個有序鏈表合併
遞歸
- 遞歸代碼簡潔,不遞歸也可以通過兩個指針遍歷解決;
public static Node merger2Link(Node node1,Node node2){
//傳入第一個數據節點,不是傳入哨兵
if(node1==null){
return node2;
}else if(node2==null){
return node1;
}
Node newHead;
if(node1.data>node2.data){
newHead = node2;
newHead.next = merger2Link(node1,node2.next);
}else{
newHead = node1;
newHead.next = merger2Link(node1.next,node2);
}
return newHead;
}
4、刪除鏈表倒數第 n 個節點
快慢指針法
- 讓fast指針先移動n個節點之後slow節點再加入一起向後移動,直至fast==null,此時slow指向的就時倒是第N個;
- 鏈表爲空或者n小於0或者超出鏈表長度返回null;
public static Node removeNthFromEnd(Node head,int n){
if(head.next==null || n<=0){
return head;
}
//fast和slow都指向哨兵
Node fast = head;
Node slow = head;
int count = 0;
//循環結束條件要注意時fast.next!=null
//如果時fast!=null,則n=1的時候會出問題
//注意邊界條件
while (fast.next!=null){
if(count<n){
//這裏至少會執行一次
fast = fast.next;
count++;
}else{
fast = fast.next;
slow = slow.next;
}
}
slow.next = slow.next.next;
return head;
}
5、求鏈表的中間節點
快慢指針法
- fast每次移動兩個節點,slow每次移動一個節點同時向尾部移動,fast.next==null時結束,此時slow指向中間節點
public static Node middleNode(Node head) {
if (head.next == null) {
return head;
}
Node slow = head;
Node fast = head;
//長度可能爲奇數和偶數,奇數結束fast==null,偶數結束fast.next==null
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
熄燈
以上代碼鏈表都是引入哨兵的帶頭鏈表