国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

用 JavaScript 實(shí)現(xiàn)鏈表操作 - 05 Sorted Insert

junbaor / 748人閱讀

摘要:把節(jié)點(diǎn)插入一個(gè)已排序的鏈表。這個(gè)函數(shù)接受兩個(gè)參數(shù)一個(gè)鏈表的頭節(jié)點(diǎn)和一個(gè)數(shù)據(jù),并且始終返回新鏈表的頭節(jié)點(diǎn)。這是鏈表的一個(gè)常用技巧。另外合理使用可以簡化不少循環(huán)的代碼。

TL;DR

把節(jié)點(diǎn)插入一個(gè)已排序的鏈表。系列目錄見 前言和目錄 。

需求

寫一個(gè) sortedInsert() 函數(shù),把一個(gè)節(jié)點(diǎn)插入一個(gè)已排序的鏈表中,鏈表為升序排列。這個(gè)函數(shù)接受兩個(gè)參數(shù):一個(gè)鏈表的頭節(jié)點(diǎn)和一個(gè)數(shù)據(jù),并且始終返回新鏈表的頭節(jié)點(diǎn)。

sortedInsert(1 -> 2 -> 3 -> null, 4) === 1 -> 2 -> 3 -> 4 -> null)
sortedInsert(1 -> 7 -> 8 -> null, 5) === 1 -> 5 -> 7 -> 8 -> null)
sortedInsert(3 -> 5 -> 9 -> null, 7) === 3 -> 5 -> 7 -> 9 -> null)
遞歸版本

我們可以從簡單的情況推演遞歸的算法。下面假定函數(shù)簽名為 sortedInsert(head, data)

當(dāng) head 為空,即空鏈表,直接返回新節(jié)點(diǎn):

if (!head) return new Node(data, null)

當(dāng) head 的值大于或等于 data 時(shí),新節(jié)點(diǎn)也應(yīng)該插入頭部:

if (head.data >= data) return new Node(data, head)

如果以上兩點(diǎn)都不滿足,data 就應(yīng)該插入后續(xù)的節(jié)點(diǎn)了,這種 “把數(shù)據(jù)插入某鏈表” 的邏輯恰好符合 sortedInsert 的定義,因?yàn)檫@個(gè)函數(shù)始終返回修改后的鏈表,我們可以新鏈表賦值給 head.next 完成鏈接:

head.next = sortedInsert(head.next, data)
return head

整合起來代碼如下,非常簡單并且有表達(dá)力:

function sortedInsert(head, data) {
  if (!head || data <= head.data) return new Node(data, head)

  head.next = sortedInsert(head.next, data)
  return head
}
循環(huán)版本

循環(huán)邏輯是這樣:從頭到尾檢查每個(gè)節(jié)點(diǎn),對第 n 個(gè)節(jié)點(diǎn),如果數(shù)據(jù)小于或等于節(jié)點(diǎn)的值,則新建一個(gè)節(jié)點(diǎn)插入節(jié)點(diǎn) n 和節(jié)點(diǎn) n-1 之間。如果數(shù)據(jù)大于節(jié)點(diǎn)的值,則對下個(gè)節(jié)點(diǎn)做同樣的判斷,直到結(jié)束。

先上代碼:

function sortedInsertV2(head, data) {
  let node = head
  let prevNode

  while (true) {
    if (!node || data <= node.data) {
      let newNode = new Node(data, node)
      if (prevNode) {
        prevNode.next = newNode
        return head
      } else {
        return newNode
      }
    }

    prevNode = node
    node = node.next
  }
}

這段代碼比較復(fù)雜,主要有幾個(gè)邊界情況處理:

函數(shù)需要始終返回新鏈表的頭,但插入的節(jié)點(diǎn)可能在鏈表頭部或者其他地方,所以返回值需要判斷是返回新節(jié)點(diǎn)還是 head

因?yàn)椴迦牍?jié)點(diǎn)的操作需要連接前后兩個(gè)節(jié)點(diǎn),循環(huán)體要維護(hù) prevNodenode 兩個(gè)變量,這也間接導(dǎo)致 for 的寫法會(huì)比較麻煩,所以才用 while

循環(huán)版本 - dummy node

我們可以用 上一個(gè) kata 中提到的 dummy node 來解決鏈表循環(huán)中頭結(jié)點(diǎn)的 if/else 判斷,從而簡化一下代碼:

function sortedInsertV3(head, data) {
  const dummy = new Node(null, head)
  let prevNode = dummy
  let node = dummy.next

  while (true) {
    if (!node || node.data > data) {
      prevNode.next = new Node(data, node)
      return dummy.next
    }

    prevNode = node
    node = node.next
  }
}

這段代碼簡化了第一版循環(huán)中返回 head 還是 new Node(...) 的問題。但能不能繼續(xù)簡化一下每次循環(huán)中維護(hù)兩個(gè)節(jié)點(diǎn)變量的問題呢?

循環(huán)版本 - dummy node & check next node

為什么要在循環(huán)中維護(hù)兩個(gè)變量 prevNodenode ?這是因?yàn)樾鹿?jié)點(diǎn)要插入兩個(gè)節(jié)點(diǎn)之間,而我們每次循環(huán)的當(dāng)前節(jié)點(diǎn)是 node ,單鏈表中的節(jié)點(diǎn)沒辦法引用到上一個(gè)節(jié)點(diǎn),所以才需要維護(hù)一個(gè) prevNode

如果在每次循環(huán)中檢查的主體是 node.next 呢?這個(gè)問題就解決了。換言之,我們檢查的是數(shù)據(jù)是否適合插入到 nodenode.next 之間。這種做法的唯一問題是第一次循環(huán),我們需要 node.next 指向頭結(jié)點(diǎn),那 node 本身又是什么? dummy node 正好解決了這個(gè)問題。這塊有點(diǎn)繞,不懂的話可以仔細(xì)想想。這是鏈表的一個(gè)常用技巧。

簡化后的代碼如下,順帶一提,因?yàn)榭梢陨倬S護(hù)一個(gè)變量,while 可以簡化成 for 了:

function sortedInsertV4(head, data) {
  const dummy = new Node(null, head)

  for (let node = dummy; node; node = node.next) {
    const nextNode = node.next
    if (!nextNode || nextNode.data >= data) {
      node.next = new Node(data, nextNode)
      return dummy.next
    }
  }
}
總結(jié)

這個(gè) kata 是遞歸簡單循環(huán)麻煩的一個(gè)例子,有比較才會(huì)理解遞歸的優(yōu)雅之處。另外合理使用 dummy node 可以簡化不少循環(huán)的代碼。算法相關(guān)的代碼和測試我都放在 GitHub 上,如果對你有幫助請幫我點(diǎn)個(gè)贊!

參考資料

Codewars Kata
GitHub 的代碼實(shí)現(xiàn)
GitHub 的測試

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86651.html

相關(guān)文章

  • JavaScript 實(shí)現(xiàn)鏈表操作 - 前言和目錄

    摘要:我打算寫一個(gè)鏈表操作的系列,來自的系列,實(shí)現(xiàn)語言是。通過自己實(shí)現(xiàn)一個(gè)鏈表和常用操作,可以加深理解這類數(shù)據(jù)結(jié)構(gòu)的優(yōu)缺點(diǎn)。鏈表經(jīng)常用來訓(xùn)練指針操作,雖然這只對適用,但等高級語言中控制引用的思路其實(shí)也差不多。 TL;DR 我打算寫一個(gè)鏈表操作的系列,來自 Codewars 的 Linked List 系列 kata ,實(shí)現(xiàn)語言是 JavaScript 。這篇是開篇,簡單描述了一下我寫這個(gè)的目...

    BetaRabbit 評論0 收藏0
  • LeetCode 攻略 - 2019 年 7 月上半月匯總(55 題攻略)

    摘要:微信公眾號記錄截圖記錄截圖目前關(guān)于這塊算法與數(shù)據(jù)結(jié)構(gòu)的安排前。已攻略返回目錄目前已攻略篇文章。會(huì)根據(jù)題解以及留言內(nèi)容,進(jìn)行補(bǔ)充,并添加上提供題解的小伙伴的昵稱和地址。本許可協(xié)議授權(quán)之外的使用權(quán)限可以從處獲得。 Create by jsliang on 2019-07-15 11:54:45 Recently revised in 2019-07-15 15:25:25 一 目錄 不...

    warmcheng 評論0 收藏0
  • LeetCode 攻略 - 2019 年 7 月下半月匯總(100 題攻略)

    摘要:月下半旬攻略道題,目前已攻略題。目前簡單難度攻略已經(jīng)到題,所以后面會(huì)調(diào)整自己,在刷算法與數(shù)據(jù)結(jié)構(gòu)的同時(shí),攻略中等難度的題目。 Create by jsliang on 2019-07-30 16:15:37 Recently revised in 2019-07-30 17:04:20 7 月下半旬攻略 45 道題,目前已攻略 100 題。 一 目錄 不折騰的前端,和咸魚有什么區(qū)別...

    tain335 評論0 收藏0
  • JavaScript 實(shí)現(xiàn)鏈表操作 - 16 Sorted Intersect

    摘要:需求實(shí)現(xiàn)函數(shù)取兩個(gè)已排序的鏈表的交集,交集指兩個(gè)鏈表都有的節(jié)點(diǎn),節(jié)點(diǎn)不一定連續(xù)。每個(gè)鏈表應(yīng)該只遍歷一次。結(jié)果鏈表中不能包含重復(fù)的節(jié)點(diǎn)。當(dāng)我們對比和的值時(shí),有這幾種情況,這時(shí)節(jié)點(diǎn)肯定交集,加入結(jié)果鏈表中。 TL;DR 一次遍歷取兩個(gè)排序鏈表的交集,系列目錄見 前言和目錄 。 需求 實(shí)現(xiàn)函數(shù) sortedIntersect() 取兩個(gè)已排序的鏈表的交集,交集指兩個(gè)鏈表都有的節(jié)點(diǎn),節(jié)點(diǎn)不一定...

    zhigoo 評論0 收藏0
  • JavaScript 實(shí)現(xiàn)鏈表操作 - 14 Sorted Merge

    摘要:需求實(shí)現(xiàn)函數(shù)把兩個(gè)升序排列的鏈表合并成一個(gè)新鏈表,新鏈表也必須是升序排列的。有一些邊界情況要考慮或可能為,在合并過程中或的數(shù)據(jù)有可能先取完。第行的指針調(diào)換讓始終小于等于,從而避免了重復(fù)的代碼。參考資料的代碼實(shí)現(xiàn)的測試 TL;DR 把兩個(gè)升序排列的鏈表合并成一個(gè),系列目錄見 前言和目錄 。 需求 實(shí)現(xiàn)函數(shù) sortedMerge() 把兩個(gè)升序排列的鏈表合并成一個(gè)新鏈表,新鏈表也必須是升...

    jzman 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<