|
|
@ -18,7 +18,7 @@
|
|
|
|
<link rel="prev" href="../../chapter_tree/summary/">
|
|
|
|
<link rel="prev" href="../../chapter_tree/summary/">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="next" href="../../chapter_graph/graph/">
|
|
|
|
<link rel="next" href="../build_heap/">
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="icon" href="../../assets/images/favicon.png">
|
|
|
|
<link rel="icon" href="../../assets/images/favicon.png">
|
|
|
|
<meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.0.11">
|
|
|
|
<meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.0.11">
|
|
|
@ -1055,6 +1055,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_9" id="__nav_9_label" tabindex="0">
|
|
|
|
<label class="md-nav__link" for="__nav_9" id="__nav_9_label" tabindex="0">
|
|
|
|
8. 堆
|
|
|
|
8. 堆
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
@ -1154,13 +1156,6 @@
|
|
|
|
堆顶元素出堆
|
|
|
|
堆顶元素出堆
|
|
|
|
</a>
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
|
|
|
|
|
|
<a href="#_5" class="md-nav__link">
|
|
|
|
|
|
|
|
输入数据并建堆 *
|
|
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</li>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
@ -1184,6 +1179,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
|
|
|
|
|
|
<a href="../build_heap/" class="md-nav__link">
|
|
|
|
|
|
|
|
8.2. 建堆操作 *
|
|
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</li>
|
|
|
@ -1636,13 +1645,6 @@
|
|
|
|
堆顶元素出堆
|
|
|
|
堆顶元素出堆
|
|
|
|
</a>
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
|
|
|
|
|
|
<a href="#_5" class="md-nav__link">
|
|
|
|
|
|
|
|
输入数据并建堆 *
|
|
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</li>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
@ -2882,163 +2884,6 @@
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<h3 id="_5">输入数据并建堆 *<a class="headerlink" href="#_5" title="Permanent link">¶</a></h3>
|
|
|
|
|
|
|
|
<p>如果我们想要直接输入一个列表并将其建堆,那么该怎么做呢?最直接地,考虑使用「元素入堆」方法,将列表元素依次入堆。元素入堆的时间复杂度为 <span class="arithmatex">\(O(\log n)\)</span> ,而平均长度为 <span class="arithmatex">\(\frac{n}{2}\)</span> ,因此该方法的总体时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。</p>
|
|
|
|
|
|
|
|
<p>然而,存在一种更加优雅的建堆方法。设结点数量为 <span class="arithmatex">\(n\)</span> ,我们先将列表所有元素原封不动添加进堆,<strong>然后迭代地对各个结点执行「从顶至底堆化」</strong>。当然,<strong>无需对叶结点执行堆化</strong>,因为其没有子结点。</p>
|
|
|
|
|
|
|
|
<div class="tabbed-set tabbed-alternate" data-tabs="8:10"><input checked="checked" id="__tabbed_8_1" name="__tabbed_8" type="radio" /><input id="__tabbed_8_2" name="__tabbed_8" type="radio" /><input id="__tabbed_8_3" name="__tabbed_8" type="radio" /><input id="__tabbed_8_4" name="__tabbed_8" type="radio" /><input id="__tabbed_8_5" name="__tabbed_8" type="radio" /><input id="__tabbed_8_6" name="__tabbed_8" type="radio" /><input id="__tabbed_8_7" name="__tabbed_8" type="radio" /><input id="__tabbed_8_8" name="__tabbed_8" type="radio" /><input id="__tabbed_8_9" name="__tabbed_8" type="radio" /><input id="__tabbed_8_10" name="__tabbed_8" type="radio" /><div class="tabbed-labels"><label for="__tabbed_8_1">Java</label><label for="__tabbed_8_2">C++</label><label for="__tabbed_8_3">Python</label><label for="__tabbed_8_4">Go</label><label for="__tabbed_8_5">JavaScript</label><label for="__tabbed_8_6">TypeScript</label><label for="__tabbed_8_7">C</label><label for="__tabbed_8_8">C#</label><label for="__tabbed_8_9">Swift</label><label for="__tabbed_8_10">Zig</label></div>
|
|
|
|
|
|
|
|
<div class="tabbed-content">
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.java</span><pre><span></span><code><a id="__codelineno-50-1" name="__codelineno-50-1" href="#__codelineno-50-1"></a><span class="cm">/* 构造方法,根据输入列表建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-2" name="__codelineno-50-2" href="#__codelineno-50-2"></a><span class="n">MaxHeap</span><span class="p">(</span><span class="n">List</span><span class="o"><</span><span class="n">Integer</span><span class="o">></span><span class="w"> </span><span class="n">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-3" name="__codelineno-50-3" href="#__codelineno-50-3"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-4" name="__codelineno-50-4" href="#__codelineno-50-4"></a><span class="w"> </span><span class="n">maxHeap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="o"><></span><span class="p">(</span><span class="n">nums</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-5" name="__codelineno-50-5" href="#__codelineno-50-5"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-6" name="__codelineno-50-6" href="#__codelineno-50-6"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parent</span><span class="p">(</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-7" name="__codelineno-50-7" href="#__codelineno-50-7"></a><span class="w"> </span><span class="n">siftDown</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-8" name="__codelineno-50-8" href="#__codelineno-50-8"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-50-9" name="__codelineno-50-9" href="#__codelineno-50-9"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.cpp</span><pre><span></span><code><a id="__codelineno-51-1" name="__codelineno-51-1" href="#__codelineno-51-1"></a><span class="cm">/* 构造方法,根据输入列表建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-2" name="__codelineno-51-2" href="#__codelineno-51-2"></a><span class="n">MaxHeap</span><span class="p">(</span><span class="n">vector</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-3" name="__codelineno-51-3" href="#__codelineno-51-3"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-4" name="__codelineno-51-4" href="#__codelineno-51-4"></a><span class="w"> </span><span class="n">maxHeap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">;</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-5" name="__codelineno-51-5" href="#__codelineno-51-5"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-6" name="__codelineno-51-6" href="#__codelineno-51-6"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parent</span><span class="p">(</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-7" name="__codelineno-51-7" href="#__codelineno-51-7"></a><span class="w"> </span><span class="n">siftDown</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-8" name="__codelineno-51-8" href="#__codelineno-51-8"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-51-9" name="__codelineno-51-9" href="#__codelineno-51-9"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.py</span><pre><span></span><code><a id="__codelineno-52-1" name="__codelineno-52-1" href="#__codelineno-52-1"></a><span class="sd">""" 构造方法 """</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-52-2" name="__codelineno-52-2" href="#__codelineno-52-2"></a><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nums</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">int</span><span class="p">]):</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-52-3" name="__codelineno-52-3" href="#__codelineno-52-3"></a> <span class="c1"># 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-52-4" name="__codelineno-52-4" href="#__codelineno-52-4"></a> <span class="bp">self</span><span class="o">.</span><span class="n">max_heap</span> <span class="o">=</span> <span class="n">nums</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-52-5" name="__codelineno-52-5" href="#__codelineno-52-5"></a> <span class="c1"># 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-52-6" name="__codelineno-52-6" href="#__codelineno-52-6"></a> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">parent</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">),</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-52-7" name="__codelineno-52-7" href="#__codelineno-52-7"></a> <span class="bp">self</span><span class="o">.</span><span class="n">sift_down</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.go</span><pre><span></span><code><a id="__codelineno-53-1" name="__codelineno-53-1" href="#__codelineno-53-1"></a><span class="cm">/* 构造方法,根据切片建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-2" name="__codelineno-53-2" href="#__codelineno-53-2"></a><span class="kd">func</span><span class="w"> </span><span class="nx">newMaxHeap</span><span class="p">(</span><span class="nx">nums</span><span class="w"> </span><span class="p">[]</span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="nx">maxHeap</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-3" name="__codelineno-53-3" href="#__codelineno-53-3"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-4" name="__codelineno-53-4" href="#__codelineno-53-4"></a><span class="w"> </span><span class="nx">h</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&</span><span class="nx">maxHeap</span><span class="p">{</span><span class="nx">data</span><span class="p">:</span><span class="w"> </span><span class="nx">nums</span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-5" name="__codelineno-53-5" href="#__codelineno-53-5"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">h</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">--</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-6" name="__codelineno-53-6" href="#__codelineno-53-6"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-7" name="__codelineno-53-7" href="#__codelineno-53-7"></a><span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">siftDown</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-8" name="__codelineno-53-8" href="#__codelineno-53-8"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-9" name="__codelineno-53-9" href="#__codelineno-53-9"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">h</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-53-10" name="__codelineno-53-10" href="#__codelineno-53-10"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.js</span><pre><span></span><code><a id="__codelineno-54-1" name="__codelineno-54-1" href="#__codelineno-54-1"></a><span class="cm">/* 构造方法,建立空堆或根据输入列表建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-2" name="__codelineno-54-2" href="#__codelineno-54-2"></a><span class="kr">constructor</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-3" name="__codelineno-54-3" href="#__codelineno-54-3"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-4" name="__codelineno-54-4" href="#__codelineno-54-4"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="err">#</span><span class="nx">maxHeap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">nums</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="kc">undefined</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">[...</span><span class="nx">nums</span><span class="p">];</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-5" name="__codelineno-54-5" href="#__codelineno-54-5"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-6" name="__codelineno-54-6" href="#__codelineno-54-6"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="err">#</span><span class="nx">parent</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">);</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-7" name="__codelineno-54-7" href="#__codelineno-54-7"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="err">#</span><span class="nx">siftDown</span><span class="p">(</span><span class="nx">i</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-8" name="__codelineno-54-8" href="#__codelineno-54-8"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-54-9" name="__codelineno-54-9" href="#__codelineno-54-9"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.ts</span><pre><span></span><code><a id="__codelineno-55-1" name="__codelineno-55-1" href="#__codelineno-55-1"></a><span class="cm">/* 构造方法,建立空堆或根据输入列表建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-2" name="__codelineno-55-2" href="#__codelineno-55-2"></a><span class="kr">constructor</span><span class="p">(</span><span class="nx">nums?</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">[])</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-3" name="__codelineno-55-3" href="#__codelineno-55-3"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-4" name="__codelineno-55-4" href="#__codelineno-55-4"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">maxHeap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">nums</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="kc">undefined</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">[...</span><span class="nx">nums</span><span class="p">];</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-5" name="__codelineno-55-5" href="#__codelineno-55-5"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-6" name="__codelineno-55-6" href="#__codelineno-55-6"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">parent</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">);</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-7" name="__codelineno-55-7" href="#__codelineno-55-7"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">siftDown</span><span class="p">(</span><span class="nx">i</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-8" name="__codelineno-55-8" href="#__codelineno-55-8"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-55-9" name="__codelineno-55-9" href="#__codelineno-55-9"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.c</span><pre><span></span><code><a id="__codelineno-56-1" name="__codelineno-56-1" href="#__codelineno-56-1"></a><span class="p">[</span><span class="n">class</span><span class="p">]{</span><span class="n">maxHeap</span><span class="p">}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">newMaxHeap</span><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.cs</span><pre><span></span><code><a id="__codelineno-57-1" name="__codelineno-57-1" href="#__codelineno-57-1"></a><span class="cm">/* 构造函数,根据输入列表建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-2" name="__codelineno-57-2" href="#__codelineno-57-2"></a><span class="n">MaxHeap</span><span class="p">(</span><span class="n">IEnumerable</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">nums</span><span class="p">)</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-3" name="__codelineno-57-3" href="#__codelineno-57-3"></a><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-4" name="__codelineno-57-4" href="#__codelineno-57-4"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-5" name="__codelineno-57-5" href="#__codelineno-57-5"></a><span class="w"> </span><span class="n">maxHeap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">List</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="p">(</span><span class="n">nums</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-6" name="__codelineno-57-6" href="#__codelineno-57-6"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-7" name="__codelineno-57-7" href="#__codelineno-57-7"></a><span class="w"> </span><span class="kt">var</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parent</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-8" name="__codelineno-57-8" href="#__codelineno-57-8"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="m">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">--</span><span class="p">)</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-9" name="__codelineno-57-9" href="#__codelineno-57-9"></a><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-10" name="__codelineno-57-10" href="#__codelineno-57-10"></a><span class="w"> </span><span class="n">siftDown</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-11" name="__codelineno-57-11" href="#__codelineno-57-11"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-57-12" name="__codelineno-57-12" href="#__codelineno-57-12"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.swift</span><pre><span></span><code><a id="__codelineno-58-1" name="__codelineno-58-1" href="#__codelineno-58-1"></a><span class="cm">/* 构造方法,根据输入列表建堆 */</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-2" name="__codelineno-58-2" href="#__codelineno-58-2"></a><span class="kd">init</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="p">[</span><span class="nb">Int</span><span class="p">])</span> <span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-3" name="__codelineno-58-3" href="#__codelineno-58-3"></a> <span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-4" name="__codelineno-58-4" href="#__codelineno-58-4"></a> <span class="n">maxHeap</span> <span class="p">=</span> <span class="n">nums</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-5" name="__codelineno-58-5" href="#__codelineno-58-5"></a> <span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-6" name="__codelineno-58-6" href="#__codelineno-58-6"></a> <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="bp">stride</span><span class="p">(</span><span class="n">from</span><span class="p">:</span> <span class="n">parent</span><span class="p">(</span><span class="n">i</span><span class="p">:</span> <span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">),</span> <span class="n">through</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="n">by</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-7" name="__codelineno-58-7" href="#__codelineno-58-7"></a> <span class="n">siftDown</span><span class="p">(</span><span class="n">i</span><span class="p">:</span> <span class="n">i</span><span class="p">)</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-8" name="__codelineno-58-8" href="#__codelineno-58-8"></a> <span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-58-9" name="__codelineno-58-9" href="#__codelineno-58-9"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tabbed-block">
|
|
|
|
|
|
|
|
<div class="highlight"><span class="filename">my_heap.zig</span><pre><span></span><code><a id="__codelineno-59-1" name="__codelineno-59-1" href="#__codelineno-59-1"></a><span class="c1">// 构造方法,根据输入列表建堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-2" name="__codelineno-59-2" href="#__codelineno-59-2"></a><span class="k">fn</span><span class="w"> </span><span class="n">init</span><span class="p">(</span><span class="n">self</span><span class="o">:</span><span class="w"> </span><span class="o">*</span><span class="n">Self</span><span class="p">,</span><span class="w"> </span><span class="n">allocator</span><span class="o">:</span><span class="w"> </span><span class="n">std</span><span class="p">.</span><span class="n">mem</span><span class="p">.</span><span class="n">Allocator</span><span class="p">,</span><span class="w"> </span><span class="n">nums</span><span class="o">:</span><span class="w"> </span><span class="p">[]</span><span class="kr">const</span><span class="w"> </span><span class="n">T</span><span class="p">)</span><span class="w"> </span><span class="o">!</span><span class="kt">void</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-3" name="__codelineno-59-3" href="#__codelineno-59-3"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">maxHeap</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="p">;</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-4" name="__codelineno-59-4" href="#__codelineno-59-4"></a><span class="w"> </span><span class="n">self</span><span class="p">.</span><span class="n">maxHeap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span><span class="p">.</span><span class="n">ArrayList</span><span class="p">(</span><span class="n">T</span><span class="p">).</span><span class="n">init</span><span class="p">(</span><span class="n">allocator</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-5" name="__codelineno-59-5" href="#__codelineno-59-5"></a><span class="w"> </span><span class="c1">// 将列表元素原封不动添加进堆</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-6" name="__codelineno-59-6" href="#__codelineno-59-6"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="n">self</span><span class="p">.</span><span class="n">maxHeap</span><span class="p">.</span><span class="o">?</span><span class="p">.</span><span class="n">appendSlice</span><span class="p">(</span><span class="n">nums</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-7" name="__codelineno-59-7" href="#__codelineno-59-7"></a><span class="w"> </span><span class="c1">// 堆化除叶结点以外的其他所有结点</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-8" name="__codelineno-59-8" href="#__codelineno-59-8"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">i</span><span class="o">:</span><span class="w"> </span><span class="kt">usize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parent</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-9" name="__codelineno-59-9" href="#__codelineno-59-9"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-10" name="__codelineno-59-10" href="#__codelineno-59-10"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="n">self</span><span class="p">.</span><span class="n">siftDown</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-11" name="__codelineno-59-11" href="#__codelineno-59-11"></a><span class="w"> </span><span class="p">}</span>
|
|
|
|
|
|
|
|
<a id="__codelineno-59-12" name="__codelineno-59-12" href="#__codelineno-59-12"></a><span class="p">}</span>
|
|
|
|
|
|
|
|
</code></pre></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<p>那么,第二种建堆方法的时间复杂度时多少呢?我们来做一下简单推算。</p>
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
|
|
<li>完全二叉树中,设结点总数为 <span class="arithmatex">\(n\)</span> ,则叶结点数量为 <span class="arithmatex">\((n + 1) / 2\)</span> ,其中 <span class="arithmatex">\(/\)</span> 为向下整除。因此在排除叶结点后,需要堆化结点数量为 <span class="arithmatex">\((n - 1)/2\)</span> ,即为 <span class="arithmatex">\(O(n)\)</span> ;</li>
|
|
|
|
|
|
|
|
<li>从顶至底堆化中,每个结点最多堆化至叶结点,因此最大迭代次数为二叉树高度 <span class="arithmatex">\(O(\log n)\)</span> ;</li>
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
<p>将上述两者相乘,可得时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。然而,该估算结果仍不够准确,因为我们没有考虑到 <strong>二叉树底层结点远多于顶层结点</strong> 的性质。</p>
|
|
|
|
|
|
|
|
<p>下面我们来尝试展开计算。为了减小计算难度,我们假设树是一个「完美二叉树」,该假设不会影响计算结果的正确性。设二叉树(即堆)结点数量为 <span class="arithmatex">\(n\)</span> ,树高度为 <span class="arithmatex">\(h\)</span> 。上文提到,<strong>结点堆化最大迭代次数等于该结点到叶结点的距离,而这正是“结点高度”</strong>。因此,我们将各层的“结点数量 <span class="arithmatex">\(\times\)</span> 结点高度”求和,即可得到所有结点的堆化的迭代次数总和。</p>
|
|
|
|
|
|
|
|
<div class="arithmatex">\[
|
|
|
|
|
|
|
|
T(h) = 2^0h + 2^1(h-1) + 2^2(h-2) + \cdots + 2^{(h-1)}\times1
|
|
|
|
|
|
|
|
\]</div>
|
|
|
|
|
|
|
|
<p><img alt="完美二叉树的各层结点数量" src="../heap.assets/heapify_operations_count.png" /></p>
|
|
|
|
|
|
|
|
<p align="center"> Fig. 完美二叉树的各层结点数量 </p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p>化简上式需要借助中学的数列知识,先对 <span class="arithmatex">\(T(h)\)</span> 乘以 <span class="arithmatex">\(2\)</span> ,易得</p>
|
|
|
|
|
|
|
|
<div class="arithmatex">\[
|
|
|
|
|
|
|
|
\begin{aligned}
|
|
|
|
|
|
|
|
T(h) & = 2^0h + 2^1(h-1) + 2^2(h-2) + \cdots + 2^{h-1}\times1 \newline
|
|
|
|
|
|
|
|
2 T(h) & = 2^1h + 2^2(h-1) + 2^3(h-2) + \cdots + 2^{h}\times1 \newline
|
|
|
|
|
|
|
|
\end{aligned}
|
|
|
|
|
|
|
|
\]</div>
|
|
|
|
|
|
|
|
<p><strong>使用错位相减法</strong>,令下式 <span class="arithmatex">\(2 T(h)\)</span> 减去上式 <span class="arithmatex">\(T(h)\)</span> ,可得</p>
|
|
|
|
|
|
|
|
<div class="arithmatex">\[
|
|
|
|
|
|
|
|
2T(h) - T(h) = T(h) = -2^0h + 2^1 + 2^2 + \cdots + 2^{h-1} + 2^h
|
|
|
|
|
|
|
|
\]</div>
|
|
|
|
|
|
|
|
<p>观察上式,<span class="arithmatex">\(T(h)\)</span> 是一个等比数列,可直接使用求和公式,得到时间复杂度为</p>
|
|
|
|
|
|
|
|
<div class="arithmatex">\[
|
|
|
|
|
|
|
|
\begin{aligned}
|
|
|
|
|
|
|
|
T(h) & = 2 \frac{1 - 2^h}{1 - 2} - h \newline
|
|
|
|
|
|
|
|
& = 2^{h+1} - h \newline
|
|
|
|
|
|
|
|
& = O(2^h)
|
|
|
|
|
|
|
|
\end{aligned}
|
|
|
|
|
|
|
|
\]</div>
|
|
|
|
|
|
|
|
<p>进一步地,高度为 <span class="arithmatex">\(h\)</span> 的完美二叉树的结点数量为 <span class="arithmatex">\(n = 2^{h+1} - 1\)</span> ,易得复杂度为 <span class="arithmatex">\(O(2^h) = O(n)\)</span>。以上推算表明,<strong>输入列表并建堆的时间复杂度为 <span class="arithmatex">\(O(n)\)</span> ,非常高效</strong>。</p>
|
|
|
|
|
|
|
|
<h2 id="814">8.1.4. 堆常见应用<a class="headerlink" href="#814" title="Permanent link">¶</a></h2>
|
|
|
|
<h2 id="814">8.1.4. 堆常见应用<a class="headerlink" href="#814" title="Permanent link">¶</a></h2>
|
|
|
|
<ul>
|
|
|
|
<ul>
|
|
|
|
<li><strong>优先队列</strong>。堆常作为实现优先队列的首选数据结构,入队和出队操作时间复杂度为 <span class="arithmatex">\(O(\log n)\)</span> ,建队操作为 <span class="arithmatex">\(O(n)\)</span> ,皆非常高效。</li>
|
|
|
|
<li><strong>优先队列</strong>。堆常作为实现优先队列的首选数据结构,入队和出队操作时间复杂度为 <span class="arithmatex">\(O(\log n)\)</span> ,建队操作为 <span class="arithmatex">\(O(n)\)</span> ,皆非常高效。</li>
|
|
|
@ -3138,13 +2983,13 @@ T(h) & = 2 \frac{1 - 2^h}{1 - 2} - h \newline
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<a href="../../chapter_graph/graph/" class="md-footer__link md-footer__link--next" aria-label="下一页: 9.1. &nbsp; 图(Graph)" rel="next">
|
|
|
|
<a href="../build_heap/" class="md-footer__link md-footer__link--next" aria-label="下一页: 8.2. &nbsp; 建堆操作 *" rel="next">
|
|
|
|
<div class="md-footer__title">
|
|
|
|
<div class="md-footer__title">
|
|
|
|
<div class="md-ellipsis">
|
|
|
|
<div class="md-ellipsis">
|
|
|
|
<span class="md-footer__direction">
|
|
|
|
<span class="md-footer__direction">
|
|
|
|
下一页
|
|
|
|
下一页
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
9.1. 图(Graph)
|
|
|
|
8.2. 建堆操作 *
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="md-footer__button md-icon">
|
|
|
|
<div class="md-footer__button md-icon">
|
|
|
|