Odersky Scala书中的队列实现。第19章

时间:2018-05-13 20:42:53

标签: scala

我在Odersky关于Scala的书的第388页上看到了这段代码:

class SlowAppendQueue[T](elems: List[T]) {
  def head = elems.head
  def tail = new SowAppendQueue(elems.tail)
  def enqueue(x: T) = new SlowAppendQueue(elems ::: List(x))
}

class SlowHeadQueue[T](smele: List[T]) {
  def head = smele.last
  def tail = new SlowHeadQueue(smele.init)
  def enqueue(x: T) = new SlowHeadQueue(x :: smele)
}

以下是正确的说法:

  1. tail的两个实现都需要与队列中元素数量成比例的时间。
  2. head的第二个实现比第一个慢。第二种实现需要与队列长度成比例的时间。为什么是这样?它是如何实现的?它是否像链接列表,其中每个元素都有一个指向下一个元素的指针?
  3. 为什么奥德斯基说第二堂课' tail的实施是有问题的,但不是第一个?

2 个答案:

答案 0 :(得分:1)

  1. 否。在第一种情况下,hashgraph在恒定时间内工作,因为tail是一个常量时间操作(它只返回列表的尾部)。构造函数elems.tail也是一个常量时间操作,因为它只包含列表。
  2. 因为如果new SlowAppendQueue(...)smele个元素,那么N > 1必须从头开始重建包含smele.init元素的新列表。这需要线性时间,因此它比第一个队列实现中的N - 1操作慢得多。
  3. O(1)操作存在问题,因为它们对于大型O(N)来说速度较慢,而N操作基本上不会出现问题。
  4. 我认为你应该仔细研究一下如何实现不可变的单链表,以及如何预先添加一个元素(O(1)),附加一个元素(O(1))来访问尾部(O(N)),重建O(1)init)。然后其他一切都变得明显。

答案 1 :(得分:1)

  1. 不,第一个false实现需要一段时间。这是因为false由于结构共享而是一个恒定时间操作,并且将列表包装在新的tail中也是一个恒定时间操作。

  2. 由于功能链表(包括Scala的List.tail类)的工作方式,SlowAppendQueue的第二个实现需要恒定的时间。每个列表节点都有一个指向其后节点的链接。要通过head删除最后一个元素,必须重建整个列表。

  3. 总之,List在开始操作时速度很快,但在完全操作时却不快。另请参阅Scala docs for List