Nim 語言實現(xiàn)單鏈表

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

簡介

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

單鏈表由一個個節(jié)點組成,每個節(jié)點包含當前元素,以及下一個節(jié)點的位置信息。就和網(wǎng)頁上的連接類似,一個頁面不僅有當前信息,還包含下一個網(wǎng)頁的連接信息。通過指針或者引用,我們就可以像瀏覽網(wǎng)頁那樣,過渡到下一個節(jié)點。

Nim 語言簡介

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

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

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

首先創(chuàng)建單個節(jié)點,每個節(jié)點保存當前信息,以及下一個節(jié)點的位置信息。在 Nim語言中 ref 相當于指針或者引用, 我們使用 type 聲明類型,星號表明該函數(shù)可以被其他模塊訪問。T 是 Nim 中的泛型,代表這個函數(shù)可以支持任意合理的類型,比如 int, float 等類型。object 就和面向?qū)ο笳Z言的類差不多,可以繼承。

value 代表當前元素的信息,next 指向下一個節(jié)點。

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

下面讓我們定義一個單鏈表,單鏈表有兩個屬性,node 表示單鏈表保存的節(jié)點信息,而 lastNode 則表示指向單鏈表的尾部。定義一個 lastNode 屬性,可以讓我們以 O(1) 的時間復(fù)雜度在單鏈表尾部插入節(jié)點。

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

定義函數(shù)

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

首先我們希望創(chuàng)建一個空的節(jié)點,因為 result 是 ref 類型,所以我們需要先給它分配內(nèi)存,只需 new 一下就行了。Nim 會自動初始化,假設(shè) elem 是 int 類型,value 就被初始化為 0,而 next 則被初始化為 nil。

顯然創(chuàng)建一個空節(jié)點,我們只需給 result 的 value 屬性賦值即可。

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

下一步,我們需要創(chuàng)建一個單鏈表,類似的分配變量。我們首先創(chuàng)建一個首節(jié)點,這個節(jié)點和后續(xù)節(jié)點有些不同。在邏輯上,我們不考慮該節(jié)點的 value 屬性,只保存下一個節(jié)點的信息,和 lastNode 類似,起到哨兵作用。之后,我們讓 lastNode 指向頭部節(jié)點。到此為止,一個空的單鏈表就創(chuàng)建完成了。

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

接下來,我們看頭部插入節(jié)點。我們新建節(jié)點 node,讓 node 節(jié)點的 next 屬性指向第一個節(jié)點,接著再讓頭部節(jié)點的 next 屬性指向新建節(jié)點。

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

然后,我們在尾部插入節(jié)點,也比較容易。新建節(jié)點 node,讓尾部節(jié)點的 next 屬性指向 node,接著讓 lastNode 節(jié)點指向 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é)點。首先我們查找指定元素對應(yīng)的個節(jié)點,接著在該節(jié)點的后面插入新節(jié)點。

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)的第一個指定元素。

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é)點信息。

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é)點元素。

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)注# 微信公眾號 Nim 編程, Nim 中文社區(qū)官網(wǎng) https://nim-cn.com/ 。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容