用 JavaScript 實現鏈表操做 - 01 Push & Build List

TL;DR

寫兩個幫助函數來建立鏈表。系列目錄見 前言和目錄javascript

需求

寫兩個方法 pushbuildList 來初始化鏈表。嘗試在 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

這是 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)
}

buildList

遞歸版本

這個函數很是適合用遞歸實現。這是遞歸的版本:測試

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
}

One-liner

結合循環版本的思路和 JavaScript 的數組迭代器,咱們能夠得出一個 one-liner 版本。

function buildListV3(array) {
  return (array || []).reduceRight(push, null)
}

這個就不解釋了,留給各位本身思考下吧。

參考資料

Codewars Kata
GitHub 的代碼實現
GitHub 的測試

相關文章
相關標籤/搜索