🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# SplHeap(堆) # [SplHeap](https://www.php.net/manual/zh/class.splheap.php#class.splheap) ### [堆原理](%5Bhttps://www.jianshu.com/p/6b526aa481b1%5D(https://www.jianshu.com/p/6b526aa481b1)) > 堆(Heap)就是为了实现优先队列而设计的一种数据结构,它是通过构造二叉堆(二叉树的一种)实现。根节点最大的堆叫做最大堆或大根堆(SplMaxHeap),根节点最小的堆叫做最小堆或小根堆(SplMinHeap)。二叉堆还常用于排序(堆排序) > extract 出队更为友好,即始终返回优先级最高的元素,优先级相投时会以堆调整的特性返回数据 > 注意,因为是`堆`实现,所以`rewind`方法是一个`no-op`没有什作用的操作,因为`头指针`始终指向`堆顶`,即`current`始终等于`top`,不像`List`只是游走指针,出队是会删除堆元素的,`extract`=`current + next`(current出队,从堆中删除) 节点与它的父节点和子节点在数组中的位置关系: 公式: ``` <pre class="calibre10">``` <span class="token4">parent</span><span class="token3">(</span>index<span class="token3">)</span> <span class="token1">=</span> <span class="token4">floor</span><span class="token3">(</span><span class="token3">(</span>index <span class="token1">-</span> <span class="token6">1</span><span class="token3">)</span><span class="token1">/</span><span class="token6">2</span><span class="token3">)</span> <span class="token4">left</span><span class="token3">(</span>index<span class="token3">)</span> <span class="token1">=</span> <span class="token6">2</span>index <span class="token1">+</span> <span class="token6">1</span> <span class="token4">right</span><span class="token3">(</span>index<span class="token3">)</span> <span class="token1">=</span> <span class="token6">2</span>index <span class="token1">+</span> <span class="token6">2</span> ``` ``` 如:`[ 10, 14, 25, 33, 81, 82, 99 ]` > 元素个数为7 so下面索引<=6才有子节点 > 所以 33, 81, 82, 99 无子节点 Node`index`Parent indexLeft childRight child100-1(不是有效索引so无父节点)1214103425205633317881419108252111299621314![](https://i.vgy.me/n7RdzD.png) ``` <pre class="calibre10">``` abstract SplHeap implements <span class="token4">Iterator</span> <span class="token3">,</span> Countable <span class="token3">{</span> <span class="token">/* 方法 */</span> public __construct <span class="token3">(</span> void <span class="token3">)</span> abstract protected compare <span class="token3">(</span> mixed $value1 <span class="token3">,</span> mixed $value2 <span class="token3">)</span> <span class="token3">:</span> int <span class="token">//比较元素,以便在筛选时将它们正确地放在堆中,如果value1大于value2则为正整数,如果相等则为0,否则为负整数</span> public count <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> int <span class="token">//返回元素的个数 Countable </span> public current <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> mixed <span class="token">//返回当前记录节点索引的值 超出范围返回空 Iterator</span> public extract <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> mixed <span class="token">//从堆顶部提取节点并进行筛选</span> public insert <span class="token3">(</span> mixed $value <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//通过筛选将一个元素插入堆中</span> public isCorrupted <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> bool <span class="token">//判断堆是否处于损坏状态</span> public isEmpty <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> bool <span class="token">//检查堆是否为空</span> public key <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> mixed <span class="token">//返回当前节点索引 Iterator</span> public next <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//移动到下一个节点 Iterator</span> public recoverFromCorruption <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//从损坏的状态恢复并允许堆上的进一步操作</span> public rewind <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//将指针指向迭代开始处 Iterator</span> public top <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> mixed <span class="token">//返回堆顶部的节点</span> public valid <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> bool <span class="token">//检查堆是否还有节点 Iterator</span> <span class="token3">}</span> ``` ``` ## **例子:** ``` <pre class="calibre10">``` <span class="token">//堆</span> class <span class="token4">CustomSplHeap</span> extends <span class="token4">SplHeap</span><span class="token3">{</span> <span class="token">//compare()方法用来比较两个元素的大小,绝对他们在堆中的位置</span> public <span class="token5">function</span> <span class="token4">compare</span><span class="token3">(</span> $value1<span class="token3">,</span> $value2 <span class="token3">)</span> <span class="token3">{</span> <span class="token">//return ( $value2 - $value1)</span> <span class="token5">return</span> <span class="token3">(</span> $value1 <span class="token1">-</span> $value2 <span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> $splHeap <span class="token1">=</span> <span class="token5">new</span> <span class="token4">CustomSplHeap</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">10</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">14</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">25</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">33</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">81</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">82</span><span class="token3">)</span><span class="token3">;</span> $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span><span class="token6">99</span><span class="token3">)</span><span class="token3">;</span> <span class="token4">print_r</span><span class="token3">(</span>$splHeap<span class="token3">)</span><span class="token3">;</span> echo<span class="token2">'@@@@@<br>'</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">key</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//6</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//99</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">count</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//7</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">next</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">key</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//5</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//82</span> <span class="token">//返回堆顶部的节点</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">top</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//82</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">rewind</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">count</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//6</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">key</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//5</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//82</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">extract</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//82</span> echo<span class="token2">'@@@@@<br>'</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">isCorrupted</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">isEmpty</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//</span> echo<span class="token2">'@@@@@<br>'</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">key</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//4</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//81</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">next</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">key</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//3</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//33</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">extract</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//33</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">key</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//2</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//25</span> echo<span class="token2">'@@@@@<br>'</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">rewind</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> echo $splHeap<span class="token1">-</span><span class="token1">></span><span class="token4">top</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span><span class="token">//33</span> echo<span class="token2">'@@@@@<br>'</span><span class="token3">;</span> foreach <span class="token3">(</span>$splHeap as $item<span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">'<br>'</span><span class="token3">.</span>$item<span class="token3">;</span><span class="token">//25 14 10</span> <span class="token3">}</span> ``` ``` ``` <pre class="calibre17">``` <span class="token1"><</span><span class="token1">?</span>php class <span class="token4">JupilerLeague</span> extends <span class="token4">SplHeap</span> <span class="token3">{</span> <span class="token">/** * We modify the abstract method compare so we can sort our * rankings using the values of a given array */</span> public <span class="token5">function</span> <span class="token4">compare</span><span class="token3">(</span>$array1<span class="token3">,</span> $array2<span class="token3">)</span> <span class="token3">{</span> $values1 <span class="token1">=</span> <span class="token4">array_values</span><span class="token3">(</span>$array1<span class="token3">)</span><span class="token3">;</span> $values2 <span class="token1">=</span> <span class="token4">array_values</span><span class="token3">(</span>$array2<span class="token3">)</span><span class="token3">;</span> <span class="token5">if</span> <span class="token3">(</span>$values1<span class="token3">[</span><span class="token6">0</span><span class="token3">]</span> <span class="token1">===</span> $values2<span class="token3">[</span><span class="token6">0</span><span class="token3">]</span><span class="token3">)</span> <span class="token5">return</span> <span class="token6">0</span><span class="token3">;</span> <span class="token5">return</span> $values1<span class="token3">[</span><span class="token6">0</span><span class="token3">]</span> <span class="token1"><</span> $values2<span class="token3">[</span><span class="token6">0</span><span class="token3">]</span> <span class="token1">?</span> <span class="token1">-</span><span class="token6">1</span> <span class="token3">:</span> <span class="token6">1</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">// Let's populate our heap here (data of 2009)</span> $heap <span class="token1">=</span> <span class="token5">new</span> <span class="token4">JupilerLeague</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'AA Gent'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">15</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Anderlecht'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">20</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Cercle Brugge'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">11</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Charleroi'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">12</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Club Brugge'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">21</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'G. Beerschot'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">15</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Kortrijk'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">10</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'KV Mechelen'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">18</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Lokeren'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">10</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Moeskroen'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">7</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Racing Genk'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">11</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Roeselare'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">6</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Standard'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">20</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'STVV'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">17</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Westerlo'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">10</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">insert</span><span class="token3">(</span>array <span class="token3">(</span><span class="token2">'Zulte Waregem'</span> <span class="token1">=</span><span class="token1">></span> <span class="token6">15</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> <span class="token">// For displaying the ranking we move up to the first node</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">top</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">// Then we iterate through each node for displaying the result</span> <span class="token5">while</span> <span class="token3">(</span>$heap<span class="token1">-</span><span class="token1">></span><span class="token4">valid</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span> <span class="token3">{</span> <span class="token">//var_dump($heap->current());</span> foreach <span class="token3">(</span>$heap<span class="token1">-</span><span class="token1">></span><span class="token4">current</span><span class="token3">(</span><span class="token3">)</span> as $key <span class="token1">=</span><span class="token1">></span> $value<span class="token3">)</span> <span class="token3">{</span> $team<span class="token1">=</span>$key<span class="token3">;</span> $score<span class="token1">=</span>$value<span class="token3">;</span> <span class="token3">}</span> echo $team <span class="token3">.</span> <span class="token2">': '</span> <span class="token3">.</span> $score <span class="token3">.</span><span class="token2">'<br>'</span><span class="token3">.</span> PHP_EOL<span class="token3">;</span> $heap<span class="token1">-</span><span class="token1">></span><span class="token4">next</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> 结果: Club Brugge<span class="token3">:</span> <span class="token6">21</span> Anderlecht<span class="token3">:</span> <span class="token6">20</span> Standard<span class="token3">:</span> <span class="token6">20</span> KV Mechelen<span class="token3">:</span> <span class="token6">18</span> STVV<span class="token3">:</span> <span class="token6">17</span> Zulte Waregem<span class="token3">:</span> <span class="token6">15</span> AA Gent<span class="token3">:</span> <span class="token6">15</span> G<span class="token3">.</span> Beerschot<span class="token3">:</span> <span class="token6">15</span> Charleroi<span class="token3">:</span> <span class="token6">12</span> Racing Genk<span class="token3">:</span> <span class="token6">11</span> Cercle Brugge<span class="token3">:</span> <span class="token6">11</span> Kortrijk<span class="token3">:</span> <span class="token6">10</span> Lokeren<span class="token3">:</span> <span class="token6">10</span> Westerlo<span class="token3">:</span> <span class="token6">10</span> Moeskroen<span class="token3">:</span> <span class="token6">7</span> Roeselare<span class="token3">:</span> <span class="token6">6</span> ``` ```