2019-04-21 11:50:48 +08:00

52 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="body" role="main"><div class="section" id="module-heapq"><h1><span class="yiyi-st" id="yiyi-10">8.5. <a class="reference internal" href="#module-heapq" title="heapq: Heap queue algorithm (a.k.a. priority queue)."><code class="xref py py-mod docutils literal"><span class="pre">heapq</span></code></a> - 堆队列算法</span></h1><p><span class="yiyi-st" id="yiyi-11"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/heapq.py">Lib / heapq.py</a></span></p><p><span class="yiyi-st" id="yiyi-12">该模块提供了堆队列算法的实现,也称为优先级队列算法。</span></p><p><span class="yiyi-st" id="yiyi-13">堆是二叉树,每个父节点的值小于或等于其任何子节点。</span><span class="yiyi-st" id="yiyi-14">这个实现的数组基于以下特点:<code class="docutils literal"><span class="pre">heap[k]</span> <span class="pre">&lt;=</span> <span class="pre">heap[2*k+1]</span></code> and <code class="docutils literal"><span class="pre">heap[k]</span> <span class="pre">&lt;=</span> <span class="pre">heap[2*k+2]</span></code> 对于所有的 <em>k</em>, 从零开始计数 。</span><span class="yiyi-st" id="yiyi-15">为了比较,不存在的元素被认为是无限的。</span><span class="yiyi-st" id="yiyi-16">堆的有趣的属性是它的最小元素总是根,<code class="docutils literal"><span class="pre">heap [0]</span></code></span></p><p><span class="yiyi-st" id="yiyi-17">下面的API与教科书堆算法在两个方面不同a我们使用基于零的索引。</span><span class="yiyi-st" id="yiyi-18">这使得节点的索引和其子节点的索引之间的关系稍微不那么明显但是更合适因为Python使用基于零的索引。</span><span class="yiyi-st" id="yiyi-19">b我们的pop方法返回最小的项而不是最大的在教科书中称为“最小堆”因为它适合于就地排序所以“最大堆”在文本中更常见</span></p><p><span class="yiyi-st" id="yiyi-20">这两个使得可以将堆视为正常的Python列表而没有惊喜<code class="docutils literal"><span class="pre">heap [0]</span></code>是最小的项,<code class="docutils literal"><span class="pre">heap.sort()</span></code>维持堆不变!</span></p><p><span class="yiyi-st" id="yiyi-21">要创建堆,请使用初始化为<code class="docutils literal"><span class="pre">[]</span></code>的列表,或者您可以通过函数<a class="reference internal" href="#heapq.heapify" title="heapq.heapify"><code class="xref py py-func docutils literal"><span class="pre">heapify()</span></code></a>将填充列表转换为堆。</span></p><p><span class="yiyi-st" id="yiyi-22">提供以下功能:</span></p><dl class="function"><dt id="heapq.heappush"><span class="yiyi-st" id="yiyi-23"><code class="descclassname">heapq.</code><code class="descname">heappush</code><span class="sig-paren">(</span><em>heap</em>, <em>item</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-24">将值<em>item</em>推到<em>heap</em>上,保持堆不变。</span></p></dd></dl><dl class="function"><dt id="heapq.heappop"><span class="yiyi-st" id="yiyi-25"><code class="descclassname">heapq.</code><code class="descname">heappop</code><span class="sig-paren">(</span><em>heap</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-26"><em>heap</em>中弹出并返回最小的项,保持堆不变。</span><span class="yiyi-st" id="yiyi-27">如果堆为空,则会引发<a class="reference internal" href="exceptions.html#IndexError" title="IndexError"><code class="xref py py-exc docutils literal"><span class="pre">IndexError</span></code></a></span><span class="yiyi-st" id="yiyi-28">要访问最小的项,不需要弹出它,请使用<code class="docutils literal"><span class="pre">heap [0]</span></code></span></p></dd></dl><dl class="function"><dt id="heapq.heappushpop"><span class="yiyi-st" id="yiyi-29"><code class="descclassname">heapq.</code><code class="descname">heappushpop</code><span class="sig-paren">(</span><em>heap</em>, <em>item</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-30">在堆上按<em></em>,然后弹出并返回<em></em>中的最小项。</span><span class="yiyi-st" id="yiyi-31">组合操作比<a class="reference internal" href="#heapq.heappush" title="heapq.heappush"><code class="xref py py-func docutils literal"><span class="pre">heappush()</span></code></a>运行更有效,随后单独调用<a class="reference internal" href="#heapq.heappop" title="heapq.heappop"><code class="xref py py-func docutils literal"><span class="pre">heappop()</span></code></a></span></p></dd></dl><dl class="function"><dt id="heapq.heapify"><span class="yiyi-st" id="yiyi-32"><code class="descclassname">heapq.</code><code class="descname">heapify</code><span class="sig-paren">(</span><em>x</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-33">在线性时间内,将列表<em>x</em>放入堆中。</span></p></dd></dl><dl class="function"><dt id="heapq.heapreplace"><span class="yiyi-st" id="yiyi-34"><code class="descclassname">heapq.</code><code class="descname">heapreplace</code><span class="sig-paren">(</span><em>heap</em>, <em>item</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-35"><em></em>中弹出并返回最小的项,并推送新的<em></em></span><span class="yiyi-st" id="yiyi-36">堆大小不变。</span><span class="yiyi-st" id="yiyi-37">如果堆为空,则会引发<a class="reference internal" href="exceptions.html#IndexError" title="IndexError"><code class="xref py py-exc docutils literal"><span class="pre">IndexError</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-38">这一步操作比<a class="reference internal" href="#heapq.heappop" title="heapq.heappop"><code class="xref py py-func docutils literal"><span class="pre">heappop()</span></code></a><a class="reference internal" href="#heapq.heappush" title="heapq.heappush"><code class="xref py py-func docutils literal"><span class="pre">heappush()</span></code></a>更有效,并且在使用固定大小的堆时可能更合适。</span><span class="yiyi-st" id="yiyi-39">pop / push组合总是从堆中返回一个元素并用<em>item</em>替换它。</span></p><p><span class="yiyi-st" id="yiyi-40">返回的值可能大于添加的<em></em></span><span class="yiyi-st" id="yiyi-41">如果不需要,请考虑使用<a class="reference internal" href="#heapq.heappushpop" title="heapq.heappushpop"><code class="xref py py-func docutils literal"><span class="pre">heappushpop()</span></code></a></span><span class="yiyi-st" id="yiyi-42">它的push / pop组合返回两个值中的较小值在堆上留下较大的值。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-43">该模块还提供了基于堆的三个通用功能。</span></p><dl class="function"><dt id="heapq.merge"><span class="yiyi-st" id="yiyi-44"><code class="descclassname">heapq.</code><code class="descname">merge</code><span class="sig-paren">(</span><em>*iterables</em>, <em>key=None</em>, <em>reverse=False</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-45">将多个排序的输入合并到单个排序的输出(例如,合并来自多个日志文件的带时间戳的条目)。</span><span class="yiyi-st" id="yiyi-46">在排序后的值上返回<a class="reference internal" href="../glossary.html#term-iterator"><span class="xref std std-term">iterator</span></a></span></p><p><span class="yiyi-st" id="yiyi-47"><code class="docutils literal"><span class="pre">sorted(itertools.chain(*iterables))</span></code>类似,但返回一个可迭代,不会一次将数据拉入内存,并假设每个输入流已经排序(最小到最大)。</span></p><p><span class="yiyi-st" id="yiyi-48">有两个可选参数,必须指定为关键字参数。</span></p><p><span class="yiyi-st" id="yiyi-49"><em></em>指定一个参数的<a class="reference internal" href="../glossary.html#term-key-function"><span class="xref std std-term">key function</span></a>,用于从每个输入元素提取比较键。</span><span class="yiyi-st" id="yiyi-50">默认值为<code class="docutils literal"><span class="pre">None</span></code>(直接比较元素)。</span></p><p><span class="yiyi-st" id="yiyi-51"><em>reverse</em>是一个布尔值。</span><span class="yiyi-st" id="yiyi-52">如果设置为<code class="docutils literal"><span class="pre">True</span></code>,则输入元素将合并,如同每次比较都反转一样。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-53"><span class="versionmodified">在3.5版中已更改:</span>添加了可选的<em></em><em>反向</em>参数。</span></p></div></dd></dl><dl class="function"><dt id="heapq.nlargest"><span class="yiyi-st" id="yiyi-54"> <code class="descclassname">heapq.</code><code class="descname">nlargest</code><span class="sig-paren">(</span><em>n</em>, <em>iterable</em>, <em>key=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-55">返回<em>可迭代</em>定义的数据集中<em>n</em>最大元素的列表。</span><span class="yiyi-st" id="yiyi-56"><em>key</em>,如果提供,则指定一个参数的函数,用于从迭代器中的每个元素中提取比较键。<code class="docutils literal"><span class="pre">key=str.lower</span></code>等同于:<code class="docutils literal"> <span class="pre">排序(可迭代,</span> <span class="pre">key = key</span> <span class="pre">reverse = True[n]</span></code></span></p></dd></dl><dl class="function"><dt id="heapq.nsmallest"><span class="yiyi-st" id="yiyi-57"> <code class="descclassname">heapq.</code><code class="descname">nsmallest</code><span class="sig-paren">(</span><em>n</em>, <em>iterable</em>, <em>key=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-58">返回<em>可迭代</em>定义的数据集中<em>n</em>最小元素的列表。</span><span class="yiyi-st" id="yiyi-59"><em>key</em>,如果提供,则指定一个参数的函数,用于从迭代器中的每个元素中提取比较键。<code class="docutils literal"><span class="pre">key=str.lower</span></code>等同于:<code class="docutils literal"> <span class="pre">排序(可迭代,</span> <span class="pre">键=键)[n]</span></code></span></p></dd></dl><p><span class="yiyi-st" id="yiyi-60">后两个函数对于较小的<em>n</em>值表现最好。对于较大的值,使用<a class="reference internal" href="functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal"><span class="pre">sorted()</span></code></a>函数更为有效。</span><span class="yiyi-st" id="yiyi-61">此外,当<code class="docutils literal"><span class="pre">n==1</span></code>时,使用内建<a class="reference internal" href="functions.html#min" title="min"><code class="xref py py-func docutils literal"><span class="pre">min()</span></code></a><a class="reference internal" href="functions.html#max" title="max"><code class="xref py py-func docutils literal"><span class="pre">max()</span></code></a>函数更为有效。</span><span class="yiyi-st" id="yiyi-62">如果需要重复使用这些函数请考虑将iterable转换为实际堆。</span></p><div class="section" id="basic-examples"><h2><span class="yiyi-st" id="yiyi-63">8.5.1.</span><span class="yiyi-st" id="yiyi-64">基本示例</span></h2><p><span class="yiyi-st" id="yiyi-65">可以通过将所有值推送到堆上,然后一次一个地弹出最小值来实现<a class="reference external" href="https://en.wikipedia.org/wiki/Heapsort">堆栈</a></span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">heapsort</span><span class="p">(</span><span class="n">iterable</span><span class="p">):</span>
<span class="gp">... </span> <span class="n">h</span> <span class="o">=</span> <span class="p">[]</span>
<span class="gp">... </span> <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">:</span>
<span class="gp">... </span> <span class="n">heappush</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">return</span> <span class="p">[</span><span class="n">heappop</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <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="nb">len</span><span class="p">(</span><span class="n">h</span><span class="p">))]</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">heapsort</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
<span class="go">[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</span>
</code></pre><p><span class="yiyi-st" id="yiyi-66">这类似于<code class="docutils literal"><span class="pre">sorted(iterable)</span></code>,但与<a class="reference internal" href="functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal"><span class="pre">sorted()</span></code></a>不同,此实现不稳定。</span></p><p><span class="yiyi-st" id="yiyi-67">堆元素可以是元组。</span><span class="yiyi-st" id="yiyi-68">这对于在正在跟踪的主记录旁边分配比较值(例如任务优先级)很有用:</span></p><pre><code class="language-python"><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">h</span> <span class="o">=</span> <span class="p">[]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">heappush</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s1">'write code'</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">heappush</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="s1">'release product'</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">heappush</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'write spec'</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">heappush</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="s1">'create tests'</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">heappop</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
<span class="go">(1, 'write spec')</span>
</code></pre></div><div class="section" id="priority-queue-implementation-notes"><h2><span class="yiyi-st" id="yiyi-69">8.5.2.</span><span class="yiyi-st" id="yiyi-70">优先级队列实现注释</span></h2><p><span class="yiyi-st" id="yiyi-71"><a class="reference external" href="https://en.wikipedia.org/wiki/Priority_queue">优先级队列</a>通常用于堆,并且它提出了几个实现挑战:</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-72">排序稳定性:如何使两个具有相同优先级的任务按照它们最初添加的顺序返回?</span></li><li><span class="yiyi-st" id="yiyi-73">如果优先级相等且任务没有默认比较顺序,则(优先级,任务)对的元组比较中断。</span></li><li><span class="yiyi-st" id="yiyi-74">如果任务的优先级改变,你如何将它移动到堆中的新位置?</span></li><li><span class="yiyi-st" id="yiyi-75">或者,如果一个挂起的任务需要被删除,你如何找到它并将其从队列中删除?</span></li></ul><p><span class="yiyi-st" id="yiyi-76">前两个挑战的解决方案是将条目存储为包括优先级条目计数和任务的3元素列表。</span><span class="yiyi-st" id="yiyi-77">条目计数用作tie-breaker以便按照添加的顺序返回具有相同优先级的两个任务。</span><span class="yiyi-st" id="yiyi-78">由于没有两个条目计数是相同的,元组比较将永远不会尝试直接比较两个任务。</span></p><p><span class="yiyi-st" id="yiyi-79">其余的挑战包括找到一个待完成的任务,改变其优先级或完全删除它。</span><span class="yiyi-st" id="yiyi-80">可以使用指向队列中的条目的字典来完成查找任务。</span></p><p><span class="yiyi-st" id="yiyi-81">删除条目或更改其优先级更加困难,因为它会破坏堆结构不变式。</span><span class="yiyi-st" id="yiyi-82">因此,一个可能的解决方案是将该条目标记为已删除,并添加具有修改的优先级的新条目:</span></p><pre><code class="language-python"><span></span><span class="n">pq</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># list of entries arranged in a heap</span>
<span class="n">entry_finder</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># mapping of tasks to entries</span>
<span class="n">REMOVED</span> <span class="o">=</span> <span class="s1">'&lt;removed-task&gt;'</span> <span class="c1"># placeholder for a removed task</span>
<span class="n">counter</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">()</span> <span class="c1"># unique sequence count</span>
<span class="k">def</span> <span class="nf">add_task</span><span class="p">(</span><span class="n">task</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="s1">'Add a new task or update the priority of an existing task'</span>
<span class="k">if</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">entry_finder</span><span class="p">:</span>
<span class="n">remove_task</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
<span class="n">count</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">counter</span><span class="p">)</span>
<span class="n">entry</span> <span class="o">=</span> <span class="p">[</span><span class="n">priority</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">task</span><span class="p">]</span>
<span class="n">entry_finder</span><span class="p">[</span><span class="n">task</span><span class="p">]</span> <span class="o">=</span> <span class="n">entry</span>
<span class="n">heappush</span><span class="p">(</span><span class="n">pq</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">remove_task</span><span class="p">(</span><span class="n">task</span><span class="p">):</span>
<span class="s1">'Mark an existing task as REMOVED. Raise KeyError if not found.'</span>
<span class="n">entry</span> <span class="o">=</span> <span class="n">entry_finder</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
<span class="n">entry</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">REMOVED</span>
<span class="k">def</span> <span class="nf">pop_task</span><span class="p">():</span>
<span class="s1">'Remove and return the lowest priority task. Raise KeyError if empty.'</span>
<span class="k">while</span> <span class="n">pq</span><span class="p">:</span>
<span class="n">priority</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">task</span> <span class="o">=</span> <span class="n">heappop</span><span class="p">(</span><span class="n">pq</span><span class="p">)</span>
<span class="k">if</span> <span class="n">task</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">REMOVED</span><span class="p">:</span>
<span class="k">del</span> <span class="n">entry_finder</span><span class="p">[</span><span class="n">task</span><span class="p">]</span>
<span class="k">return</span> <span class="n">task</span>
<span class="k">raise</span> <span class="ne">KeyError</span><span class="p">(</span><span class="s1">'pop from an empty priority queue'</span><span class="p">)</span>
</code></pre></div><div class="section" id="theory"><h2><span class="yiyi-st" id="yiyi-83">8.5.3.</span><span class="yiyi-st" id="yiyi-84">理论</span></h2><p><span class="yiyi-st" id="yiyi-85">Heaps are arrays for which <code class="docutils literal"><span class="pre">a[k]</span> <span class="pre">&lt;=</span> <span class="pre">a[2*k+1]</span></code> and <code class="docutils literal"><span class="pre">a[k]</span> <span class="pre">&lt;=</span> <span class="pre">a[2*k+2]</span></code> for all <em>k</em>, counting elements from 0. </span><span class="yiyi-st" id="yiyi-86">为了比较,不存在的元素被认为是无限的。</span><span class="yiyi-st" id="yiyi-87">堆的有趣属性是<code class="docutils literal"><span class="pre">a[0]</span></code>始终是其最小的元素。</span></p><p><span class="yiyi-st" id="yiyi-88">上面奇怪的不变式意味着是一个有效的内存表示为比赛。</span><span class="yiyi-st" id="yiyi-89">下面的数字是<em>k</em>,而不是<code class="docutils literal"><span class="pre">a[k]</span></code></span></p><pre><code class="language-python"><span></span> <span class="mi">0</span>
<span class="mi">1</span> <span class="mi">2</span>
<span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span> <span class="mi">6</span>
<span class="mi">7</span> <span class="mi">8</span> <span class="mi">9</span> <span class="mi">10</span> <span class="mi">11</span> <span class="mi">12</span> <span class="mi">13</span> <span class="mi">14</span>
<span class="mi">15</span> <span class="mi">16</span> <span class="mi">17</span> <span class="mi">18</span> <span class="mi">19</span> <span class="mi">20</span> <span class="mi">21</span> <span class="mi">22</span> <span class="mi">23</span> <span class="mi">24</span> <span class="mi">25</span> <span class="mi">26</span> <span class="mi">27</span> <span class="mi">28</span> <span class="mi">29</span> <span class="mi">30</span>
</code></pre><p><span class="yiyi-st" id="yiyi-90">在上面的树中,每个单元<em>k</em>顶在<code class="docutils literal"><span class="pre">2*k+1</span></code><code class="docutils literal"><span class="pre">2*k+2</span></code></span><span class="yiyi-st" id="yiyi-91">在一个通常的二进制比赛,我们看到在体育,每个单元格是两个单元格的冠军,它顶部,我们可以跟踪赢家在树上查看所有的对手/他有。</span><span class="yiyi-st" id="yiyi-92">然而,在这样的比赛的许多计算机应用中,我们不需要追踪获胜者的历史。</span><span class="yiyi-st" id="yiyi-93">为了提高内存的效率,当一个优胜者被提升时,我们尝试用更低级别的其他东西取代它,规则变成一个单元格和它上面的两个单元格包含三个不同的项目,但顶部单元格“胜利”在两个顶端的细胞。</span></p><p><span class="yiyi-st" id="yiyi-94">如果这个堆不变量在任何时候都受到保护索引0显然是总赢家。</span><span class="yiyi-st" id="yiyi-95">去除它并找到“下一个”获胜者的最简单的算法方法是将一些失败者让我们说上面的图中的单元格30移动到0位置然后沿着树来渗透这个新的0交换值直到不变量重新建立。</span><span class="yiyi-st" id="yiyi-96">这显然是对树中项目总数的对数。</span><span class="yiyi-st" id="yiyi-97">通过遍历所有项你得到一个On log n排序。</span></p><p><span class="yiyi-st" id="yiyi-98">这种类型的一个很好的功能是你可以有效地插入新的项目而排序进行只要插入的项目不比你提取的最后第0个元素“更好”。</span><span class="yiyi-st" id="yiyi-99">这在模拟上下文中尤其有用,其中树保存所有传入的事件,并且“赢”条件意味着最小的调度时间。</span><span class="yiyi-st" id="yiyi-100">当事件计划其他事件以供执行时,它们将被调度到将来,以便他们可以轻松地进入堆。</span><span class="yiyi-st" id="yiyi-101">所以堆是一个很好的结构实现调度器这是我用于我的MIDI音序器:-)。</span></p><p><span class="yiyi-st" id="yiyi-102">已经广泛地研究了用于实现调度器的各种结构,并且堆是有益的,因为它们合理地快,速度几乎恒定,并且最坏情况与平均情况没有太多不同。</span><span class="yiyi-st" id="yiyi-103">然而,有其他表示,整体更有效,但最坏的情况可能是可怕的。</span></p><p><span class="yiyi-st" id="yiyi-104">堆在大磁盘排序中也非常有用。</span><span class="yiyi-st" id="yiyi-105">你很可能都知道一个大排序意味着生成“运行”它是预排序的序列其大小通常与CPU内存量相关然后是这些运行的合并遍这些合并通常非常巧妙组织了<a class="footnote-reference" href="#id2" id="id1">[1]</a></span><span class="yiyi-st" id="yiyi-106">非常重要的是,初始排序产生尽可能长的运行。</span><span class="yiyi-st" id="yiyi-107">比赛是一个很好的方式来实现。</span><span class="yiyi-st" id="yiyi-108">如果使用所有可用的内存来举办锦标赛,你可以替换和渗透到适合当前运行的项目,你会产生的运行是随机输入的内存大小的两倍,对输入进行模糊排序会更好。</span></p><p><span class="yiyi-st" id="yiyi-109">此外如果您输出磁盘上的第0项并获得一个可能不适合当前比赛的输入因为值“胜过”最后一个输出值它不能适合堆所以大小堆减少。</span><span class="yiyi-st" id="yiyi-110">释放的内存可以立即被巧妙地重用,用于逐步构建第二个堆,它以与第一个堆融化的速率完全相同的速度增长。</span><span class="yiyi-st" id="yiyi-111">当第一个堆完全消失时,您切换堆并开始新的运行。</span><span class="yiyi-st" id="yiyi-112">聪明而相当有效!</span></p><p><span class="yiyi-st" id="yiyi-113">总之,堆是有用的内存结构要知道。</span><span class="yiyi-st" id="yiyi-114">我在几个应用程序中使用它们,我认为保存一个'heap'模块是很好的。</span><span class="yiyi-st" id="yiyi-115">:-)</span></p><p class="rubric"><span class="yiyi-st" id="yiyi-116">脚注</span></p><table class="docutils footnote" frame="void" id="id2" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-117"><a class="fn-backref" href="#id1">[1]</a></span></td><td><span class="yiyi-st" id="yiyi-118">当今的磁盘平衡算法比现在更烦人,这是磁盘搜索能力的结果。</span><span class="yiyi-st" id="yiyi-119">在不能寻找的设备,如大磁带驱动器,故事是完全不同的,一个人必须非常聪明,以确保(提前)每个磁带运动将是最有效的可能(也就是说,最好参与“进行“合并)。</span><span class="yiyi-st" id="yiyi-120">一些磁带甚至能够向后读,这也用于避免重绕时间。</span><span class="yiyi-st" id="yiyi-121">相信我,真正好的磁带类别是相当壮观的看!</span><span class="yiyi-st" id="yiyi-122">从任何时候,排序一直是一个伟大的艺术!</span><span class="yiyi-st" id="yiyi-123">:-)</span></td></tr></tbody></table></div></div></div>