【问题标题】:Array merging and sorting complexity calculation数组合并排序复杂度计算
【发布时间】:2017-10-04 14:14:40
【问题描述】:

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

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) 的合并排序算法来合并和排序作为参数传递的两个数组。但我如何证明这是有史以来最好的解决方案?

【问题讨论】:

  • 你首先需要证明合并和排序的下界。您可以通过在网上搜索找到解决方案和解释,这是一个非常理论化的论点,争论需要进行多少比较才能找到排序。之后,您需要找到具有这种复杂性的算法。就像一个问题一样,对这两个数组有什么了解吗?例如,如果它们已经排序?然后,理想的算法使用 类似拉链的 方法,同时处理两个数组,始终插入两个列表的较低元素,依此类推O(n)
  • 两个数组参数排序
  • Mergesort 在O(n log n) 中工作,这将是排序的最佳解决方案之一,因为基于比较的排序算法的下限在Omega(n log n) (see also) 中。但是,我不知道您对 合并 两个数组 并对其进行排序 的附加要求如何发挥作用。
  • 合并和排序两个有序数组的最佳优化解决方案是什么?

标签: algorithm sorting merge


【解决方案1】:

算法

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

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

您可以在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 方法是否真的产生了这种复杂性,因为它不会得到任意输入,而是总是得到 的结果合并-方法。因此,特定排序方法可能对此类特定输入特别有效,最终产生O(n)

但我怀疑这是否是您的任务重点。

【讨论】:

  • 完美解决方案。只问你两个问题:1. 我没有得到你的证明来证明这个算法是最优的,说“这会为这个问题产生一个 Omega(n) 的下限,因此算法是最优的。”。
  • 2.如何解决重复值的问题?例如,如果我在两个数组中都有数字 3?
  • 非常感谢。还有两个问题,在那之后我真的结束了打扰。这个解决方案是 O(n) 比 O(n log n) 好,对吧?回到这篇文章的主题,为什么我在上面发布的代码不是最好的优化?我想是因为它首先合并,在使数组唯一值和排序后
  • 太好了!非常感谢!
  • 一个注意事项:我认为当我们在两个数组中具有相同的值时,应该增加两者的指针
猜你喜欢
  • 2017-08-01
  • 2013-10-21
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多