我需要使用合并排序来计算反转次数:
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 < 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)
不过,看起来不太好。
更新2:
而且它实际上不算正确,我找不到错误在哪里。
最佳答案
这是我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)
}
}