【问题标题】:Mutable Linked List in ScalaScala中的可变链表
【发布时间】:2019-03-16 07:00:30
【问题描述】:

Scala 新手在这里。我正在尝试在 Scala 中实现一个可变链表。 (有一个图书馆类可以做同样的事情——我只是把它当作一个学习练习)。到目前为止,我只支持 add() 操作。这是我的尝试:

class MutableList[T] {

  class Node[T](val value: T) {
    var next: Node[T] = null
    def hasNext = (next != null)
  }

  var first, last: Node[T] = null
  var size = 0

  def add(value: T) = {
    val newNode = new Node[T](value)
    if (first == null) {
      assert(size == 0)
      first = newNode
    } else {
      last.next = newNode
    }
    last = newNode
    size += 1
  }

  override def toString = {
    def getValues() = {
      var current = first
      for (i <- 1 to size) yield {
        val valStr = current.value.toString
        current = current.next
        valStr
      }
    }
    getValues().mkString(",")
  }
}

我知道可变数据结构并不是在 Scala 中使用/实现的最佳选择。但我只是在试验,想知道是否有更实用的 Scala 方式来编写这个?

编辑:

感谢大家提供的所有 cmets。我试图删除 nulls 并使用更多原生 Scala 构造。欢迎评论。

class MutableLinkedList[T] {

  private type Node = MutableLinkedList[T]#MutableListNode

  class MutableListNode(val value: T) {
    var next: Option[Node] = None
  }

  private var first, last: Option[Node] = None
  private var _size = 0
  def size = _size

  def add(value: T) = {
    val newNode = Some(new MutableListNode(value))
    first match {
      case None => {
        assert(_size == 0)
        first = newNode
      }
      case Some(x) => {
        assert(last.isDefined)
        last.get.next = newNode
      }
    }
    last = newNode
    _size += 1
  }

  def head: Option[T] = {
    first match {
      case None => None
      case Some(x) => Some(x.value)
    }
  }

  def tail: Option[MutableLinkedList[T]] = {
    first match {
      case None => None
      case Some(x) => {
        var l = new MutableLinkedList[T]
        l.first = this.first.get.next
        l.last = this.last
        l._size = this.size - 1
        Some(l)
      }
    }
  }

  def exists(value: T): Boolean = {
    var current = first
    var foundIt = false
    while(current.isDefined && !foundIt) {
      if(current.get.value == value)
        foundIt = true
      current = current.get.next
    }
    foundIt
  }

  def delete(value: T): Boolean = {
    var previous: Option[Node] = None
    var current = first
    var deleted = false
    while(current.isDefined && !deleted) {
      if(current.get.value == value) {
        if(!previous.isDefined)
          first = current.get.next
        else
          previous.get.next = current.get.next
        _size -= 1
        deleted = true
      }
      previous = current
      current = current.get.next
    }
    deleted
  }

  override def toString = {
    var current = first
    var output = ""
    while(current.isDefined) {
      output += current.get.value.toString
      current = current.get.next
      if(current.isDefined)
        output += ","
    }
    output
  }
}

【问题讨论】:

  • 你对“函数式 Scala”的定义是什么?对于许多排除可变状态的人以及null
  • 也许一个好的折衷方案是 a) 仅在顶层使用 var,但 Node 本身是不可变的,并且 b) 要么使用 Option[T] 要么使用 @ 987654330@ 具有实现 EmptyNodeFullNode 的密封特征。
  • 这个问题可能更适合codereview.stackexchange.com
  • 您好 :) 我前几次问过完全相同的问题。我有一个很好的解释,所以我放弃了here
  • 按值删除意味着您只能删除具有该值的第一个元素。换句话说,使用a,b,a,c 列表,您不能删除第三个元素(第二个a)。

标签: scala


【解决方案1】:

首先,您确实不需要或不希望在两个位置都使用类型参数:

class MutableList[T] { //type parameter T

  class Node[T](val value: T) {...
          //^^^ a new type parameter T, shadowing the 1st

我会保留第一个并放弃第二个,但它可以是任何一种方式。

避免null 的常用方法是使用Option

class Node(val value: T) {
  var next: Option[Node] = None //no hasNext needed
}

有了这些,您的toString 可以简单地从firstiterate 开始,直到用完非None 节点。

override def toString :String =
  Stream.iterate(Option(first))(_.flatMap(_.next))
        .takeWhile(_.nonEmpty)
        .map(_.get.value.toString)
        .mkString(",")

可能有更多方法可以消除代码中null 的使用,但到目前为止,您还没有实现任何需要last(或size)的方法,因此很难推荐合适的解决方案。

我必须同意 Brian McCutchon 的评论,这可能更适合 Code Review

【讨论】:

    【解决方案2】:

    它的功能版本将是不可变的。如果您在列表的开头附加(O(1)时间),则实现非常简单且高效。删除将花费 O(i) 时间,i 是删除发生的索引。

    如果您不特别需要在列表的中间或末尾快速添加,并且您不需要知道恒定时间的大小,那么坚持不可变版本是一个不错的选择。实现更加简单,可以在collection.immutable.List阅读。

    here 描述了一个更简单的实现,没有所有标准集合库绒毛。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-14
      • 2011-12-23
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 2012-01-07
      • 1970-01-01
      相关资源
      最近更新 更多