數據結構與算法——單鏈表練習

1. 概述

前面的文章說到了一種很基礎的數據結構——鏈表:數據結構與算法——鏈表,今天就來看看關於單鏈表的幾種常見的操做,技術筆試的時候很大機率可以遇到其中的一些。多練習一下,對咱們理解鏈表有很大的幫助,也可以提高咱們的編碼能力。
廢話很少說,這幾個練習題是:node

  • 單鏈表反轉
  • 合併兩個有序鏈表
  • 檢測鏈表中的環
  • 刪除鏈表倒數第 k 個節點
  • 找到鏈表的中間節點
2. 單鏈表反轉

單鏈表反轉,顧名思義,就是將鏈表的指針指向所有倒過來,尾結點變成頭節點,頭節點變成尾結點。具體的代碼以下:算法

public class SingleLinkedList {
    private Node head = null;//鏈表的頭節點
    
    public Node reverse(Node node) {
        Node head = null;
        Node previous = null;
        Node current = node;
        
        while(current != null) {
            Node next = current.next; 
            if (next == null) {
                head = current;
            }
            current.next = previous;
            previous = current;
            current = next;
        }
        
        this.head = head;
        return this.head;
    }
}
3. 合併兩個有序鏈表

假如鏈表中存儲的數據是數值類型,而且是有序的,這時候能夠合併兩個有序的鏈表,主要涉及到兩個鏈表元素的比較。代碼以下:segmentfault

//合併兩個有序的鏈表
    public Node mergeSortedList(Node la, Node lb) {
        if(la == null && lb == null) return null;
        if(la == null) return lb;
        if(lb == null) return la;
        
        Node p = la;
        Node q = lb;
        Node head = null;
        
        //比較第一個元素
        if(p.getData() < q.getData()) {
            head = p;
            p = p.next;
        }else {
            head = q;
            q = q.next;
        }
        
        //比較後面的元素
        Node r = head;
        while(p != null && q != null) {
            if(p.getData() < q.getData()) {
                r.next = p;
                p = p.next;
            }else {
                r.next = q;
                q = q.next;
            }
            r = r.next;
        }
        
        //比較鏈表可能剩餘的元素
        while(p != null) {
            r.next = p;
            p = p.next;
            r = r.next;
        }
        while(q != null) {
            r.next = q;
            q = q.next;
            r = r.next;
        }
        
        return head;
    }
4. 檢測鏈表中的環

單鏈表中有可能存在像循環鏈表這樣的環形結構,檢測鏈表中是否有這樣的結構,能夠利用這樣的思路:定義兩個指針,一個指針每次移動兩個節點,另外一個指針移動一個節點,若是兩個指針相遇,則說明存在環,代碼以下:數據結構

//檢測鏈表中的環
    public boolean checkCircle(Node node) {
        if(node == null) return false;
        
        Node fast = node.next;
        Node slow = node;
    
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            
            if(fast == slow) return true;
        }
        
        return false;
    }
5. 刪除鏈表倒數第 k 個節點

這個題在筆試當中很是常見,解決的思路比較的巧妙,不容易想到,可是隻要一想到,代碼寫起來就很簡單了。主要的思路是這樣的:定義一個指針 fast,從鏈表頭開始,移動 k-1 個節點,再定義一個指針 slow,同時移動 fast 和 slow ,當 fast 到達鏈表尾節點的時候,slow 所指向的節點就是要刪除的節點。
具體的代碼實現以下:this

public static Node deleteLastKth(Node head, int k) {
        Node fast = head;
        int i = 1;
        //先讓前面的指針移動k - 1步
        while(fast != null && i < k) {
            fast = fast.next;
            ++ i;
        }
        
        Node slow = head;
        Node prev = null;
        //先後指針同時移動
        while(fast.next != null) {
            fast = fast.next;
            prev = slow;
            slow = slow.next;
        }
        
        if(prev == null) {//說明刪除的是第一個節點
            head = head.next;
        }else {
            prev.next = prev.next.next;
        }
        
        return head;
    }
6. 找到鏈表的中間節點

尋找鏈表中間的那個節點,思路很簡單,也是定義兩個指針,一個指針每次移動兩個節點,另外一個指針移動一個節點,前面的指針到達鏈表尾部的時候,後面的指針指向的節點就是中間的那個節點:編碼

public static Node findMiddleNode(Node head) {
        if(head == null) return null;
        
        Node fast = head;
        Node slow = head;
        
        while(fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
相關文章
相關標籤/搜索