鏈接清單 (Linked List) 鏈接清單是表示一系列節點(node)的資料結構。
與陣列不同,在鏈接清單中存取特定索引並非常數(constant)時間。 若要找到清單中的第K個元素,需要迭代K個元素。
建構鏈接清單 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Node { public ?Node $next = null ; public int $data ; public function __construct (int $data ) { $this ->int = $data ; } public function appendToTail (int $data ) { $end = new Node ($data ); $n = $this ; while ($n ->next != null ) { $n = $n ->next; } $n ->next = $end ; } }
此實作中沒有LinkedList資料結構。 我們透過第一個節點參考(reference)存取此鏈接清單。
以這種方式實作鏈接清單必須小心。 若有多個物件需要此鏈接清單的參考,而第一個節點改變了呢?
我們可以選擇實作包裝Node類別的LinkedList類別。 它只有一個成員變數:第一個Node。 這會大幅解決前述問題。
記得討論鏈接清單要知道是單向 或雙向 的。
從單向鏈接清單中刪除節點 對節點n找出前一個節點prev並將prev.next設定為n.next值。
若為雙向鏈接,還有將n.next.prev設定為n.prev值。
重點是檢查空指標 與更新頭尾指標 。
runner技巧 “runner” (或說是第二個指標) 技巧用於鏈接清單問題。 意思是同時以兩個指標迭代鏈接清單,其中一個領先另一個 (節點領先固定數量)。
遞迴問題 許多鏈接清單依靠遞迴解決。 但你應該要記住遞迴演算法至少需要$O(n)$空間,$n$是遞迴呼叫的深度。
所有遞迴演算法都可以用迭代實作,但會比較複雜。
面試問題 2.1 Remove Dups Write code to remove duplicates from an unsorted linked list.
First Answer (hash table)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static function removeDuplicated (Node $node ) { $hashTable = []; $previousNode = null ; while (!is_null ($node )) { if (in_array ($node ->data, $hashTable )) { $previousNode ->next = $node ->next; } else { $hashTable [] = $node ->data; $previousNode = $node ; } $node = $node ->getNext (); } }
Best Answer (two point)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static function removeDuplicated (Node $node ) { $pointer1 = $node ; while (!is_null ($pointer1 )) { $pointer2 = $pointer1 ; while (!is_null ($pointer2 ->next)) { if ($pointer2 ->next->data == $pointer1 ->data) { $pointer2 ->next = $pointer2 ->next->next; } else { $pointer2 = $pointer2 ->next; } } $pointer1 = $pointer1 ->next; } }
2.2 Return Kth to Last Implement an algorithm to find the kth to last element of a singly linked list. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static function find (Node $node , $k ): ?Node { $pointer1 = $node ; $pointer2 = $node ; for ($i = 0 ; $i < $k ; $i ++) { if (is_null ($pointer1 )) { return null ; } $pointer1 = $pointer1 ->next; } while ($pointer1 != null ) { $pointer1 = $pointer1 ->next; $pointer2 = $pointer2 ->next; } return $pointer2 ; }
2.4 Partition Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. If x is contained within the list, the values of x only need to be after the elements less than x (see below). The partition element x can appear anywhere in the “right partition”; it does not need to appear between the left and right partitions. [Example]
Input: Output: 3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1 [partition= 5] 3 -> 1 -> 2 -> 10 -> 5 -> 5 -> 8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static function partition (Node $node , $x ) { $head = new Node (); $headStart = $head ; $tail = new Node (); $tailStart = $tail ; while (!is_null ($node )) { $data = $node ->data; if ($data < $x ) { $head ->next = new Node ($data ); $head = $head ->next; } else { $tail ->next = new Node ($data ); $tail = $tail ->next; } $node = $node ->next; } $head ->next = $tailStart ->next; return $headStart ->next; }
2.6 Palindrome Implement a function to check if a linked list is a palindrome.
Solution #1 (Reverse and Compare)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public static function isPalindrome (?Node $node ): bool { $reversed = self ::reverseAndClone ($node ); return self ::isEqual ($node , $reversed ); } private static function reverseAndClone (Node $node ): ?Node { $head = null ; while (!is_null ($node )) { $n = new Node ($node ->data); $n ->next = $head ; $head = $n ; $node = $node ->next; } return $head ; } private static function isEqual (?Node $node , ?Node $reversed ): bool { while (!is_null ($node ) && !is_null ($reversed )) { if ($node ->data != $reversed ->data) { return false ; } $node = $node ->next; $reversed = $reversed ->next; } return $node === $reversed ; }
ʕ •ᴥ•ʔ:程式碼可參考:CtCI-6th-php 。