使用分而治之的范式提高算法效率
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。
【讨论】:
以上是关于使用分而治之的范式提高算法效率的主要内容,如果未能解决你的问题,请参考以下文章