联合无限循环scala

时间:2015-10-18 16:42:08

标签: scala recursion union

我正在学习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在线讲座中使用的顺序,所以我无法理解为什么它会在某些情况下导致无限循环。

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

1 个答案:

答案 0 :(得分:2)

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

假设

case class Tweet(text: String)

我们可以定义简单的

var unionsCalled = 0

并添加行

unionsCalled += 1

同时发送EmptyNonEmpty联合实现

然后运行行

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

为第一个实现变体提供unionsCalled的最终899值,为第二个

提供149489的最终值union

这是因为树木不平衡而发生的。 在最坏的情况下,您的n单项和n - 1项集的算法应创建新的elem元素集,然后包含that.elem,然后2^(n/2)。有时会降低到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 _ ) }

要准确实施高效设置,您应搜索this article

中的链接

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

From p In PlanObjects Group By p.PlanId Into First Select First