斯卡拉新手。我正在尝试在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编写方式?
编辑:
感谢大家的所有评论。我试图删除null
并使用更多本机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
}
}
答案 0 :(得分:3)
首先,您实际上并不需要两个地方的type参数:
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
可以简单地从first
和iterate
开始,直到用尽非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。
答案 1 :(得分:1)
此功能的版本将是不可变的。如果在列表的开头(O(1)时间)追加,则实现非常容易且高效。删除将花费O(i)时间,其中i
是删除发生的索引。
如果您不需要在列表的中间或结尾快速添加内容,并且不需要在固定时间内知道大小,那么坚持使用不可变版本是个不错的选择。该实现甚至更加容易,您可以在collection.immutable.List
中阅读它。
here描述了一个没有所有标准集合库绒毛的更简单的实现。