青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

loop_in_codes

低調做技術__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

libevent 源碼分析:min_heap帶來的超時機制

author : Kevin Lynx

什么是min heap ?

    首先看什么是heap,heap是這樣一種數據結構:1.它首先是一棵完成二叉樹;2.父親節(jié)點始終大于(或其他邏輯關系
)其孩子節(jié)點。根據父親節(jié)點與孩子節(jié)點的這種邏輯關系,我們將heap分類,如果父親節(jié)點小于孩子節(jié)點,那么這個heap
就是min heap。
    就我目前所看到的實現(xiàn)代碼來看,heap基本上都是用數組(或者其他的連續(xù)存儲空間)作為其存儲結構的。這可以保證
數組第一個元素就是heap的根節(jié)點。這是一個非常重要的特性,它可以保證我們在取heap的最小元素時,其算法復雜度為
O(1)。
    原諒我的教科書式說教,文章后我會提供我所查閱的比較有用的關于heap有用的資料。

What Can It Do?
    libevent中的min_heap其實不算做真正的MIN heap。它的節(jié)點值其實是一個時間值。libevent總是保證時間最晚的節(jié)
點為根節(jié)點。
    libevent用這個數據結構來實現(xiàn)IO事件的超時控制。當某個事件(libevent中的struct event)被添加時(event_add),
libevent將此事件按照其超時時間(由用戶設置)保存在min_heap里。然后libevent會定期地去檢查這個min_heap,從而實現(xiàn)
了超時機制。

實現(xiàn)

    min_heap相關源碼主要集中在min_heap.h以及超時相關的event.c中。
    首先看下min_heap的結構體定義:

typedef struct min_heap
{
    
struct event** p;
    unsigned n, a;
}
 min_heap_t;


    p指向了一個動態(tài)分配的數組(隨便你怎么說,反正它是一個由realloc分配的連續(xù)內存空間),數組元素為event*,這也是
heap中的節(jié)點類型。這里libevent使用連續(xù)空間去保存heap,也就是保存一棵樹。因為heap是完成樹,所以可以保證其元素在
數組中是連續(xù)的。n表示目前保存了多少個元素,a表示p指向的內存的尺寸。
    struct event這個結構體定義了很多東西,但是我們只關注兩個成員:min_heap_idx:表示該event保存在min_heap數組中
的索引,初始為-1;ev_timeout:該event的超時時間,將被用于heap操作中的節(jié)點值比較。

    接下來看幾個與堆操作不大相關的函數:
    min_heap_elem_greater:比較兩個event的超時值大小。
    min_heap_size:返回heap元素值數量。
    min_heap_reserve:調整內存空間大小,也就是調整p指向的內存區(qū)域大小。凡是涉及到內存大小調整的,都有一個策略問
題,這里采用的是初始大小為8,每次增大空間時以2倍的速度增加。
    看幾個核心的:真正涉及到heap數據結構操作的函數:往堆里插入元素、從堆里取出元素:
    相關函數為:min_heap_push、min_heap_pop、min_heap_erase、min_heap_shift_up_、min_heap_shift_down_。

heap的核心操作:

- 往堆里插入元素:
    往堆里插入元素相對而言比較簡單,如圖所示,每一次插入時都從樹的最右最下(也就是葉子節(jié)點)開始。然后比較即將插入
的節(jié)點值與該節(jié)點的父親節(jié)點的值,如果小于父親節(jié)點的話(不用在意這里的比較規(guī)則,上下文一致即可),那么交換兩個節(jié)點,
將新的父親節(jié)點與其新的父親節(jié)點繼續(xù)比較。重復這個過程,直到比較到根節(jié)點。

  heap_add
    libevent實現(xiàn)這個過程的函數主要是min_heap_shift_up_。每一次min_heap_push時,首先檢查存儲空間是否足夠,然后直接
調用min_heap_shift_up_插入。主要代碼如下:

void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{
    
/* 獲取父節(jié)點 */
    unsigned parent 
= (hole_index - 1/ 2;
    
/* 只要父節(jié)點還大于子節(jié)點就循環(huán) */
    
while(hole_index && min_heap_elem_greater(s->p[parent], e))
    
{
        
/* 交換位置 */
        (s
->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
        hole_index 
= parent;
        parent 
= (hole_index - 1/ 2;
    }

    (s
->p[hole_index] = e)->min_heap_idx = hole_index;



- 從堆里取元素:

    大部分時候,從堆里取元素只局限于取根節(jié)點,因為這個節(jié)點是最有用的。對于數組存儲結構而言,數組第一個元素即為根
節(jié)點。取完元素后,我們還需要重新調整整棵樹以使其依然為一個heap。
    這需要保證兩點:1.依然是完成樹;2.父親節(jié)點依然小于孩子節(jié)點。
    在具體實現(xiàn)heap的取元素操作時,具體到代碼層次,方法都是有那么點微小差別的。libvent里的操作過程大致如圖所示(實際上libevent中父節(jié)點的時間值小于子節(jié)點的時間值,時間值的比較通過evutil_timercmp實現(xiàn)):

heap_remove
    主要過程分為兩步:
    1.比較左右孩子節(jié)點,選擇最大的節(jié)點,移到父親節(jié)點上;按照這種方式處理被選擇的孩子節(jié)點,直到沒有孩子節(jié)點為止。例如,
    當移除了100這個節(jié)點后,我們在100的孩子節(jié)點19和36兩個節(jié)點里選擇較大節(jié)點,即36,將36放置到100處;然后選擇原來的36的
左右孩子25和1,選25放置于原來的36處;
    2.按照以上方式處理后,樹會出現(xiàn)一個空缺,例如原先的25節(jié)點,因為被移動到原先的36處,25處就空缺了。因此,為了保證完
成性,就將最右最下的葉子節(jié)點(也就是連續(xù)存儲結構中最后一個元素),例如這里的7,移動到空缺處,然后按照插入元素的方式處理
新插入的節(jié)點7。
    完成整個過程。

    libevent完成這個過程的函數主要是min_heap_shift_down_:

/* hole_index 為取出的元素的位置,e為最右最下的元素值 */
void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
{
    
/* 取得hole_index的右孩子節(jié)點索引 */
    unsigned min_child 
= 2 * (hole_index + 1);
    
while(min_child <= s->n)
    
{
        
/* 有點惡心的一個表達式,目的就是取兩個孩子節(jié)點中較大的那個孩子索引 */
        min_child 
-= min_child == s->|| min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
        
/* 找到了位置,這里似乎是個優(yōu)化技巧,不知道具體原理 */
        
if(!(min_heap_elem_greater(e, s->p[min_child])))
            
break;
        
/* 換位置 */
        (s
->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
        
/* 重復這個過程 */
        hole_index 
= min_child;
        min_child 
= 2 * (hole_index + 1);
    }

    
/* 執(zhí)行第二步過程,將最右最下的節(jié)點插到空缺處 */
    min_heap_shift_up_(s, hole_index,  e);
}
 


STL中的heap

值得一提的是,STL中提供了heap的相關操作算法,借助于模板的泛化特性,其適用范圍非常廣泛。相關函數為:
make_heap, pop_heap, sort_heap, is_heap, sort 。其實現(xiàn)原理同以上算法差不多,相關代碼在algorithm里。SGI的
STL在stl_heap.h里。

參考資料:

What is a heap?

Heap_(data_structure)

Heap Remove

posted on 2008-07-18 15:56 Kevin Lynx 閱讀(6666) 評論(6)  編輯 收藏 引用 所屬分類: 通用編程network

評論

# re: libevent 源碼分析:min_heap帶來的超時機制 2008-07-21 12:07 foxtail

向高手致敬 哈哈  回復  更多評論   

# re: libevent 源碼分析:min_heap帶來的超時機制[未登錄] 2008-07-23 20:06 happyday

插入元素和取元素的程序似乎是一樣的???  回復  更多評論   

# re: libevent 源碼分析:min_heap帶來的超時機制 2008-07-23 23:12 Kevin Lynx

@happyday
取元素只是從樹根取,取了后需要對整棵樹進行調整。
插入元素插入到最下最右的節(jié)點,插入后需要進行微小的調整。
總之元素的增加/減少,都需要重新調整整棵樹使其依然為一個堆。  回復  更多評論   

# re: libevent 源碼分析:min_heap帶來的超時機制[未登錄] 2009-03-30 13:43 無名

哥們,libevent的最小堆根元素是最小的,父節(jié)點總比子節(jié)點值要小,

與你這里畫得圖不符,拜托能認真點嗎?  回復  更多評論   

# re: libevent 源碼分析:min_heap帶來的超時機制 2009-03-31 16:24 Kevin Lynx

@happyday
代碼確實粘貼錯誤,謝謝提醒。

@無名
圖確實存在問題,謝謝提醒。

文章已做過微小修改。
  回復  更多評論   

# re: libevent 源碼分析:min_heap帶來的超時機制 2012-03-10 16:44 Color

其實是左節(jié)點,從0開始???  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美四级伦理在线| 国产视频不卡| 在线视频你懂得一区| 亚洲黄色一区| 久久影音先锋| 久久蜜臀精品av| 老**午夜毛片一区二区三区| 久久久久九九视频| 久久精品国产精品亚洲精品| 性色av香蕉一区二区| 美女精品国产| 9人人澡人人爽人人精品| 欧美亚洲在线播放| 狂野欧美激情性xxxx欧美| 欧美区亚洲区| 激情国产一区| 久久久国产精品一区二区三区| 亚洲精品美女久久7777777| 亚洲电影免费在线| 亚洲精品在线观看免费| 亚洲视屏在线播放| 欧美激情综合色| 亚洲欧美成人精品| 亚洲一区国产精品| 免费在线观看一区二区| 久久综合久久综合这里只有精品| 米奇777在线欧美播放| 一区二区不卡在线视频 午夜欧美不卡在 | 亚洲电影在线播放| 一区二区欧美日韩| 欧美国产综合一区二区| 亚洲欧洲精品一区二区三区 | 欧美日本一区二区高清播放视频| 国产日韩1区| 欧美在线啊v| 久久国产精品久久w女人spa| 国产日韩一区二区三区在线播放| 午夜亚洲性色视频| 亚洲免费小视频| 国产午夜精品麻豆| 久久久久久久久久久成人| 久久精品一区二区三区四区| 国模精品娜娜一二三区| 欧美成人性网| 欧美三日本三级三级在线播放| 午夜久久黄色| 久久婷婷久久| 欧美一区二视频在线免费观看| 一区二区三区在线免费播放| 亚洲国产精品t66y| 国产精品羞羞答答xxdd| 欧美日韩国产专区| 亚洲一区二区三区在线| 国产精品色午夜在线观看| 香蕉成人伊视频在线观看| 午夜久久资源| 亚洲免费成人av| 午夜免费在线观看精品视频| 在线电影一区| 亚洲中午字幕| 一区二区三欧美| 久久精品国产亚洲一区二区三区 | 国产三区精品| 亚洲精品欧美极品| 亚洲国产成人久久综合| 亚洲欧美变态国产另类| 艳妇臀荡乳欲伦亚洲一区| 久久av资源网| 久久精品久久99精品久久| 欧美视频网站| 亚洲老板91色精品久久| 亚洲风情在线资源站| 久久精品99无色码中文字幕| 久久av一区二区三区漫画| 国产精品久久久久久久电影| 亚洲精品网址在线观看| 亚洲天堂av图片| 国产精品久久久久久久久免费| 亚洲精品一区二区三区樱花| 夜夜嗨av一区二区三区四季av | 久久久久久亚洲精品中文字幕| 亚洲欧美日韩电影| 亚洲欧美日韩在线观看a三区| 欧美日韩国产成人在线| 亚洲作爱视频| 久久精品亚洲精品| 亚洲第一色在线| 国产精品久久久久久久久久ktv| 亚洲视屏一区| 亚洲国产三级网| 这里只有视频精品| 娇妻被交换粗又大又硬视频欧美| 久久嫩草精品久久久精品| 亚洲国内自拍| 久久午夜精品| 性欧美暴力猛交另类hd| 一本到高清视频免费精品| 国产欧美日韩综合精品二区| 欧美精品日韩| 久久精品亚洲一区二区| 中文无字幕一区二区三区| 亚洲国产天堂久久综合| 久久久www免费人成黑人精品| 亚洲免费黄色| 欧美性猛交视频| 亚洲一卡二卡三卡四卡五卡| 久久久久国产精品一区二区| 亚洲一区3d动漫同人无遮挡| 国产日韩欧美一区二区三区四区| 欧美—级a级欧美特级ar全黄| 午夜精品免费在线| 正在播放欧美视频| 一本色道综合亚洲| 亚洲国产美女精品久久久久∴| 久久精品视频在线观看| 亚洲欧美激情一区| 亚洲欧美日韩精品综合在线观看 | 亚洲精品视频在线看| 亚洲日本无吗高清不卡| 亚洲大胆在线| 日韩亚洲欧美一区二区三区| 最新国产の精品合集bt伙计| 亚洲第一区在线观看| 日韩亚洲一区二区| 亚洲一区二区在线观看视频| 中文国产成人精品| 欧美诱惑福利视频| 欧美大色视频| 国产精品女主播一区二区三区| 国产精品av久久久久久麻豆网| 国产日韩欧美一区二区三区在线观看 | 亚洲国产视频直播| 99精品视频免费| 久久国产精品72免费观看| 欧美高清在线视频| 亚洲午夜精品久久久久久app| 久久综合久久综合久久综合| 欧美午夜宅男影院在线观看| 精品999在线播放| 亚洲天堂男人| 在线视频日本亚洲性| 美女爽到呻吟久久久久| 一区二区不卡在线视频 午夜欧美不卡'| 亚洲一区二区三区激情| 欧美激情一二三区| 黑人巨大精品欧美黑白配亚洲| 亚洲欧美在线免费观看| 一本色道久久| 国产精品免费看| 亚洲欧美清纯在线制服| 夜夜爽www精品| 欧美色网在线| 午夜精品久久久久久久99樱桃| 亚洲精品社区| 欧美三级乱码| 欧美一级视频免费在线观看| 亚洲最新色图| 国产精品午夜久久| 久久在线免费观看视频| 欧美成人官网二区| 在线亚洲精品福利网址导航| 亚洲午夜久久久久久久久电影院| 国产精品成人免费| 久久国产精品99国产精| 美国三级日本三级久久99| 亚洲精品免费在线| 久久免费黄色| 午夜精品久久久久| 亚洲一区二区精品| 国内成+人亚洲| 亚洲激情精品| 国产精品成人一区二区三区夜夜夜 | 在线精品国精品国产尤物884a| 亚洲成在线观看| 国产女人精品视频| 亚洲每日更新| 亚洲精品1区2区| 亚洲综合不卡| 亚洲欧洲日夜超级视频| 久久久视频精品| 欧美一区视频在线| 欧美色视频在线| 欧美激情一区二区三级高清视频| 国产精品看片你懂得| 99精品国产在热久久下载| 亚洲精品国产欧美| 欧美不卡视频一区| 久久久久久成人| 国产欧美亚洲一区| 欧美怡红院视频一区二区三区| 亚洲免费影视第一页| 欧美人与禽猛交乱配视频| 亚洲日本精品国产第一区| 99re6这里只有精品视频在线观看| 另类激情亚洲| 99精品热视频| 久久久久久高潮国产精品视| 在线观看成人一级片| 久热国产精品视频| 日韩午夜在线视频|