Nim 语言实现单链表

这一节,我们来介绍单链表这种数据结构。

简介

单链表是一种逻辑上连续,而在内存存储位置不连续的线性结构。使用单链表,在插入和删除已知节点时,可以以 O(1) 的时间复杂度完成。

单链表由一个个节点组成,每个节点包含当前元素,以及下一个节点的位置信息。就和网页上的连接类似,一个页面不仅有当前信息,还包含下一个网页的连接信息。通过指针或者引用,我们就可以像浏览网页那样,过渡到下一个节点。

Nim 语言简介

我们使用 Nim 语言实现系列数据结构。Nim 语言是一种高效而优雅的系统级编程语言,具体介绍可以查看 Nim 语言官网。

https://nim-lang.org/
Nim 中文社区
https://nim-cn.com/

单链表的基本结构

首先创建单个节点,每个节点保存当前信息,以及下一个节点的位置信息。在 Nim语言中 ref 相当于指针或者引用, 我们使用 type 声明类型,星号表明该函数可以被其他模块访问。T 是 Nim 中的泛型,代表这个函数可以支持任意合理的类型,比如 int, float 等类型。object 就和面向对象语言的类差不多,可以继承。

value 代表当前元素的信息,next 指向下一个节点。

# 微信公众号 Nim 编程
type
  SinglyNodeObj*[T] = object
    value*: T
    next*: ref SinglyNodeObj[T]
  SinglyNode*[T] = ref SinglyNodeObj[T]

下面让我们定义一个单链表,单链表有两个属性,node 表示单链表保存的节点信息,而 lastNode 则表示指向单链表的尾部。定义一个 lastNode 属性,可以让我们以 O(1) 的时间复杂度在单链表尾部插入节点。

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

定义函数

我们刚才定义了单链表的底层数据表示,接下来让我们定义操作这些数据的函数。

首先我们希望创建一个空的节点,因为 result 是 ref 类型,所以我们需要先给它分配内存,只需 new 一下就行了。Nim 会自动初始化,假设 elem 是 int 类型,value 就被初始化为 0,而 next 则被初始化为 nil。

显然创建一个空节点,我们只需给 result 的 value 属性赋值即可。

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

下一步,我们需要创建一个单链表,类似的分配变量。我们首先创建一个首节点,这个节点和后续节点有些不同。在逻辑上,我们不考虑该节点的 value 属性,只保存下一个节点的信息,和 lastNode 类似,起到哨兵作用。之后,我们让 lastNode 指向头部节点。到此为止,一个空的单链表就创建完成了。

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

接下来,我们看头部插入节点。我们新建节点 node,让 node 节点的 next 属性指向第一个节点,接着再让头部节点的 next 属性指向新建节点。

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

然后,我们在尾部插入节点,也比较容易。新建节点 node,让尾部节点的 next 属性指向 node,接着让 lastNode 节点指向 node。

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

在单链表插入指定节点。首先我们查找指定元素对应的个节点,接着在该节点的后面插入新节点。

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

删除单链表出现的第一个指定元素。

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

打印节点信息。

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"

迭代节点元素。

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

欢迎关注# 微信公众号 Nim 编程, Nim 中文社区官网 https://nim-cn.com/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容