【问题标题】:Complexity of List.reverse?List.reverse 的复杂性?
【发布时间】:2011-09-02 11:43:24
【问题描述】:

在 Scala 中,列表有 reverse 方法。这种方法的复杂性是什么?是简单地使用原始列表并始终记住该列表与我们期望的相反,还是在对其进行操作之前显式使用reverse 更好。

编辑:我真正感兴趣的是获取原始列表的最后两个元素(或反向列表的前两个元素)。

所以我会这样做:

val myList = origList.reverse
val a = myList(0)
val b = myList(1)

这不是循环,只是我库中的一次性事情......但是如果其他人使用该库并将其置于循环中,则它不在我的控制之下。

【问题讨论】:

  • Is it better 在没有目标、要达到的目标和具体情况的情况下是无法回答的。
  • 我想知道你为什么写“永远记住列表与我们期望的相反”。您永远不必“记住”某些与预期不同的东西。这是一个等待发生的错误。因此,即使它会损害性能,您也应该按照预期顺序使用列表。这就引出了一个问题,为什么该列表与您的期望相反。也许您应该从一开始就以不同的方式创建列表,或者使用其他东西,那么您就不必反转它了。见stackoverflow.com/questions/1241166/…
  • @用户未知。我同意。我曾含蓄地假设better 意味着高效。但我真正感兴趣的是复杂性。我已经编辑了这个问题。但下面的答案可能对某人有用。
  • @Ido Tamir:我编辑了这个问题来描述我的工作。希望这能回答你的问题。我认为使用 reverse 的建议是个好主意,因为代码永远不会在循环中调用。

标签: scala


【解决方案1】:

查看源代码,您可以合理地预期它是 O(n)

override def reverse: List[A] = {
  var result: List[A] = Nil
  var these = this
  while (!these.isEmpty) {
    result = these.head :: result
    these = these.tail
  }
  result
}

如果在您的代码中,您能够以与正向迭代相同的成本以反向顺序遍历列表,那么这样做会比颠倒列表更更有效 .

事实上,如果涉及使用原始列表的替代操作的工作时间少于O(n) 时间,那么有一个真正的论据支持这样做。如果您更多地依赖它(尤其是在其他循环中使用时,如 oxbow_lakes 在下面指出的那样),使算法渐近地更快将产生巨大的差异。

总体而言,尽管我希望您反转列表的任何事情都意味着您关心大量元素的相对顺序,因此无论您在做什么,本质上都是 O(n)反正。 (这可能不适用于其他数据结构,例如二叉树;但列表是线性的,在极端情况下,即使 reverse . head 也无法在 O(1) 时间内使用单链表完成。)

因此,如果您在两个 O(n) 选项之间进行选择 - 对于广大大多数应用程序,将迭代时间缩短几纳秒并不会真正为您带来任何好处。因此,让您的代码尽可能具有可读性是“最好的”——这意味着调用reverse,然后迭代,如果这最接近您的意图。

(并且如果你的应用太慢了,并且分析显示这个列表操作是一个热点,那么你可以考虑如何以提高效率。考虑到您届时将拥有的额外上下文,这很可能涉及到您当前的两个候选人的不同选择。)

【讨论】:

  • 谢谢。我会做reverse 使代码更具可读性。在我的例子中,列表少于 100 个元素。
  • 是的,但是如果您在某个循环的每次迭代中都调用List.reverse,那么您有一个 O(n^2) 算法,这可能会出现问题
  • 如果性能是一个问题,并且您想以多种方式访问​​列表,您可以使用不同的结构,例如不可变的Vector,或者对于数字代码,Array 以避免装箱。
  • @oxbow_lakes:在那种情况下,无论您调用 reverse、只是向后遍历列表,还是执行涉及 O( n) 每次循环迭代的操作。根据问题的上下文,假设无论涉及原始列表的替代方案是什么,它也将是 O(n),这似乎是公平的。如果不是,并且替代方案是 O(1) 或 O(lg n),那么在任何情况下都应该使用它。
  • @Andrzej - 确实如此。我只是说,在进行一些重新计算(或装箱或其他)时损失纳秒与因为您选择了提供 O(N) 性能而不是 O(1) 的结构来进行所需操作而丢失它们之间存在差异.根据我的经验,O(N) 可能会造成伤害,这就是为什么 Set.++ 使用 scala 2.9.0(在 2.9.1 中修复)无法使用(对于某些算法)
猜你喜欢
  • 2019-08-13
  • 1970-01-01
  • 2016-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多