This commit is contained in:
krahets
2023-08-20 13:37:20 +08:00
parent 88e0b11361
commit 96fded547b
35 changed files with 777 additions and 716 deletions

View File

@ -2411,15 +2411,15 @@
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_1" class="md-nav__link">
操作数量优化
<a href="#1" class="md-nav__link">
1. &nbsp; 操作数量优化
</a>
</li>
<li class="md-nav__item">
<a href="#_2" class="md-nav__link">
并行计算优化
<a href="#2" class="md-nav__link">
2. &nbsp; 并行计算优化
</a>
</li>
@ -3425,15 +3425,15 @@
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_1" class="md-nav__link">
操作数量优化
<a href="#1" class="md-nav__link">
1. &nbsp; 操作数量优化
</a>
</li>
<li class="md-nav__item">
<a href="#_2" class="md-nav__link">
并行计算优化
<a href="#2" class="md-nav__link">
2. &nbsp; 并行计算优化
</a>
</li>
@ -3503,7 +3503,7 @@
<h2 id="1212">12.1.2 &nbsp; 通过分治提升效率<a class="headerlink" href="#1212" title="Permanent link">&para;</a></h2>
<p>分治不仅可以有效地解决算法问题,<strong>往往还可以带来算法效率的提升</strong>。在排序算法中,快速排序、归并排序、堆排序相较于选择、冒泡、插入排序更快,就是因为它们应用了分治策略。</p>
<p>那么,我们不禁发问:<strong>为什么分治可以提升算法效率,其底层逻辑是什么</strong>?换句话说,将大问题分解为多个子问题、解决子问题、将子问题的解合并为原问题的解,这几步的效率为什么比直接解决原问题的效率更高?这个问题可以从操作数量和并行计算两方面来讨论。</p>
<h3 id="_1">操作数量优化<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h3>
<h3 id="1">1. &nbsp; 操作数量优化<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p>以「冒泡排序」为例,其处理一个长度为 <span class="arithmatex">\(n\)</span> 的数组需要 <span class="arithmatex">\(O(n^2)\)</span> 时间。假设我们把数组从中点分为两个子数组,则划分需要 <span class="arithmatex">\(O(n)\)</span> 时间,排序每个子数组需要 <span class="arithmatex">\(O((\frac{n}{2})^2)\)</span> 时间,合并两个子数组需要 <span class="arithmatex">\(O(n)\)</span> 时间,总体时间复杂度为:</p>
<div class="arithmatex">\[
O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n)
@ -3522,7 +3522,7 @@ n(n - 4) &amp; &gt; 0
<p><strong>这意味着当 <span class="arithmatex">\(n &gt; 4\)</span> 时,划分后的操作数量更少,排序效率应该更高</strong>。请注意,划分后的时间复杂度仍然是平方阶 <span class="arithmatex">\(O(n^2)\)</span> ,只是复杂度中的常数项变小了。</p>
<p>进一步想,<strong>如果我们把子数组不断地再从中点划分为两个子数组</strong>,直至子数组只剩一个元素时停止划分呢?这种思路实际上就是「归并排序」,时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span></p>
<p>再思考,<strong>如果我们多设置几个划分点</strong>,将原数组平均划分为 <span class="arithmatex">\(k\)</span> 个子数组呢?这种情况与「桶排序」非常类似,它非常适合排序海量数据,理论上时间复杂度可以达到 <span class="arithmatex">\(O(n + k)\)</span></p>
<h3 id="_2">并行计算优化<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h3>
<h3 id="2">2. &nbsp; 并行计算优化<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<p>我们知道,分治生成的子问题是相互独立的,<strong>因此通常可以并行解决</strong>。也就是说,分治不仅可以降低算法的时间复杂度,<strong>还有利于操作系统的并行优化</strong></p>
<p>并行优化在多核或多处理器的环境中尤其有效,因为系统可以同时处理多个子问题,更加充分地利用计算资源,从而显著减少总体的运行时间。</p>
<p>比如在桶排序中,我们将海量的数据平均分配到各个桶中,则可所有桶的排序任务分散到各个计算单元,完成后再进行结果合并。</p>