鏈表——單鏈表常見的五種操作

五種常見操作

以下代碼都是針對引入哨兵的帶頭鏈表

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;
    }

熄燈

以上代碼鏈表都是引入哨兵的帶頭鏈表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章