【问题标题】:Divide and conquer algorithm to sort a list where each element is root(n) away from its sorted position分治算法对列表进行排序,其中每个元素距其排序位置的根(n)
【发布时间】:2023-03-10 14:28:02
【问题描述】:

我被一个问题困住了,我只需要一个大方向的提示/点(不要求答案)

该问题询问分治算法的详细信息,该算法给定一个几乎已排序的序列,在 O(n) 时间内产生正确的顺序。

他们所说的几乎排序的意思是给定列表

x_1, x_2, .... x_n

如果排序列表由

表示

y_1, y_2, ... y_n

对于每一个 i, j

x_i == y_j && |i-j|

我想到的唯一一件事是将列表划分为每个级别的 root(n) 组(这将导致它们在第一次拆分时最多为 root(n)),但我不是太确定从那里去哪里,因为你必须在递归备份时一次加入 root(n) 个元素。

我还发现递归复杂度方程是:

T(n) = root(n) * T(n/root(n)) + d * root(n)

master's theorem 可以证明是 O(n) 时间。

所以看起来我在拆分方面走在正确的轨道上,我只是不确定是否应该以特殊方式拆分或比较某种方式或什么。

编辑:所以应该这是正确的答案。

我们的算法如下:如果 n > 1,那么我们递归地对序列的两半(近似)进行排序;现在所有元素都在正确的位置,除了中间的√n个位置(你明白为什么这是真的吗?);所以我们现在对这些位置的元素进行合并。如果我们让 T(n) 是用于对 n 个元素进行排序的时间,那么对于 n > 1,我们有

T(n)≤2T(⌈n=2⌉) +c * √n

由于 √(n) = n.5 和 .5 22,分治递归主定理告诉我们 T(n) ∈O(n)。

我不确定我是否同意,因为排序两半的时间是 O(n2 * log(n2)) 结果为 O(n*logn),最终合并为 O(√n * √n),即 O(n),总共为 O(n *logn + n) -> O(n*logn)

【问题讨论】:

  • 有点不对劲——每个比较排序都需要 Ω(n log n) 次比较来对 √n 个包含 √n 个元素的列表进行排序。
  • 条件 x_i == x_j 看起来很可疑......
  • 更正版本:列表 x(1), ..., x(n) 几乎已排序 如果存在排列 pi 使得 x(pi(1) )
  • @WolframH 你说得对,应该是 x_i == y_j,我现在已经更正了
  • 我可能使问题过于复杂,并且可能暗示对问题有更严格的限制。但是你不能用合并排序来做到这一点。我们知道,在最坏的情况下,一个元素只需要与 2*root(n) 个其他元素进行比较。然后我们得到 T(n) = 2*T(n/2) + 2*root(n) 的修改归并排序递归,由 masters 定理给出 O(n)。还是我错过了什么?

标签: algorithm divide-and-conquer


【解决方案1】:

这种算法可用于在 O(r*r) 时间内对 r 个项目的 r 个列表进行排序,只需连接列表(并在必要时装饰元素)。但是,众所周知,对于 n = r * r,您不能做得比 O(r*r*ln(r)) 或 O(n * ln(n)) 更好。

我猜要么是原始问题有点不同,要么是向您提供原始问题的人在计算复杂度时犯了错误。例如,假设当列表被分成两半时,这两部分仍然几乎排序。 (有一些方法可以通过这种方式拆分列表,比如取第二个元素,但不是列表的每个分区都会有这个属性。)

【讨论】:

  • 就是这样。他假设已分类的财产持有。他最终撤回了作业中的问题
【解决方案2】:

我认为基于比较的排序不可能在 O(n) 中进行。

考虑一个简化的问题,将排序后的数组分成√n个桶,每个桶内的元素被打乱。满足每个元素距离其最终点不超过 √n 个位置的条件。

要解决此问题,您必须对每个存储桶进行排序。使用任何O(n*logn) 排序,您将得到 √n * (√n*log√n)。这是 (1/2)*n*logn,仍然是 O(n*logn)

由于这个简化的问题只能在O(n*logn) 中解决,所以我得出结论,使用基于比较的排序来解决O(n) 中的原始问题是不可能的。

例如,如果您知道所有元素都是某个范围内的整数,那么您将不再局限于基于比较的排序,并且可能能够使用非基于比较的排序解决O(n) 中的问题,比如pigeon sort

【讨论】:

    【解决方案3】:

    第一条线索:T(n) = root(n) * T(n/root(n)) + d * root(n) 不正确。因为它是一个递归函数,所以它不适用于 T(root(n))。

    【讨论】:

    • 它必须是:设 k 为原始列表中的元素数,然后 T(n) = root(k) * T(n/root(k)) + d * root(n) 这将给出 O(n) 但也意味着只会有两个递归调用,因为第一个递归调用将是 T(n/root(k)) = T(root(k)) (因为n = k),然后第二次调用将是 T(root(k)/root(k)),即 T(1)。但现在我只是觉得我在强迫事情发挥作用。
    猜你喜欢
    • 2020-01-05
    • 1970-01-01
    • 2010-09-15
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 2021-10-28
    • 1970-01-01
    相关资源
    最近更新 更多