【问题标题】:How to create immutable Doubly LinkedList in Scala?如何在 Scala 中创建不可变的双链表?
【发布时间】:2020-12-02 03:20:32
【问题描述】:

有人可以通过展示其中一种方法实现来帮助我在 Scala 中创建不可变的双向链表吗?另外,您能否通过让我们实现 prepend(element:Int): DoublyLinkedList[Int] 来提供一个示例?

【问题讨论】:

  • 你不能创建一个不可变的双向链表,否则效率会非常低,因为任何返回新列表的操作都需要复制整个列表,这意味着即使是空列表也需要复制而不是共享。 - 你为什么需要这个?做作业?如果是这样,您至少能够实现单个链表吗?
  • 当您创建一个新元素时,您可以将对前一个元素的引用传递给它并使其不可变。但只有在创建此元素之后,您才有可以传递给前一个元素的引用,以便将其存储为“下一个”。您也不能有一个 Nil 元素,因为它不能指向 2 个不同列表中的 2 个先前元素。事实上,在创建新元素时,您不能重用列表中的任何元素。因此,您必须在每个操作上重新分配整个列表,使其基本上是一个没有 O(1) 索引访问的无效不可变数组。
  • 查找搜索词“Credit Card Transform”和“Tying the Knot”。这是您需要的两个技巧。

标签: scala doubly-linked-list


【解决方案1】:

用文本版本的链接补充已经链接的视频并包括重要的引语:

这在Immutable Doubly Linked Lists in Scala with Call-By-Name and Lazy Values进行了描述

双向链表在 Scala 中并没有提供太多好处,恰恰相反。

所以从实际的角度来看,这个数据结构是毫无用处的,这就是为什么......在 Scala 标准集合库中没有双向链表

综上所述,双向链表是对不可变数据结构心智模型的一次极好的练习。

想一想:Java 中的这个操作应该分 3 步完成:

  • 新节点
  • 新节点的prev是1
  • 1 的下一个是新节点

如果我们可以在同一个表达式中执行新的 1 ⇆ 2,我们就成功了;然后我们可以递归地将此操作应用于列表的其余部分。奇怪的是,这是可能的。

class DLCons[+T](override val value: T, p: => DLList[T], n: => DLList[T]) extends DLList[T] {
  // ... other methods

  override def updatePrev[S >: T](newPrev: => DLList[S]) = {
    lazy val result: DLCons[S] = new DLCons(value, newPrev, n.updatePrev(result))
    result
  }
  
}

updatePrev:我们正在创建一个新节点,它的下一个引用立即指向一个递归调用;递归调用在当前的下一个节点上,它将更新它自己之前对我们仍在定义的结果的引用!这种前向引用只有在存在惰性值和按名称参数时才有可能。

【讨论】:

    【解决方案2】:

    Call By Name & lazy val (Call by need) 使得拥有不可变的双向链表成为可能。

    【讨论】:

      猜你喜欢
      • 2012-06-01
      • 1970-01-01
      • 2011-12-23
      • 1970-01-01
      • 1970-01-01
      • 2013-08-16
      • 1970-01-01
      • 2019-09-02
      • 2015-08-01
      相关资源
      最近更新 更多