把兩個升序排列的鏈表合併成一個,系列目錄見 前言和目錄 。node
實現函數 sortedMerge()
把兩個升序排列的鏈表合併成一個新鏈表,新鏈表也必須是升序排列的。這個函數應該對每一個輸入的鏈表都只遍歷一次。git
var first = 2 -> 4 -> 6 -> 7 -> null var second = 1 -> 3 -> 5 -> 6 -> 8 -> null sortedMerge(first, second) === 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 6 -> 7 -> 8 -> null
有一些邊界狀況要考慮:first
或 second
可能爲 null
,在合併過程當中 first
或 second
的數據有可能先取完。若是一個鏈表爲空,就返回另外一個鏈表(即便它也爲空),不須要拋出異常。github
在作這個 kata 以前,建議先完成 Shuffle Merge 。segmentfault
代碼以下:app
function sortedMerge(first, second) { if (!first || !second) return first || second if (first.data <= second.data) { return new Node(first.data, sortedMerge(first.next, second)) } else { return new Node(second.data, sortedMerge(first, second.next)) } }
跟上個 kata 相似的思路。不過爲了保證最後的結果是升序排列的,咱們要取兩個鏈表中值更小的首節點,添加到結果鏈表的末尾。思路就不贅述了 。函數
循環是這個 kata 有意思的一點,不少邊界狀況的判斷也發生在這裏。很容易寫出這樣的 if/else
:測試
let [p1, p2] = [first, second] while (p1 || p2) { if (p1 && p2) { if (p1.data <= p2.data) { // append p1 data to result } else { // append p2 data to result } } else if (p1) { // append p1 to result } else { // append p2 to result } }
上面例子裏 p1
和 p2
是指向兩個鏈表節點的指針,在循環中它們隨時可能變成空,所以要比較數據大小首先就要判斷兩個都不爲空。並且註釋中的 append 代碼也會有必定重複。指針
爲了解決這個問題,咱們能夠上個 kata 裏調換指針的方法。完整代碼以下:code
function sortedMergeV2(first, second) { const result = new Node() let [pr, p1, p2] = [result, first, second] while (p1 || p2) { // if either list is null, append the other one to the result list if (!p1 || !p2) { pr.next = (p1 || p2) break } if (p1.data <= p2.data) { pr = pr.next = new Node(p1.data) p1 = p1.next } else { // switch 2 lists to make sure it's always p1 <= p2 [p1, p2] = [p2, p1] } } return result.next }
第 7 行判斷 p1
或 p2
爲空,而且把非空的鏈表直接添加到 result
末尾,省去了繼續循環每一個節點。第 17 行的指針調換讓 p1
始終小於等於 p2
,從而避免了重複的 append 代碼 。其餘技巧如 dummy node 在以前的 kata 都有講,就很少說了。遞歸