Nim 語(yǔ)言實(shí)現(xiàn)單鏈表

這一節(jié),我們來(lái)介紹單鏈表這種數(shù)據(jù)結(jié)構(gòu)泡态。

簡(jiǎn)介

單鏈表是一種邏輯上連續(xù),而在內(nèi)存存儲(chǔ)位置不連續(xù)的線性結(jié)構(gòu)迂卢。使用單鏈表某弦,在插入和刪除已知節(jié)點(diǎn)時(shí)桐汤,可以以 O(1) 的時(shí)間復(fù)雜度完成。

單鏈表由一個(gè)個(gè)節(jié)點(diǎn)組成刀崖,每個(gè)節(jié)點(diǎn)包含當(dāng)前元素惊科,以及下一個(gè)節(jié)點(diǎn)的位置信息。就和網(wǎng)頁(yè)上的連接類似亮钦,一個(gè)頁(yè)面不僅有當(dāng)前信息馆截,還包含下一個(gè)網(wǎng)頁(yè)的連接信息。通過(guò)指針或者引用蜂莉,我們就可以像瀏覽網(wǎng)頁(yè)那樣蜡娶,過(guò)渡到下一個(gè)節(jié)點(diǎn)。

Nim 語(yǔ)言簡(jiǎn)介

我們使用 Nim 語(yǔ)言實(shí)現(xiàn)系列數(shù)據(jù)結(jié)構(gòu)映穗。Nim 語(yǔ)言是一種高效而優(yōu)雅的系統(tǒng)級(jí)編程語(yǔ)言窖张,具體介紹可以查看 Nim 語(yǔ)言官網(wǎng)。

https://nim-lang.org/
Nim 中文社區(qū)
https://nim-cn.com/

單鏈表的基本結(jié)構(gòu)

首先創(chuàng)建單個(gè)節(jié)點(diǎn)蚁滋,每個(gè)節(jié)點(diǎn)保存當(dāng)前信息宿接,以及下一個(gè)節(jié)點(diǎn)的位置信息。在 Nim語(yǔ)言中 ref 相當(dāng)于指針或者引用, 我們使用 type 聲明類型辕录,星號(hào)表明該函數(shù)可以被其他模塊訪問(wèn)睦霎。T 是 Nim 中的泛型,代表這個(gè)函數(shù)可以支持任意合理的類型走诞,比如 int, float 等類型副女。object 就和面向?qū)ο笳Z(yǔ)言的類差不多,可以繼承蚣旱。

value 代表當(dāng)前元素的信息碑幅,next 指向下一個(gè)節(jié)點(diǎn)。

# 微信公眾號(hào) Nim 編程
type
  SinglyNodeObj*[T] = object
    value*: T
    next*: ref SinglyNodeObj[T]
  SinglyNode*[T] = ref SinglyNodeObj[T]

下面讓我們定義一個(gè)單鏈表塞绿,單鏈表有兩個(gè)屬性沟涨,node 表示單鏈表保存的節(jié)點(diǎn)信息,而 lastNode 則表示指向單鏈表的尾部异吻。定義一個(gè) lastNode 屬性拷窜,可以讓我們以 O(1) 的時(shí)間復(fù)雜度在單鏈表尾部插入節(jié)點(diǎn)。

type
  SinglyList*[T] = ref object
    node*: SinglyNode[T]
    lastNode*: SinglyNode[T]

定義函數(shù)

我們剛才定義了單鏈表的底層數(shù)據(jù)表示涧黄,接下來(lái)讓我們定義操作這些數(shù)據(jù)的函數(shù)篮昧。

首先我們希望創(chuàng)建一個(gè)空的節(jié)點(diǎn),因?yàn)?result 是 ref 類型笋妥,所以我們需要先給它分配內(nèi)存懊昨,只需 new 一下就行了。Nim 會(huì)自動(dòng)初始化春宣,假設(shè) elem 是 int 類型酵颁,value 就被初始化為 0嫉你,而 next 則被初始化為 nil。

顯然創(chuàng)建一個(gè)空節(jié)點(diǎn)躏惋,我們只需給 result 的 value 屬性賦值即可幽污。

proc newSinglyNode*[T](elem: T): SinglyNode[T] = 
  new(result)
  result.value = elem

下一步,我們需要?jiǎng)?chuàng)建一個(gè)單鏈表簿姨,類似的分配變量距误。我們首先創(chuàng)建一個(gè)首節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)和后續(xù)節(jié)點(diǎn)有些不同扁位。在邏輯上准潭,我們不考慮該節(jié)點(diǎn)的 value 屬性,只保存下一個(gè)節(jié)點(diǎn)的信息域仇,和 lastNode 類似刑然,起到哨兵作用。之后暇务,我們讓 lastNode 指向頭部節(jié)點(diǎn)泼掠。到此為止,一個(gè)空的單鏈表就創(chuàng)建完成了垦细。

proc newSinglyList*[T](): SinglyList[T] = 
  new(result)
  result.node = SinglyNode[T](next:nil)
  result.lastNode = result.node

接下來(lái)择镇,我們看頭部插入節(jié)點(diǎn)。我們新建節(jié)點(diǎn) node蝠检,讓 node 節(jié)點(diǎn)的 next 屬性指向第一個(gè)節(jié)點(diǎn)沐鼠,接著再讓頭部節(jié)點(diǎn)的 next 屬性指向新建節(jié)點(diǎn)挚瘟。

proc prepend*[T](list: SinglyList[T], elem: T) = 
  var 
    p = list.node
    node = newSinglyNode(elem=elem)
  node.next = p.next
  p.next = node

然后叹谁,我們?cè)谖膊坎迦牍?jié)點(diǎn),也比較容易乘盖。新建節(jié)點(diǎn) node焰檩,讓尾部節(jié)點(diǎn)的 next 屬性指向 node,接著讓 lastNode 節(jié)點(diǎn)指向 node订框。

proc insert*[T](list: SinglyList[T], elem: T) =
  var 
    p = list.lastNode
    node = newSinglyNode(elem=elem)
  p.next = node
  list.lastNode = p.next

在單鏈表插入指定節(jié)點(diǎn)析苫。首先我們查找指定元素對(duì)應(yīng)的個(gè)節(jié)點(diǎn),接著在該節(jié)點(diǎn)的后面插入新節(jié)點(diǎn)穿扳。

proc find*[T](list: SinglyList[T], elem: T): SinglyNode[T] = 
  result = list.node
  while (result != nil) and (result.value != elem):
    result = result.next

proc insert*[T](list: SinglyList[T], pos: SinglyNode[T], elem: T) =
  if pos.isLast:
    list.insert(elem)
  var p = new SinglyNode[T]
  p.value = elem
  p.next = pos.next
  pos.next = p

刪除單鏈表出現(xiàn)的第一個(gè)指定元素衩侥。

proc delete*[T](list: SinglyList[T], elem: T) = 
  var p = findPrevious[T](list, elem)
  if p == nil: return
  if p.next.isLast:
    list.lastNode = p
    p.next = nil
  if not p.isLast:
    p.next = p.next.next

打印節(jié)點(diǎn)信息。

proc `$`[T](list: SinglyList[T]): string = 
  while list.isEmpty:
    return "empty"
  var p = list.node.next
  while p != nil:
    result &=  $p.value & "->" 
    p = p.next 
  result &= "tail"

迭代節(jié)點(diǎn)元素矛物。

iterator items*[T](list: SinglyList[T]): T = 
  var p = list.node.next
  while p.next != nil:
    yield p.value
    p = p.next
    
iterator pairs*[T](list: SinglyList[T]): tuple[idx: int, value: T] = 
  var 
    p = list.node.next
    idx = 0
  while p.next != nil:
    yield (idx, p.value)
    p = p.next    

示例

when isMainModule:
  let a = newSinglyList[int]()
  a.insert(12)
  a.insert(8)
  a.insert(17)
  a.insert(12)
  a.insert(8)
  a.prepend(9)
  a.insert(17)
  let t1 = a.find(17)
  a.insert(t1, 99)
  a.prepend(87)
  a.delete(8)
  a.delete(12)
  echo a
# output 87->9->17->99->12->8->17->tail

歡迎關(guān)注# 微信公眾號(hào) Nim 編程, Nim 中文社區(qū)官網(wǎng) https://nim-cn.com/ 茫死。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市履羞,隨后出現(xiàn)的幾起案子峦萎,更是在濱河造成了極大的恐慌屡久,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爱榔,死亡現(xiàn)場(chǎng)離奇詭異被环,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)详幽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門筛欢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人妒潭,你說(shuō)我怎么就攤上這事悴能。” “怎么了雳灾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵漠酿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谎亩,道長(zhǎng)炒嘲,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任匈庭,我火速辦了婚禮夫凸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘阱持。我一直安慰自己夭拌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布衷咽。 她就那樣靜靜地躺著鸽扁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪镶骗。 梳的紋絲不亂的頭發(fā)上桶现,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音鼎姊,去河邊找鬼骡和。 笑死,一個(gè)胖子當(dāng)著我的面吹牛相寇,可吹牛的內(nèi)容都是我干的慰于。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼唤衫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼婆赠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起战授,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤页藻,失蹤者是張志新(化名)和其女友劉穎桨嫁,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體份帐,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡璃吧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了废境。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畜挨。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖噩凹,靈堂內(nèi)的尸體忽然破棺而出巴元,到底是詐尸還是另有隱情,我是刑警寧澤驮宴,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布逮刨,位于F島的核電站,受9級(jí)特大地震影響堵泽,放射性物質(zhì)發(fā)生泄漏修己。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一迎罗、第九天 我趴在偏房一處隱蔽的房頂上張望睬愤。 院中可真熱鬧,春花似錦纹安、人聲如沸尤辱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)光督。三九已至,卻和暖如春咪笑,著一層夾襖步出監(jiān)牢的瞬間可帽,已是汗流浹背娄涩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工窗怒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蓄拣。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓扬虚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親球恤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辜昵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容