演算法面試:單向連結串列節點的奇偶排序。
給定一個單項鍊表,要求實現一個演算法,把連結串列分成兩部分,前一部分全是下標為偶數的節點,後一部分全是下標為奇數的節點,例如給定連結串列為下圖的第一個佇列,要求編寫一個演算法,將連結串列轉換為第二個佇列:
要求演算法不能分配多餘的記憶體,同時,在操作連結串列是,不能更改節點內部的內容,只能更改節點的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
由此可見,我們演算法的實現是正確的。更詳細的程式碼講解和除錯,請參看視訊。
更多技術資訊,包括作業系統,編譯器,面試演算法,機器學習,人工智慧,請關照我的公眾號: