Scala如何进行合并排序?

合并排序是一种经典的“分而治之”排序算法。 您应该永远不必编写一个,因为当标准库类已经为您完成时,您这样做就很愚蠢了。 但是,展示Scala编程技术的一些特性很有用。 首先,快速回顾一下合并排序。 这是一个分而治之的算法。 元素列表分为越来越小的列表。 当列表具有一个元素时,将被视为已排序。 然后将其与旁边的列表合并。 如果没有更多列表要合并,则认为原始数据集已排序。 现在,让我们看看如何使用Java中的命令式方法来做到这一点。

public void sort(int[] values) {
   int[] numbers = values;
   int[] auxillaryNumbers = new int[values.length];
   mergesort(numbers, auxillaryNumbers, 0, values.length - 1);
}

private void mergesort(int [] numbers, int [] auxillaryNumbers, int low, int high) {
    // Check if low is smaller then high, if not then the array is sorted
    if (low < high) {
        // Get the index of the element which is in the middle
        int middle = low + (high - low) / 2;

        // Sort the left side of the array
        mergesort(numbers, auxillaryNumbers, low, middle);
        // Sort the right side of the array
        mergesort(numbers, auxillaryNumbers, middle + 1, high);

        // Combine them both
        // Alex: the first time we hit this when there is min difference between high and low.
        merge(numbers, auxillaryNumbers, low, middle, high);
    }
}

/**
 * Merges a[low .. middle] with a[middle..high].
 * This method assumes a[low .. middle] and a[middle..high] are sorted. It returns
 * a[low..high] as an sorted array. 
 */
private void merge(int [] a, int[] aux, int low, int middle, int high) {
    // Copy both parts into the aux array
    for (int k = low; k <= high; k++) {
        aux[k] = a[k];
    }

    int i = low, j = middle + 1;
    for (int k = low; k <= high; k++) {
        if (i > middle)                      a[k] = aux[j++];
        else if (j > high)                   a[k] = aux[i++];
        else if (aux[j] < aux[i])            a[k] = aux[j++];
        else                                 a[k] = aux[i++];
    }
}

public static void main(String args[]){
     ...
     ms.sort(new int[] {5, 3, 1, 17, 2, 8, 19, 11});
     ...
}

}

讨论中…

  1. 辅助数组用于实现排序。 要排序的元素被复制到其中,然后一旦排序就被复制回去。 重要的是,此阵列只能创建一次,否则创建的大量阵列可能会降低性能。 merge方法不必创建辅助数组,但是由于它会更改对象,因此意味着merge方法具有副作用。
  2. 合并排序big(O)性能为N logN。

现在让我们来看看Scala解决方案。

def mergeSort(xs: List[Int]): List[Int] = {
    val n = xs.length / 2
    if (n == 0) xs
    else {
      def merge(xs: List[Int], ys: List[Int]): List[Int] =
          (xs, ys) match {
          case(Nil, ys) => ys
          case(xs, Nil) => xs
          case(x :: xs1, y :: ys1) =>
            if (x < y) x::merge(xs1, ys)
            else y :: merge(xs, ys1)
      }
      val (left, right) = xs splitAt(n)
      merge(mergeSort(left), mergeSort(right))
    }
  }

关键讨论点:

  1. 这是相同的分而治之的思想。
  2. splitAt函数用于每次将数据分成一个元组。 对于每次递归,这将创建一个新的元组。
  3. 然后使用本地函数合并来执行合并。 局部函数是一个有用的功能,因为它们有助于促进封装并防止代码膨胀。
  4. 不论mergeSort()还是merge()函数都有任何副作用。 他们不更改任何对象。 他们创建(并丢弃)对象。
  5. 因为没有跨合并的迭代传递数据,所以不需要传递开始和结束的指针,而这些指针可能会变得非常麻烦。
  6. 此合并递归使用模式匹配在这里效果很好。 不仅存在数据列表的匹配,而且发生匹配时,数据列表也被分配给变量:
    • x表示左侧列表中的顶部元素
    • xs1其余列表
    • y表示右边列表中的顶部元素
    • ys1表示右边列表中的其余数据

这样可以轻松比较顶部的元素,并传递剩余的日期进行比较。 Java中是否可以使用迭代方法? 当然。 但这将更加复杂。 您没有任何模式匹配,也无法像Scala那样通过使对象变为val或var来声明对象是不可变的。 在Java中,如果以命令式样式完成对象遍历循环的迭代而更改代码,那么阅读此问题的代码总是比较容易的。 但是Scala的功能性递归方法可能非常简洁。 因此,在这里我们看到一个示例,该示例说明了Scala如何使更容易实现良好,干净,简洁的递归并使功能性方法变得更加可行。

参考: Scala如何进行合并排序? 从我们的JCG合作伙伴 Alex Staveley在都柏林的技术博客博客中获得。

翻译自: https://www.javacodegeeks.com/2013/05/how-could-scala-do-a-merge-sort.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值