Algorithm 使用合并排序计算反转数

Algorithm 使用合并排序计算反转数,algorithm,scala,sorting,mergesort,Algorithm,Scala,Sorting,Mergesort,我需要使用合并排序计算反转数: 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)) cas

我需要使用合并排序计算反转数:

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))                           
}
然而,当我尝试时,我失败了

我该怎么做

更新

带有累加器的版本:

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
    }
  } 
不过看起来不太好

更新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)
对象示例{
var反演=0
def msort(xs:List[Int]):List[Int]={
def合并(左:列表[Int],右:列表[Int]):流[Int]=(左,右)匹配{
如果xStream.cons(x,merge(xs,right))
案例(x::xs,y::ys)=>
反转=反转+1
Stream.cons(y,merge(左,y))
case=>if(left.isEmpty)right.toStream else left.toStream
}
val n=xs.length/2
如果(n==0)xs
否则{
val(ys,zs)=xs在n处拆分
合并(msort(ys),msort(zs)).toList
}
}
}
示例.msort(列表(8、15、3))
println(例如,反转)

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

这是我的Scala端口

对象计数反转{
def inversionCount(xs:List[Int],size:Int):(Int,List[Int])=
xs匹配{
如果列表中有多个元素,则案例::=>{//
val mid=尺寸/2
val lsize=mid
val rsize=尺寸-中等
val(左,右)=x.splitAt(中间)
val(lcount,lsorted)=反转计数(左,lsize)
val(rcount,rsorted)=反转计数(右,rsize)
val(合并计数,排序)=反转合并计数(lsorted,lsize,rsorted,
rsize,0,Nil)
val计数=lcount+rcount+mergecount
(计数,排序)
}
案例xs=>(0,xs)
}
def inversionMergeCount(xs:List[Int],m:Int,ys:List[Int],n:Int,
acc:Int,排序:List[Int]):(Int,List[Int])=
(xs,ys)匹配{
大小写(xs,Nil)=>(acc,sorted.reverse++xs)
大小写(Nil,ys)=>(acc,sorted.reverse++ys)
大小写(x::restx,y::resty)=>
if(xy)反转合并计数(xs,m,resty,n-1,acc+m,y::排序)
else inversionMergeCount(restx、m-1、resty、n-1、acc、x::y::排序)
}
}

也许你的意思是反转?:也许这些会有帮助:我在弗雷格的解决方案可能会帮助你:@Aravind,它不会。“当我尝试时,我失败了”--显示你尝试了什么,以及你失败的地方。实际上,它必须是,不允许使用“var”。它有效吗?如果你的半流是(1,2)和(0,3),有多少个反转?它有。我的意思是,我不想有“var”。请看我的更新。事实上,它没有。尝试msort(列表(8,15,3,1))。应该有5个,但上面说有3个是错的。@MariusKavansky这就是我要说的。也许当你遇到
yit的情况时,它是如此复杂。它必须是这样吗?这对2,3,9,2,9不起作用,它输出1个反转,应该是2
def merge(left: List[Int], right: List[Int], invariantAcc: Int = 0): (Stream[Int], Int)
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)
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)
      }

}