用 JavaScript 實現鏈表操做 - 06 Insert Sort

TL;DR

2016 年底最後一篇,對鏈表進行插入排序。系列目錄見 前言和目錄javascript

需求

實現一個 insertSort() 函數對鏈表進行升序排列(插入排序)。實現過程當中可使用 上一個 kata 中的 sortedInsert() 函數。insertSort() 函數接受鏈表頭爲參數並返回排序後的鏈表頭。java

var list = 4 -> 3 -> 1 -> 2 -> null
insertSort(list) === 1 -> 2 -> 3 -> 4 -> null

若是傳入的鏈表爲 null 或者只有一個節點,就原樣返回。node

關於插入排序

插入排序的介紹能夠看 Wikipedia ,大致邏輯爲:git

  1. 創建一個新的空鏈表。github

  2. 依次遍歷待排序的鏈表節點,挨個插入新鏈表的合適位置,始終保持新鏈表是已排序的。算法

  3. 遍歷完成,返回新鏈表。編程

觀察這段邏輯不難發現,第二個步驟其實就是上個 kata 中 sortedInsert 作的事情 -- 把節點插入一段已排序的鏈表的合適位置。在此之上稍微包裝一下就能夠實現 insertSortsegmentfault

遞歸版本

首先咱們記住兩個函數的表達的意思:函數

  1. insertSort 返回鏈表的排序版本。測試

  2. sortedInsert 把節點插入一個已排序鏈表的合適位置,並返回修改後的鏈表(也是已排序的)。

而後咱們用遞歸的思路描述 insertSort 邏輯,應該是先把原鏈表的第一個節點插入某個已排序的鏈表的合適位置,這段邏輯能夠用 sortedInsert(someList, head.data) 表達。而這個 「某個已排序的鏈表」 ,咱們須要它包含除了 head 以外其餘的因此節點,這個鏈表能夠用 insertSort(head.next) 來表達。

整理後的代碼以下:

function insertSort(head) {
  if (!head) return null
  return sortedInsert(insertSort(head.next), head.data)
}

循環版本

循環版本是最接近算法描述的版本,因此很少贅述。代碼以下:

function insertSort(head) {
  for (var sortedList = null, node = head; node; node = node.next) {
    sortedList = sortedInsert(sortedList, node.data)
  }
  return sortedList
}

總結

由於有上個 kata 的函數的幫助,這個插入排序實現起來很是簡單。遞歸版本再次體現了聲明式編程的優點。有時候能表達某種數據的不僅是變量,也能夠是函數。只要咱們發現表達合適邏輯的函數,實現過程就會很是簡單。

算法相關的代碼和測試我都放在 GitHub 上,若是對你有幫助請幫我點個贊!

參考資料

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

相關文章
相關標籤/搜索