1. 程式人生 > >演算法面試:單向連結串列節點的奇偶排序。

演算法面試:單向連結串列節點的奇偶排序。

給定一個單項鍊表,要求實現一個演算法,把連結串列分成兩部分,前一部分全是下標為偶數的節點,後一部分全是下標為奇數的節點,例如給定連結串列為下圖的第一個佇列,要求編寫一個演算法,將連結串列轉換為第二個佇列:

這裡寫圖片描述

要求演算法不能分配多餘的記憶體,同時,在操作連結串列是,不能更改節點內部的內容,只能更改節點的next 指標。

如果允許分配新記憶體,那麼我們可以先把奇數下標的節點存成一個佇列,把偶數下標的節點存成另一個佇列,然後把兩佇列收尾連線即可。但限制條件是不能分配新記憶體,因此問題的解決需要一點小技巧。

我們可以這麼做,用一個指標evenHead,專門指向偶下標節點,用另一個指標,oddHead指向奇下標節點。我們注意到,偶下標節點的下一個節點正好是奇下標節點,同時奇下標節點的下一個節點正好是偶下標節點。因此,如果我們把 evenHead.nex 指向 oddHead.next, oddHead.next 指向evenHead.next ,那麼,我們就能實現偶下標節點連在一起,奇下標節點連在一起的效果,例如:

這裡寫圖片描述

evenHead 指向節點0,oddHead指向節點1, oddHead.next 指向節點2,如果把evenHead的next指標設定成oddHead的next, 那相當於把節點0和2連在一起,然後把evenHead挪到它的next指標指向的節點:

這裡寫圖片描述

此時evenHead的next指向的是節點3,正好是一個奇下標節點,此時把oddHead的next指向evenHead.next那麼就可以實現奇數節點連成一體了:

這裡寫圖片描述

將上面操作迴圈下去,直到遍歷完整個佇列,那麼我們的目標就達到了。這個演算法沒有分配新記憶體,同時只需對整個連結串列遍歷一次足夠,因此演算法複雜度是O(n),空間複雜度是O(1).

實現程式碼如下:


public class EvenOddListSorter {
    private Node listHead;
    private Node evenHead, oddHead;

    public EvenOddListSorter(Node head) {
        this.listHead = head;
    }


    public Node sort() {
        if (listHead == null || listHead.next == null) {
            return listHead;
        }

        evenHead = listHead;
        oddHead = listHead.next
; Node node = oddHead; while (evenHead.next != null && oddHead.next != null) { if (oddHead.next != null) { evenHead.next = oddHead.next; evenHead = evenHead.next; } if (evenHead.next != null) { oddHead.next = evenHead.next; oddHead = oddHead.next; } } evenHead.next = node; return listHead; } }

sort函式所實現的正好是我們前面所描述的邏輯。主函式實現如下:

public class LinkList {
    public static void main(String[] args) {
        ListUtility util1 = new ListUtility();
        Node head = util1.createList(10);
        EvenOddListSorter sorter = new EvenOddListSorter(head);
        head = sorter.sort();
        util1.printList(head);
    }
}

我們先構造一個長度為10的佇列,然後對其進行節點的奇偶排序,最後打印出的結果如下:

0 -> 2 -> 4 -> 6 -> 8 -> 1 -> 3 -> 5 -> 7 -> 9 -> null

由此可見,我們演算法的實現是正確的。更詳細的程式碼講解和除錯,請參看視訊。

更多技術資訊,包括作業系統,編譯器,面試演算法,機器學習,人工智慧,請關照我的公眾號:
這裡寫圖片描述