分而治之——为啥有效?
Posted
技术标签:
【中文标题】分而治之——为啥有效?【英文标题】:Divide and conquer - why does it work?分而治之——为什么有效? 【发布时间】:2013-03-17 18:17:55 【问题描述】:我知道合并排序和快速排序等算法使用分而治之的范式,但我想知道为什么它可以降低时间复杂度...
为什么“分而治之”的算法通常比非分而治之的算法效果更好?
【问题讨论】:
why does it work
是什么意思?
“降低时间复杂度..”
【参考方案1】:
分而治之的算法工作得更快,因为它们最终做的工作更少。
考虑一下二分搜索的经典分治算法:二分搜索不是通过查看N
项目来找到答案,而是最终只检查其中的Log2N
。自然,当你做的工作越少,你就能完成得越快;这正是分治算法所发生的事情。
当然,结果在很大程度上取决于您的策略在划分工作方面的效果:如果划分在每一步都或多或少公平(即您将工作分成两半),您将获得完美的Log2N
速度。但是,如果划分不是完美的(例如快速排序的最坏情况,当它花费O(n^2)
对数组进行排序时,因为它在每次迭代中只消除了一个元素),那么分而治之的策略就没有帮助,因为你的算法不会减少工作量。
【讨论】:
【参考方案2】:分而治之,因为数学支持它!
考虑一些分而治之的算法:
1) 二分搜索:该算法每次将您的输入空间减少一半。很明显,这比线性搜索要好,因为我们会避免查看很多元素。
但是好到什么程度呢?我们得到了重复(注意:这是最坏情况分析的重复):
T(n) = T(n/2) + O(1)
数学暗示T(n) = Theta(log n)
。因此,这比线性搜索要好得多。
2) 合并排序: 这里我们分成(几乎)相等的两半,对两半进行排序然后合并。为什么这应该比二次方更好?这是重复:
T(n) = 2T(n/2) + O(n)
T(n) = Theta(n log n)
可以用数学方法证明(比如使用主定理)。因此 T(n) 渐近优于二次。
观察到 naive 快速排序最终给了我们最坏情况下的重复
T(n) = T(n-1) + O(n)
从数学上讲,它是二次的,在最坏的情况下,并不比冒泡排序好(渐近地说)。但是,我们可以证明,在平均情况下,快速排序是 O(n log n)。
3 选择算法:这是一种分治算法,用于查找第 k^th 大元素。这种算法是否比排序更好(甚至不是二次的),这一点并不明显。
但在数学上,它的重现(也是最坏的情况)结果是
T(n) = T(n/5) + T(7n/10 + 6) + O(n)
可以用数学方法证明T(n) = O(n)
,因此它比排序要好。
也许是一种常见的看待它们的方式:
您可以将算法视为树,其中每个子问题都变成当前问题的子树,并且可以用完成的工作量标记节点,然后可以将每个节点的总工作量相加。
对于二分查找,工作量是O(1)(只是比较),其中一个子树,工作量是0,所以总工作量是O(log n)(本质上是一条路径,就像我们在二叉搜索树中所做的那样)。
对于合并排序,对于具有 k 个子节点的节点,工作量为 O(k)(合并步骤)。每个级别完成的工作是 O(n) (n, n/2 + n/2, n/4 + n/4 + n/4 + n/4 等),并且有 O(log n) 个级别,并且所以归并排序是 O(n log n)。
对于快速排序,在最坏的情况下二叉树实际上是一个链表,所以完成的工作是 n+n-1 + ... + 1 = Omega(n^2)。
对于选择排序,我不知道如何将其可视化,但我相信将其视为具有 3 个孩子(n/5、7n/10 和其余)的树可能仍然有帮助。
【讨论】:
【参考方案3】:分而治之的算法不会“通常效果更好”。它们只是工作,就像其他非分而治之的算法一样。它们不会降低排序复杂度,但与其他算法一样好。
【讨论】:
理论上是否有可能找到另一种算法来解决问题,该算法具有与快速排序相同的 O 复杂度,但不是分治法? @gongzhitaao 嗯,其他的,我需要先启动一个堆并运行,这需要时间 @JohnnyPauling make_heap 需要 O(n),基于比较的最佳排序是 O(nlogn) 那么可能是一个不错的选择,但我怀疑 heapsort 的性能比 quikcksort 差 @JohnnyPauling 您是否在输入中尝试过不同的算法?这是了解其中一个是否更快的唯一方法,因为它们具有相同的复杂性,并且在某些输入上快速排序可能更快,而在其他输入上使用堆排序。以上是关于分而治之——为啥有效?的主要内容,如果未能解决你的问题,请参考以下文章