【问题标题】:O(log n) algorithm for finding max of array?O(log n)算法用于查找数组的最大值?
【发布时间】:2012-09-08 14:46:59
【问题描述】:

是否存在一种算法可以在 O(log n) 时间内找到未排序数组的最大值?

【问题讨论】:

  • @elyashiv 这叫做并行归约。每个核心/处理器都从少量元素的最大值开始,然后进行二叉树缩减。
  • @amit 因此是“非常多的内核/处理器”。即如k > n.
  • @amit 使用你的公式,当 n == k 时会发生什么? n/n + log(n) = 1 + log(n) = log(n)。所以,如果你有 n 个核心(实际上 n/2 个核心就足够了),你可以获得 O( log(n) )。尽管您可能需要添加一个术语来表示并行化开销(处理器之间的通信延迟)。
  • @Xantix, @Mystical:这是一个特殊情况,核心数与元素数线性。传统上,在并行分析中,我们有以下两种选择之一:(1) 将k 视为某个常数,因此忽略它。 (2) 明确使用k 表示法。我从未见过任何书/文章分析算法假设某些功能k = f(n) 的核心数量f(当然,除了常数)。如果有人这样做 - 请参考我这个来源,我会回复我的评论。
  • @Mystical,我认为线程分配复杂度仍然是O(n),所以你最终得到O(n log n)。布伦特定理可能有助于此处的一些算法级联(证明很重要),但也许我误解了这个概念。请参阅uni-graz.at/~haasegu/Lectures/GPU_CUDA/Lit/reduction.pdf 第 30 张幻灯片。

标签: algorithm big-o


【解决方案1】:

我认为使用 Segment tree 可能会有所帮助,您可以实现 log(N) 成本。

【讨论】:

    【解决方案2】:

    如果您使用N 处理器,则可以在O(log N) 时间内完成。 但是工作复杂度仍然是O(N)

    如果使用N^2 处理器,您可以通过应用Usain Bolt 算法将时间复杂度降低到O(1)

    【讨论】:

      【解决方案3】:

      这是非常古老的,但我不同意给出的答案。 是的,它可以通过并行硬件在对数时间内完成。

      时间复杂度为:

      O(log(n) * log(m))
      

      n 是要比较的数字数量; m 是每个数字的大小。

      但是,硬件大小为:

      O(n * m)
      

      算法是:

      1. 成对比较数字。这个时间是O(log(m)),大小是O(n * m),使用进位超前比较器。

      2. 使用1中的结果来复用1的两个输入。这个时间是O(1),大小是O(n * m)

      3. 现在你有了一个初始大小一半的数组;转到步骤 1。此循环重复 log(n) 次,因此总时间为 O(log(n) * log(m)),总大小为 O(n * m)

      添加更多的 MUX,如果需要,您还可以跟踪最大数字的索引,而不会增加算法的复杂性。

      【讨论】:

      • 在 O(1) 中也可以做到,但这并不实用;硬件大小会随着 n 和 m 快速增长。
      【解决方案4】:

      当然不是。假设还有一个元素,您还没有将它与任何其他元素进行比较。所以不能保证你没有比较的元素不是最大元素

      并假设您的比较图(元素的顶点和比较的边)具有多个组件。在这种情况下,您必须放置一条边(以最好的方式在最多两个组件之间)。我们可以看到,必须在 n-1 处进行操作

      【讨论】:

        【解决方案5】:

        O(log(N)) 中无法做到这一点。在最佳/最差/平均情况下是O(N),因为需要访问数组中的每个项目以确定它是否是最大的。数组是未排序的,这意味着你不能偷工减料。

        即使在并行化的情况下,这也不能在O(N) 中完成,因为 Big-O 表示法并不关心一个 CPU 有多少或每个 CPU 的频率是多少。专门从这里抽象出来以粗略估计问题。

        可以忽略并行化,因为可以认为划分作业所花费的时间等于顺序执行的时间。这是由于忽略了常数的原因。以下都是一样的:

        O(N) = O(Const * N) = O(N / Const) = O(N + Const) = O(N - Const)
        

        另一方面,在实践中,分治并行算法可以为您带来一些性能优势,因此它的运行速度可能会更快一些。幸运的是,Big-O 不处理这种细粒度的算法复杂度分析。

        【讨论】:

        • Big O 分析当然可以处理分而治之的复杂性。如果您的并行度同时进行 n/2 次比较,那么它会降低到 O(log n) 复杂度。如果 n 足够大并且您实际上拥有如此多的处理器,那么细粒度的点就完全无关紧要了。您将获得实际的时间节省。划分作业可能是一次性任务,而计算可能会重复多次。让大量专用处理器等待单独执行此任务并不是特别现实,但它在理论上和实践上都是可行的
        • @GregoryMorse 假设有可能拥有 N 核超级计算机。可以假设可以在每个核心之间划分任务。这样每个核心都执行一些计算任务。哪个 使这是一个O(1) 任务,前提是我们不必然后 征服 - 比较彼此之间的计算以找出最大的计算价值观。比较是O(1) 操作,但需要重复N 次,因为没有办法不比较某些东西并仍然获得最大值。因此O(log n) 是不可能完成这项任务的,无论内核数量如何。
        • 这是不正确的,征服部分是 O(log n) 步。锦标赛获胜者风格算法意味着每一步都需要一半的比较。因此,首先比较 O(1) 中的 n/2,然后比较 O(1) 中的 n/4 ...直到剩下 1,最大值。这是原型的 log n 算法
        • 问题是,数组没有排序。如果它是一个排序数组,那么可以尝试使用类似的东西,但是第一个(最后一个)元素将在O(1) 中提供结果。这个想法如何在4, 1, 0, 22, 7, 3, 5 上发挥作用,如果我将22 移动到第一个/最后一个位置会怎样?此逻辑不能应用于未排序的数据。
        • @GregoryMorse One 不能在这里简单地使用锦标赛选择,因为需要先建立锦标赛。建立锦标赛是一个 O(n)。我很高兴把它留在这里:你认为你是对的,就这样吧。
        【解决方案6】:

        这个问题被问了很多(这是一个流行的 CS 作业问题还是什么?),答案总是一样的:

        从数学上考虑。除非对数组进行排序,否则没有什么可以“减半”来为您提供 log(n) 行为。

        阅读问题 cmets 进行更深入的讨论(无论如何,这可能超出了问题的范围)。

        【讨论】:

        • 双音阵列呢?我们如何在具有 log(n) 复杂度的数组中找到双调数(最大数)?
        • 显然这个问题是指并行计算,在哪种情况下它肯定是可能的。
        【解决方案7】:

        考虑一下:如果不访问每个元素,你怎么知道你没有访问过的某个元素不大于你迄今为止找到的最大元素?

        【讨论】:

          【解决方案8】:

          没有。是 O(n)。在最坏的情况下,必须访问和比较数组的所有成员。

          【讨论】:

            【解决方案9】:

            没有。您必须至少遍历数组一次。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-04-03
              相关资源
              最近更新 更多