联合无限循环scala

Posted

技术标签:

【中文标题】联合无限循环scala【英文标题】:union infinite loop scala 【发布时间】:2015-10-18 16:42:07 【问题描述】:

我正在学习 scala 并通过在线参加 Odersky 课程。在第三个作业中,有一个练习,您必须使用推文集。推文集应支持的操作之一是union。也就是说,两个集合之间的并集是一个新集合,其中包含来自这两个集合的推文。

我实现了这个操作如下:

abstract class TweetSet 
   def union(that: TweetSet): TweetSet
   def incl(tweet: Tweet): TweetSet


class Empty extends TweetSet 
 def union(that:TweetSet): TweetSet = that
 def incl(tweet: Tweet): TweetSet = new NonEmpty(tweet, new Empty, new Empty)


class NonEmpty(elem: Tweet, left: TweetSet, right: TweetSet) extends TweetSet 

  def incl(x: Tweet): TweetSet = 
     if (x.text < elem.text) new NonEmpty(elem, left.incl(x), right)
     else if (x.text > elem.text) new NonEmpty(elem, left, right.incl(x))
     else this
   

   def union(that: TweetSet): TweetSet =
    (left union (right union that)) incl elem //:: 1 Okay
   // ((right union left) union that) incl elem //:: 2 Infinite loop

我不明白为什么用于合并集合的顺序很重要。这对我来说真的没有任何意义。我的代码中的第一行正常工作,而第二行导致无限循环。联合操作数的顺序无关紧要,我应该独立于我决定使用哪一行而得到相同的结果。

我使用的顺序是 Odersky 在其在线讲座中使用的顺序,所以我无法理解为什么它在某些情况下会导致无限循环。

我认为我的代码中存在错误,但我找不到它。任何帮助将不胜感激。

【问题讨论】:

leftright 是什么?好像少了几块。 @m-z 谢谢。我没有正确复制构造函数。我更新了我的答案。谢谢 我看不出有什么问题;你能发布你正在使用的产生无限循环的测试代码吗? 【参考方案1】:

实际上并不是无限循环。它是有限循环,但第二种变体涉及更多操作。

假设

case class Tweet(text: String)

我们可以定义简单的

var unionsCalled = 0

并添加一行

unionsCalled += 1

EmptyNonEmptys 联合实现

然后运行线路

(1 to 30).view map (_.toString) map Tweet map (new NonEmpty(_, new Empty, new Empty)) reduce (_ union _)
println(unionsCalled)

给我们最终的unionsCalled899 用于第一个实现变体,149489 用于第二个实现变体

这是由于不平衡的树木而发生的。 在最坏的情况下,您对union 单个项目和n 项目集的算法应该创建新的n - 1 元素集,然后包括elem,然后是that.elem。有时会降级为2^(n/2)

要准确实现高效集,您应该搜索this article中的链接

我敢于使用最简单的代码 randomized search tree 重新实现您的任务

import scala.util.Random

case class Tweet(text: String)

abstract class TweetSet 
  def union(that: TweetSet): TweetSet
  def rankInsert(tweet: Tweet, rank: Int): TweetSet
  def incl(tweet: Tweet): TweetSet = rankInsert(tweet, Random.nextInt())
  def toList: List[Tweet]
  def depth: Int


case object Empty extends TweetSet 
  def depth = 0
  def union(that: TweetSet): TweetSet = that
  def rankInsert(tweet: Tweet, rank: Int) = NonEmpty(tweet, Empty, Empty, rank)
  def toList = List()


case class NonEmpty(elem: Tweet, 
                    left: TweetSet, 
                    right: TweetSet, 
                    rank: Int) extends TweetSet 
  lazy val depth = (left.depth max right.depth) + 1
  def attachToParent(tweet: Tweet, rank: Int) = if (tweet.text < elem.text)
    NonEmpty(tweet, Empty, this, rank)
  else NonEmpty(tweet, this, Empty, rank)

  def rankInsert(tweet: Tweet, rank: Int) =
    if (tweet.text == elem.text) this
    else if (rank > this.rank) attachToParent(tweet, rank)
    else if (tweet.text < elem.text) copy(left = left.rankInsert(tweet, rank))
    else copy(right = right.rankInsert(tweet, rank))

  def toList = left.toList ++ (elem :: right.toList)
  def union(that: TweetSet): TweetSet = if (depth > that.depth) that.union(this)
  else (that /: toList)(_ incl _ )


object TweetSet 
  def empty: TweetSet = Empty
  def apply(tweets: Tweet*) = (empty /:  tweets)( _ incl _ )

【讨论】:

我希望我能给你更多的支持,我鼓励任何阅读这个答案的人这样做。非常感谢您的帮助。我还有一个问题,为什么我的实现退化为 2^(n/2)?在最坏的情况下不应该退化为一个列表?因此复杂度为 n? @GiuseppePes 谢谢!我对你的问题想了很多,但没有得出一些描述复杂性增长的公式或规律。 Here my work on it。如果您愿意,它会涉及一些 scalaz。

以上是关于联合无限循环scala的主要内容,如果未能解决你的问题,请参考以下文章

如何可视化vue无限更新循环的无限循环

无限循环与嵌套循环

检查空无限循环中的选项与做一些无限循环

C++入门基础知识[3]——循环嵌套循环无限循环

Python无限循环

00014_无限循环