【问题标题】:Counting the number of inversions using Merge Sort使用合并排序计算反转次数
【发布时间】:2013-07-12 06:02:06
【问题描述】:

我需要使用归并排序来计算反转次数:

object Example {
 def msort(xs: List[Int]): List[Int] = {
    def merge(left: List[Int], right: List[Int]): Stream[Int] = (left, right) match {
      case (x :: xs, y :: ys) if x < y => Stream.cons(x, merge(xs, right))
      case (x :: xs, y :: ys) => Stream.cons(y, merge(left, ys))
      case _ => if (left.isEmpty) right.toStream else left.toStream
    }

    val n = xs.length / 2
    if (n == 0) xs
    else {
      val (ys, zs) = xs splitAt n
      merge(msort(ys), msort(zs)).toList
    }
  }                                              

  msort(List(8, 15, 3))                           
}

我想我必须在行中算(y &lt; y,第二行在match

case (x :: xs, y :: ys) => Stream.cons(y, merge(left, ys))

但是,当我尝试时,我失败了。

我该怎么做?

更新

带有累加器的版本:

def msort(xs: List[Int]): List[Int] = {
    def merge(left: List[Int], right: List[Int], inversionAcc: Int = 0): Stream[Int] = (left, right) match {
      case (x :: xs, y :: ys) if x < y => Stream.cons(x, merge(xs, right, inversionAcc))
      case (x :: xs, y :: ys) => Stream.cons(y, merge(left, ys, inversionAcc + 1))
      case _ => if (left.isEmpty) right.toStream else left.toStream
    }

    val n = xs.length / 2
    if (n == 0) xs
    else {
      val (ys, zs) = xs splitAt n
      merge(msort(ys), msort(zs)).toList
    }
  } 

如何轻松返回inversionAcc?我想,我只能像这样将它作为元组的一部分返回:

def merge(left: List[Int], right: List[Int], invariantAcc: Int = 0): (Stream[Int], Int)

虽然看起来不太好。

UPDATE2

而且它实际上并没有正确计算,我找不到错误在哪里。

【问题讨论】:

标签: algorithm scala sorting mergesort


【解决方案1】:

这是我的Frege solution 的 Scala 端口。

object CountInversions {

  def inversionCount(xs: List[Int], size: Int): (Int, List[Int]) = 
    xs match {
        case _::_::_ => { //If the list has more than one element
          val mid = size / 2
          val lsize = mid
          val rsize = size - mid
          val (left, right) = xs.splitAt(mid)
          val (lcount, lsorted) = inversionCount(left, lsize)
          val (rcount, rsorted) = inversionCount(right, rsize)
          val (mergecount, sorted) = inversionMergeCount(lsorted, lsize, rsorted,
            rsize, 0, Nil)
          val count = lcount + rcount + mergecount
          (count, sorted)
        }
        case xs => (0, xs)
     }

  def inversionMergeCount(xs: List[Int], m: Int, ys: List[Int], n: Int, 
    acc: Int, sorted: List[Int]): (Int, List[Int]) = 
      (xs, ys) match {
        case (xs, Nil) => (acc, sorted.reverse ++ xs)
        case (Nil, ys) => (acc, sorted.reverse ++ ys)
        case (x :: restx, y :: resty) => 
          if (x < y) inversionMergeCount(restx, m - 1, ys, n, acc, x :: sorted)
          else if (x > y) inversionMergeCount(xs, m, resty, n - 1, acc + m, y :: sorted)
          else inversionMergeCount(restx, m - 1, resty, n - 1, acc, x :: y :: sorted)
      }

}

【讨论】:

  • 太复杂了。一定要这样吗?
  • 这不适用于 2, 3, 9, 2, 9,它输出 1 个反转,应该是 2
【解决方案2】:

如果解决方案不必严格执行功能,那么您只需添加一个简单的计数器:

object Example {
  var inversions = 0
  def msort(xs: List[Int]): List[Int] = {
    def merge(left: List[Int], right: List[Int]): Stream[Int] = (left, right) match {
      case (x :: xs, y :: ys) if x < y => Stream.cons(x, merge(xs, right))
      case (x :: xs, y :: ys) =>
        inversions = inversions + 1
        Stream.cons(y, merge(left, ys))
      case _ => if (left.isEmpty) right.toStream else left.toStream
    }

    val n = xs.length / 2
    if (n == 0) xs
    else {
      val (ys, zs) = xs splitAt n
      merge(msort(ys), msort(zs)).toList
    }
  }
}
Example.msort(List(8, 15, 3))
println(Example.inversions)

如果它必须保持功能,那么您需要创建一个累加器并将其贯穿所有方法调用,并从每个函数返回一个 Pair,其中累加器值包含在返回结果中,然后对累加器值求和对于每个合并收敛。 (我的function-fu不是很好,在尝试简单的var方法之前,我已经尝试过在功能上解决这个问题。)

【讨论】:

  • 其实是必须的,不允许“var”。
  • 有效吗?如果你的半流是 (1,2) 和 (0, 3),有多少个反转?
  • 确实如此。我的意思是,我希望没有“var”。请看我的更新。
  • 其实不然。尝试 msort(List(8, 15, 3, 1))。应该有 5 个,但它说有 3 个是错误的。
  • @MariusKavansky 这就是我要说的。也许当你遇到y&lt;x 的情况时,倒置不止一次。
猜你喜欢
  • 1970-01-01
  • 2015-07-08
  • 2014-08-04
  • 1970-01-01
  • 2016-07-22
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
相关资源
最近更新 更多