mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 23:14:06 +08:00
52 lines
28 KiB
HTML
52 lines
28 KiB
HTML
<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"><=</span> <span class="pre">heap[2*k+1]</span></code> and <code class="docutils literal"><span class="pre">heap[k]</span> <span class="pre"><=</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">>>> </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">>>> </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">>>> </span><span class="n">h</span> <span class="o">=</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="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s1">'write code'</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="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="s1">'release product'</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="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'write spec'</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="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="s1">'create tests'</span><span class="p">))</span>
|
||
<span class="gp">>>> </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">'<removed-task>'</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"><=</span> <span class="pre">a[2*k+1]</span></code> and <code class="docutils literal"><span class="pre">a[k]</span> <span class="pre"><=</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">通过遍历所有项,你得到一个O(n 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> |