数组合并和排序复杂度计算

时间:2017-10-04 14:14:41

标签: algorithm sorting merge

我的算法教科书中有一个练习,我不太确定解决方案。我需要解释为什么这个解决方案:

function array_merge_sorted(array $foo, array $bar)
{
  $baz = array_merge($foo, $bar);
  $baz = array_unique($baz);
  sort($baz);

  return $baz;
}

合并两个数组并对它们进行排序并不是最有效的,我需要提供一个最优化的解决方案,并证明不能做更好的解决方案。

我的想法是使用一个O(n log n)的mergesort算法来合并和排序作为参数传递的两个数组。但是,我怎样才能证明这是最好的解决方案?

1 个答案:

答案 0 :(得分:0)

算法

正如您所说两个输入已经排序,您可以使用简单的拉链式方法。

每个输入数组都有一个指针,指向它的开头。然后比较两个元素,将较小的元素添加到结果中,并使用较小的元素推进数组的指针。然后重复该步骤,直到两个指针都到达结尾,并将所有元素添加到结果中。

您可以在Wikipedia#Merge algorithm找到此类算法的集合,目前显示的方法列为合并两个列表

这是一些伪代码

function Array<Element> mergeSorted(Array<Element> first, Array<Element> second) {
    Array<Element> result = new Array<Element>(first.length + second.length);
    int firstPointer = 0;
    int secondPointer = 0;

    while (firstPointer < first.length && secondPointer < first.length) {
        Element elementOfFirst = first.get(firstPointer);
        Element elementOfSecond = second.get(secondPointer);

        if (elementOfFirst < elementOfSecond) {
            result.add(elementOfFirst);
            firstPointer = firstPointer + 1;
        } else {
            result.add(elementOfSecond);
            secondPointer = secondPointer + 1;
        }
    }
}

证明

该算法显然适用于O(n),其中n是结果列表的大小。或者更精确的是O(max(n, n') n是第一个列表的大小,第二个列表的n'(或O(n + n')是相同的集合。)

这显然也是最佳,因为在某些时候,您需要至少遍历所有元素一次,以便构建结果并知道最终排序。对于此问题,这会产生Omega(n)的下限,因此算法是最优的。

更正式的证明假设更好的任意算法A解决了问题没有看一下每个元素至少一次(或更准确地说,小于O(n))。

我们将该算法不看的那个元素称为e。我们现在可以构造一个输入I,使得e具有一个值,该值满足其自己的数组中的顺序,但算法会在结果数组中将其置错。

我们能够为每个算法A执行此操作,并且由于A始终需要在所有可能的输入上正常工作,我们能够找到一个反例I,以便它失败了。

因此A 不存在Omega(n)是该问题的下限

为什么给定的算法更差

您的给定算法首先合并两个数组,这适用于O(n),这很好。但之后它对阵列进行了排序。

排序(更精确:基于比较的排序)的下限为Omega(n log n)。这意味着每个这样的算法都不能比这更好。

因此,给定算法的总时间复杂度为O(n log n)(因为排序部分)。哪个 O(n)更差,其他算法的复杂性以及最佳解决方案。

然而,为了超级正确,我们还需要争论 sort 方法是否真正产生了这种复杂性,因为它不会获得任意输入,但始终是的结果合并 -method。因此,特定排序方法可能特别适用于此类特定输入,最终会产生O(n)

但我怀疑这是你工作的重点。