寫兩個幫助函數來建立鏈表。系列目錄見 前言和目錄 。javascript
寫兩個方法 push
和 buildList
來初始化鏈表。嘗試在 buildList
中使用 push
。下面的例子中我用 a -> b -> c
來表示鏈表,這是爲了書寫方便,並非 JavaScript 的有效語法。java
let chained = null chained = push(chained, 3) chained = push(chained, 2) chained = push(chained, 1) push(chained, 8) === 8 -> 1 -> 2 -> 3 -> null
push
用於把一個節點插入到鏈表的頭部。它接受兩個參數 head 和 data ,head 能夠是一個節點對象或者 null
。這個方法應該始終返回一個新的鏈表。node
buildList
接收一個數組爲參數,建立對應的鏈表。git
buildList([1, 2, 3]) === 1 -> 2 -> 3 -> null
做爲鏈表系列的第一課,咱們須要先定義節點對象是什麼樣子。按照 Codewars 上的設定,一個節點對象有兩個屬性 data 和 next 。data 是這個節點的值,next 是下一個節點的引用。這是默認的類模板。github
function Node(data) { this.data = data this.next = null }
這是 push
的基本實現:segmentfault
function push(head, data) { const node = new Node(data) if (head) { node.next = head return node } else { return node } }
我更傾向於修改一下 Node 的構造函數,把 next 也當成參數,而且加上默認值,這會讓後面的事情簡化不少:數組
function Node(data = null, next = null) { this.data = data this.next = next }
新的 push
實現:函數
function push(head, data) { return new Node(head, data) }
這個函數很是適合用遞歸實現。這是遞歸的版本:測試
function buildList(array) { if (!array || !array.length) return null const data = array.shift() return push(buildList(array), data) }
遞歸的思路是,把大的複雜的操做逐步分解成小的操做,直到分解成最基本的狀況。拿這個例子解釋,給定數組 [1, 2, 3]
,遞歸的實現思路是逐步往鏈表頭部插入數據 3,2,1 ,一共三輪。第一輪至關於 push(someList, 3)
。這個 someList
是什麼呢,其實就是 buildList([1, 2])
的返回值。以此類推:ui
第一輪 push(buildList([1, 2]), 3)
第二輪 push(buildList([1]), 2)
第三輪 push(buildList([]), 3)
到第三輪就已是最基本的狀況了,數組爲空,這時返回 null
表明空節點。
依照上面的思路,循環也很容易實現,只要反向遍歷數組就行。由於循環已經考慮了數組爲空的狀況,這裏就不用進行邊界判斷了。
function buildListV2(array) { let list = null for (let i = array.length - 1; i >= 0; i--) { list = push(list, array[i]) } return list }
結合循環版本的思路和 JavaScript 的數組迭代器,咱們能夠得出一個 one-liner 版本。
function buildListV3(array) { return (array || []).reduceRight(push, null) }
這個就不解釋了,留給各位本身思考下吧。