1. 程式人生 > >基於雙端堆實現的優先順序佇列(2):內幕

基於雙端堆實現的優先順序佇列(2):內幕

   在《基於雙端堆實現的優先順序佇列(1):原理》一文中講述了雙端堆的相關原理,本文則詳細講述具體的內部實現,便於區分,內部函式名稱都以雙下劃線作為字首,在這裡,有幾個關鍵問題需要說明
   1)怎麼求一個結點的對稱結點:如果完全二叉樹根結點從索引1開始但不儲存元素,那麼最小堆根結點則在索引2,最大堆根結點則在索引3,4和5為2的左右孩子,6和7為3的左右孩子,依次排下來,可以發現2(00000010)^1(00000001)=3(000000011),3(00000011)^1(00000001)=2,4(00000100)^2(00000010)=6(00000110),6(00000110)^2(00000010)=4(00000100),......因此,使用異或運算就可求得對稱結點,問題的關鍵變為如何求得另一運算元如 和2,3異或的1,和4,6異或的2,這個1,2正是2(3),4(6)的以2為底的整數對數(向下取整)值,而這個值可以使用位運算來高效地完成。這裡的索引有效範圍是非負數。
   2)怎麼判斷結點在最小堆或最大堆內:由1)分析,顯而易見可得,2(00000010)&1(00000001)=0,3(00000011)&1(00000001)=1,4(00000100)&2(00000010)=0,6(00000110)&2(00000010)=2,......因此,可以使用與運算來高效地判斷。
   3)為了充分利用空間,我的實現是最小堆根結點在索引0,最大堆根結點在索引1處,那麼在這種情況下,解決以上問題1),就需要將結點索引先加2,再從結果中減去2;解決以上問題2)需要將結點索引加2即可。當雙端堆元素數量佔盡全部空間容量時,次最大索引為空間容量減2,加2可能導致整數溢位,因此在實現中須區分處理。

   下面是雙端堆操作演算法的內部函式實現
  1、 以2為底的整數對數(向下取整)

 1struct _64bit_int{};
 2struct _no_64bit_int{};
 3
 4template<typename _Distance> 5inline _Distance __log2(_Distance _val,_no_64bit_int)
 6{
 7    assert(_val >0);
 8
 9    _Distance _ret =0, _tmp;
10    _tmp = _val >>16if (_tmp) { _ret +=16; _val = _tmp;}11    _tmp = _val 
>>8;  if (_tmp) { _ret +=8; _val = _tmp; }12    _tmp = _val >>4;  if (_tmp) { _ret +=4; _val = _tmp; }13    _tmp = _val >>2;  if (_tmp) { _ret +=2; _val = _tmp; }14    _ret += (_val >>1);
15
16    return _ret;
17}
18
19template<typename _Distance>20inline _Distance __log2(_Distance _val,_64bit_int)
21{
22    assert(_val >0);
23
24    _Distance _ret =0, _tmp;
25    _tmp = _val >>32if (_tmp) { _ret +=32; _val = _tmp;}26    _tmp = _val >>16if (_tmp) { _ret +=16; _val = _tmp;}27    _tmp = _val >>8;  if (_tmp) { _ret +=8; _val = _tmp; }28    _tmp = _val >>4;  if (_tmp) { _ret +=4; _val = _tmp; }29    _tmp = _val >>2;  if (_tmp) { _ret +=2; _val = _tmp; }30    _ret += (_val >>1);
31
32    return _ret;
33}
34
35template<typename _Distance>36inline _Distance __log2(_Distance val)
37{
38    return __log2(val,typename cppext::mpl::if_then_else<8==sizeof(_Distance),_64bit_int,_no_64bit_int>::type());
39}
   2、對稱結點計算和判斷函式
 1template<typename _Distance> 2inline bool __is_max_dheap_until(_Distance _dist) 
 3{
 4    assert(_dist >1);
 5    return0!=(_dist&(((_Distance)1)<<(__log2(_dist)-1)));
 6}
 7
 8template<typename _Distance> 9inline bool __is_max_dheap(_Distance _dist) 
10{
11    _Distance _tmp = _dist +2;
12    return _tmp > _dist ?  __is_max_dheap_until(_tmp) : __is_max_dheap_until((_dist>>1-1);
13}
14
15template<typename _Distance>16inline _Distance __partner_dheap_until(_Distance _dist)
17{
18    assert(_dist >1);
19    return _dist^(((_Distance)1)<<(__log2(_dist)-1));
20}
21
22template<typename _Distance>23inline _Distance __partner_dheap(_Distance _dist)
24{
25    _Distance _tmp = _dist +2;
26    return _tmp > _dist ?  __partner_dheap_until(_tmp) -2 : __partner_dheap_until((_dist>>1-1-2;
27}
   3、最大堆最小堆的插入
 1template<typename _RandIt,typename _Distance,typename _Ty> 2inline void __push_min_dheap(_RandIt _first,_Distance _hole,_Distance _top,_Ty _val,bool _flag =true)
 3{
 4    for (_Distance _parent;_hole > _top;)
 5    {
 6        _parent = (_hole -2>>1;
 7        if (!_flag && _parent == _top ||*(_first + _parent) < _val) 
 8            break;
 9        *(_first + _hole) =*(_first + _parent);
10        _hole = _parent;
11    }
12    *(_first + _hole) = _val;
13}
14
15template<typename _RandIt,typename _Distance,typename _Ty,typename _Compare>16inline void __push_min_dheap(_RandIt _first,_Distance _hole,_Distance _top,_Ty _val,_Compare _comp,bool _flag =true)
17{
18    for (_Distance _parent;_hole > _top;)
19    {
20        _parent = (_hole -2>>1;
21        if (!_flag && _parent == _top || _comp(*(_first + _parent),_val))
22            break;
23        *(_first + _hole) =*(_first + _parent);
24        _hole = _parent;
25    }
26    *(_first + _hole) = _val;
27}
28
29template<typename _RandIt,typename _Distance,typename _Ty>30inline void __push_max_dheap(_RandIt _first,_Distance _hole,_Distance _top,_Ty _val,bool _flag =true)
31

相關推薦

基於實現優先順序佇列2內幕

   在《基於雙端堆實現的優先順序佇列(1):原理》一文中講述了雙端堆的相關原理,本文則詳細講述具體的內部實現,便於區分,內部函式名稱都以雙下劃線作為字首,在這裡,有幾個關鍵問題需要說明    1)怎麼求一個結點的對稱結點:如果完全二叉樹根結點從索引1開始但不儲存元素,那麼最小堆根結點則在索引2

基於實現優先順序佇列3外觀

   本文講述雙端堆的5個公開泛型操作演算法:make_dheap(原位構造雙端堆)、push_dheap(插入元素)、pop_max_dheap(刪除最大元素)、pop_min_dheap(刪除最小元素),is_dheap(堆驗證),每個演算法都提供<小於運算子和仿函式比較2個版本,要注意

基於實現優先順序佇列1原理

前言    眾所周知,stl中的優先順序佇列是基於最大堆實現的,能夠在對數時間內插入元素和獲取優先順序最高的元素,但如果要求在對數時間內還能獲取優先順序最低的元素,而不只是獲取優先順序最高的元素,該怎麼實現呢?可以用最大堆-最小堆或雙端堆資料結構來實現,最大堆-最小堆和雙端堆都是支援雙端優先佇列

自定義佇列2迴圈佇列

通過學習自定義佇列,瞭解佇列的資料結構。 首先寫一個佇列的介面,描述其具有的基本功能。Queue.java 然後寫一個介面的實現類,這只是其中一種實現方式,為迴圈佇列。LoopQueue.java 最後寫一個測試類,測試自定義陣列佇列的效果。Test.java  

TensorFlow入門 LSTM 實現序列標註分詞

vsm max poc 代碼 單詞 arch 大致 雙端 fun http://blog.csdn.net/Jerr__y/article/details/70471066 歡迎轉載,但請務必註明原文出處及作者信息。 @author: huangyongye @creat_

自定義2通過實現優先佇列

學習堆、優先佇列之間的關係。   普通佇列:先進先出;後進後出。 優先佇列:出隊順序和入隊順序無關,和優先順序相關。     入隊 出隊(拿出最大元素) 之前自定義的普通線性結

TensorFlow入門 LSTM 實現序列標註分詞

歡迎轉載,但請務必註明原文出處及作者資訊。 @author: huangyongye @creat_date: 2017-04-19 前言 本例子主要介紹如何使用 TensorFlow 來一步一步構建雙端 LSTM 網路(聽名字就感覺好膩害的樣子),

實現優先順序佇列 Java實現

優先順序佇列分為最大優先順序佇列和最小優先順序佇列。本文介紹基於大根堆實現最大優先順序佇列。關於堆的介紹見另一篇博文: 堆這種資料結構 Java實現 最小優先順序佇列的實現可以在本文最後給出的github地址裡找到。 最大優先順序佇列包含四個操作:

兩個棧實現一個佇列java

一、問題描述 使用兩個棧實現一個佇列 二、演算法分析 棧是先進後出,因此兩個可以模擬實現先進先出 三、演算法設計 定義資料結構 Stack<Integer> stack1 Stack<Integer> stack2 對於push操作:元素入佇列

基於Python語言使用RabbitMQ訊息佇列

釋出/訂閱 前面的教程中我們已經建立了一個工作佇列。在一個工作佇列背後的假設是每個任務恰好會傳遞給一個工人。在這一部分裡我們會做一些完全不同的東西——我們會發送訊息給多個消費者。這就是所謂的“釋出/訂閱”模式。 為了解釋這種模式,我們將會構建一個簡單的日誌系

F#與ASP.NET2使用F#實現基於事件的非同步模式

在上一篇文章中,我們的簡單討論了.NET中兩種非同步模型以及它們在異常處理上的區別,並且簡單觀察了ASP.NET MVC 2中非同步Action的編寫方式。從中我們得知,ASP.NET MVC 2的非同步Action並非使用了傳統基於Begin/End的非同步程式設計模型,而是另一種基於事件的非同步模式。此外

Springboot + rabbitMQ實現延遲佇列消費者

由於太長了,所以分成兩篇寫,接上一篇講解了訊息的定義和傳送,這裡繼續講解消費者 由於可能每條訊息所處理的邏輯可能不一樣,例如:常規訂單30分鐘不支付則取消訂單,團購訂單一天拼團不成功則取消等等,為了避免在消費者監聽類中使用大量if else,這裡使用策略模式來處理(由於sp

C++模板實現佇列2

迴圈佇列中新增和刪除元素時並不像鏈式佇列那樣使用動態記憶體分配,一般採用固定的佇列長度,一次分配一片記憶體用於儲存資料,等到佇列使用完畢後釋放掉即可。記憶體使用效率比鏈式佇列高,也比較容易實現。佇列的資料定義如下: unsigned int size;

用最大堆實現優先佇列c++

關於最大堆,最小堆的概念這裡不再介紹。 #include <iostream> #include <vector> using namespace std; template<typename T> class Pri

極光訊息推送伺服器開發實現推送

以前一直使用的極光的手動輸入推送內容然後推送到客戶端,今天遇到了推送頻率比較高且比較有規律的內容,比如事實天氣。這樣就需要用我們自己的伺服器來自動生成推送內容了。 可以看到,上面兩句話很醒目,我們看看它封裝的REST API是個什麼東西,再點進去看看 上面兩句話讀了一

基於Python語言使用RabbitMQ訊息佇列

工作佇列 在第一節我們寫了程式來向命名佇列傳送和接收訊息 。在本節我們會建立一個工作佇列(Work Queue)用來在多個工人(worker)中分發時間消耗型任務(time-consuming tasks)。 工作佇列(又叫做: Task Queues)背後

極光訊息推送伺服器開發實現推送

前面我們已經實現了通過我們自己的伺服器生成訊息向極光訊息推送伺服器傳送推送訊息的功能,下面我們來看看如何在手機客戶端實現訊息接收。 一、在極光上建立一個測試專案 如上圖所示,下載Android Example 執行效果如圖 下面我們通過原始碼先看看上面的四行顯示Tex

基於Hi3559AV100 RFCN實現細節解析-2RFCN資料流分析

  下面隨筆系列將對Hi3559AV100 RFCN實現細節進行解析,整個過程涉及到VI、VDEC、VPSS、VGS、VO、NNIE,其中涉及的內容,大家可以參考之前我寫的部落格: Hi3559AV100的VI細節處理說明: https://www.cnblogs.com/iFrank/p/14374658.

SQL Server橫向擴展設計,實現與維護2- 分布式分區視圖

做的 img attach one 遠程 cnblogs ole out 不同的 為了使得朋友們對分布式分區視圖有個概念,也為了方便後面的內容展開,我們先看看下面一個圖: 講述分布式分區視圖之前,很有必要將之與我們常常熟悉的分區表和索引

【數據結構】ArrayList原理及實現學習總結2

!= 需要 但是 object count def 原理 arrays 位置 ArrayList是一個基於數組實現的鏈表(List),這一點可以從源碼中看出: transient Object[] elementData; // non-private to si