使用分而治之的范式提高算法效率

Posted

技术标签:

【中文标题】使用分而治之的范式提高算法效率【英文标题】:Increasing algorithm efficiency using divide and conquer paradigm 【发布时间】:2018-02-22 17:36:40 【问题描述】:

我想找到一个数组中的最小和最大整数。我相对低效的方法是考虑第一个整数到最大值\最小值。然后我将其与其他整数进行比较,如果将更大/更小的整数与当前的最小或最大整数进行比较,则将其替换。这一直持续到数组结束。根据我的计算,复杂性(基于最坏的情况)是 n -1 (n 是数组的大小)。我的问题是如何使用分而治之的范式来提高效率?我尝试将数组分成两部分,然后对两个部分执行与上述相同的算法,尽管这只会降低效率?根据我的计算,复杂度变为 n + 1。

【问题讨论】:

在您的情况下,如果像您已经想到的那样,将数组分成块并设置 几个线程,每个块一个线程,那么 D&C 会更有效。收集线程的结果并使用这个减小了大小的数组重复。 您需要检查数组中的 每个 数字,因此它将是 O(n) blueCat 我使用比较操作来测量复杂度,在最坏的情况下会达到 n - 1? O(n) 或 O(n-1) 没有任何真正的区别;它们都意味着复杂性是线性的,即如果您将输入加倍,它将使处理该输入所需的步骤数加倍。找到无序列表的最大值永远不会低于 O(n) 复杂度,但您当然可以使用 D&C 来为其投入更多处理器,正如 Ripi2 所提到的,并实际提高速度。 无论是 n-1 还是 n+1,复杂度都是 O(n),因为 O(n)、O(n+1) 和 O(n-1)(以及 O(n /2) FWIW) 从字面上看都是一样的。 What is a plain English explanation of “Big O” notation? 但是,您可以查看实际的比较次数(对于寻找最小值和最大值的幼稚实现,这将接近 2n),例如,如果您愿意(并忽略复杂性)。 【参考方案1】:

我会认为你正在使用一个线程

如果数组未排序,复杂度将始终为O(n)。但是,在我看来,您应该检查您是否只需要最大数量?或者第二个最大值,以及第三个最大值..

如果是这种情况,您最好构建一个最大堆(对应情况的最小堆),这需要 O(nlogn) 时间,然后只需检查堆的 peek。

【讨论】:

【参考方案2】:

为了识别n 元素的最大值,算法必须从比较中获得足够的信息。假设最大值为array[i],您必须将array[i]array[0], ... array[i-1], array[i+1], ... array[n-1] 进行比较,以证明array[i] 是最大值。所以所需的最小比较次数是n - 1比较,以便找到最大值。为什么?因为数组中有n 元素,算法必须从比较中获得足够的信息才能找到最大值。


Python 中的示例代码

# Divide-and-Conquer find max of alist
def dc_max(alist, start, end): # first call with start=0, end=len(alist)
    if end - start == 1: # base case: list of 1 element
        return alist[start]
    mid = (start + end) // 2
    x = dc_max(alist, start, mid)
    y = dc_max(alist, mid, end)
    if x > y:
        return x
    return y

# Iterative find max of alist
def it_max(alist):
    current = alist[0]
    for i in range(1, len(alist)):
        if i > current:
            current = i
    return current

两种算法都精确地进行n - 1 比较并且是就地的,因此它们都具有Θ(n) 时间复杂度和O(1) 空间复杂度。


性能现在取决于您的系统。见Is recursion ever faster than looping?

在我的例子中,使用递归方法查找 2**20 数字列表的最大值需要 657ms,而使用迭代方法需要 111ms

【讨论】:

以上是关于使用分而治之的范式提高算法效率的主要内容,如果未能解决你的问题,请参考以下文章

难以思考分而治之的方法

有缺陷的棋盘问题——寻找伪代码算法(分治法)

搜索与排序—— 归并排序与快速排序

算法:分治法和时间复杂度 O(nlogn) 有啥关系?

递归如何转换为非递归

分治,分而治之