-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
41 lines (23 loc) · 6.75 KB
/
atom.xml
File metadata and controls
41 lines (23 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Chaojie's Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2020-07-13T08:53:22.463Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>Chaojie Lai</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>heapq源码解读</title>
<link href="http://yoursite.com/heapq%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/"/>
<id>http://yoursite.com/heapq%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/</id>
<published>2020-07-12T00:41:48.589Z</published>
<updated>2020-07-13T08:53:22.463Z</updated>
<content type="html"><![CDATA[<p>Python标准库 heapq 是一个实现了最小堆(Min Heap)的库。其对于堆实现最值得注意的是其中的 <code>_siftup </code> 函数。 <code>_siftup </code> 函数 在 <code>heappop</code>函数中调用,因此,本文将从<code>heappop</code>函数开始解析,而后再解析<code>_siftup </code> 函数。</p><p>以下是 <code>heappop</code> 的源码。 </p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">heappop</span><span class="params">(heap)</span>:</span></span><br><span class="line"> <span class="string">"""Pop the smallest item off the heap, maintaining the heap invariant."""</span></span><br><span class="line"> lastelt = heap.pop() <span class="comment"># raises appropriate IndexError if heap is empty</span></span><br><span class="line"> <span class="keyword">if</span> heap:</span><br><span class="line"> returnitem = heap[<span class="number">0</span>]</span><br><span class="line"> heap[<span class="number">0</span>] = lastelt</span><br><span class="line"> _siftup(heap, <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> returnitem</span><br><span class="line"> <span class="keyword">return</span> lastelt</span><br></pre></td></tr></table></figure><p>如代码注释里所说,<code>heappop</code> 的作用就是从堆中弹出最小元素,并调整剩余元素让其还是一个堆。<code>heappop</code>从 heap 弹出元素的过程为:用 <code>heap.pop()</code> 弹出heap中最末尾的元素并赋值给lastelt(heapq中的heap就是一个list,故<code>heap.pop()</code>就是 <code>list.pop()</code> ),然后将<code>heap[0]</code>赋值给returnitem,而后用 lastelt 覆写heap[0],调用<code>_siftup</code>进行调整。如图所示:<br><img src="heapq%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/%E5%9B%BE1.jpeg"></p><p><code>_siftup</code> 函数的作用是 从根节点开始一直向下调整堆,调整剩余元素使其成为一个堆。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_siftup</span><span class="params">(heap, pos)</span>:</span></span><br><span class="line"> endpos = len(heap)</span><br><span class="line"> startpos = pos</span><br><span class="line"> newitem = heap[pos]</span><br><span class="line"> <span class="comment"># Bubble up the smaller child until hitting a leaf.</span></span><br><span class="line"> childpos = <span class="number">2</span>*pos + <span class="number">1</span> <span class="comment"># leftmost child position</span></span><br><span class="line"> <span class="keyword">while</span> childpos < endpos:</span><br><span class="line"> <span class="comment"># Set childpos to index of smaller child.</span></span><br><span class="line"> rightpos = childpos + <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> rightpos < endpos <span class="keyword">and</span> <span class="keyword">not</span> heap[childpos] < heap[rightpos]:</span><br><span class="line"> childpos = rightpos</span><br><span class="line"> <span class="comment"># Move the smaller child up.</span></span><br><span class="line"> heap[pos] = heap[childpos]</span><br><span class="line"> pos = childpos</span><br><span class="line"> childpos = <span class="number">2</span>*pos + <span class="number">1</span></span><br><span class="line"> <span class="comment"># The leaf at pos is empty now. Put newitem there, and bubble it up</span></span><br><span class="line"> <span class="comment"># to its final resting place (by sifting its parents down).</span></span><br><span class="line"> heap[pos] = newitem</span><br><span class="line"> _siftdown(heap, startpos, pos)</span><br></pre></td></tr></table></figure><p><code>_siftup</code> 函数 与很多书籍提及的调整方法是不同的。</p><p>本文所说的堆、Heap 默认是最小堆,即<code>a[0]</code>是堆中的最小元素。</p><p>关于什么是最小堆,heapq 源码中的解释相当简洁明了:</p><blockquote><p>Heaps are arrays for which a[k] <= a[2<em>k+1] and a[k] <= a[2</em>k+2] for<br>all k, counting elements from 0. For the sake of comparison,<br>non-existing elements are considered to be infinite. The interesting<br>property of a heap is that a[0] is always its smallest element.<br><a href="https://github.com/python/cpython/tree/3.8/Lib/heapq.py" target="_blank" rel="noopener">https://github.com/python/cpython/tree/3.8/Lib/heapq.py</a></p></blockquote>]]></content>
<summary type="html">
<p>Python标准库 heapq 是一个实现了最小堆(Min Heap)的库。其对于堆实现最值得注意的是其中的 <code>_siftup </code> 函数。 <code>_siftup </code> 函数 在 <code>heappop</code>函数中调用,因此,
</summary>
</entry>
</feed>