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

loop_in_codes

低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

libevent 源碼分析:min_heap帶來的超時(shí)機(jī)制

author : Kevin Lynx

什么是min heap ?

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

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

實(shí)現(xiàn)

    min_heap相關(guān)源碼主要集中在min_heap.h以及超時(shí)相關(guān)的event.c中。
    首先看下min_heap的結(jié)構(gòu)體定義:

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


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

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

heap的核心操作:

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

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

void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{
    
/* 獲取父節(jié)點(diǎn) */
    unsigned parent 
= (hole_index - 1/ 2;
    
/* 只要父節(jié)點(diǎn)還大于子節(jié)點(diǎn)就循環(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;



- 從堆里取元素:

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

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

    libevent完成這個(gè)過程的函數(shù)主要是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é)點(diǎn)索引 */
    unsigned min_child 
= 2 * (hole_index + 1);
    
while(min_child <= s->n)
    
{
        
/* 有點(diǎn)惡心的一個(gè)表達(dá)式,目的就是取兩個(gè)孩子節(jié)點(diǎn)中較大的那個(gè)孩子索引 */
        min_child 
-= min_child == s->|| min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
        
/* 找到了位置,這里似乎是個(gè)優(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;
        
/* 重復(fù)這個(gè)過程 */
        hole_index 
= min_child;
        min_child 
= 2 * (hole_index + 1);
    }

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


STL中的heap

值得一提的是,STL中提供了heap的相關(guān)操作算法,借助于模板的泛化特性,其適用范圍非常廣泛。相關(guān)函數(shù)為:
make_heap, pop_heap, sort_heap, is_heap, sort 。其實(shí)現(xiàn)原理同以上算法差不多,相關(guā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) 評(píng)論(6)  編輯 收藏 引用 所屬分類: 通用編程network

評(píng)論

# re: libevent 源碼分析:min_heap帶來的超時(shí)機(jī)制 2008-07-21 12:07 foxtail

向高手致敬 哈哈  回復(fù)  更多評(píng)論   

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

插入元素和取元素的程序似乎是一樣的???  回復(fù)  更多評(píng)論   

# re: libevent 源碼分析:min_heap帶來的超時(shí)機(jī)制 2008-07-23 23:12 Kevin Lynx

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

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

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

與你這里畫得圖不符,拜托能認(rèn)真點(diǎn)嗎?  回復(fù)  更多評(píng)論   

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

@happyday
代碼確實(shí)粘貼錯(cuò)誤,謝謝提醒。

@無名
圖確實(shí)存在問題,謝謝提醒。

文章已做過微小修改。
  回復(fù)  更多評(píng)論   

# re: libevent 源碼分析:min_heap帶來的超時(shí)機(jī)制 2012-03-10 16:44 Color

其實(shí)是左節(jié)點(diǎn),從0開始???  回復(fù)  更多評(píng)論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲精品一区二| 欧美日韩精品一区二区| 欧美激情bt| 欧美91视频| 亚洲电影欧美电影有声小说| 久久精品亚洲一区二区| 久久久亚洲高清| 欧美成人黄色小视频| 亚洲高清在线观看一区| 亚洲精品国产系列| 亚洲一区中文字幕在线观看| 欧美一区国产在线| 免费欧美视频| 欧美日韩在线另类| 国产综合视频在线观看| 亚洲精品一区二区三区99| 这里只有精品视频| 久久久久久日产精品| 亚洲国产精品一区二区久 | 久久精品一区二区国产| 老巨人导航500精品| 91久久亚洲| 性做久久久久久久免费看| 欧美成人资源| 国产日韩欧美综合| 亚洲成人在线免费| 一本一本a久久| 国产偷自视频区视频一区二区| 国产曰批免费观看久久久| 尤物九九久久国产精品的特点| 亚洲激情欧美| 久久久精彩视频| 亚洲视频在线看| 欧美日本簧片| 日韩网站在线| 亚洲国产精品专区久久| 午夜视频一区| 国产精品一区二区三区四区五区| 日韩视频亚洲视频| 欧美激情1区2区3区| 久久久噜噜噜久久| 狠狠色综合色综合网络| 久久亚洲精品视频| 久久久7777| 在线观看欧美视频| 亚洲国产欧美一区二区三区丁香婷| 久久久国产精品亚洲一区| 国产一区二区久久精品| 免费成人av在线看| 欧美激情1区| 欧美一区二区三区四区视频| 亚洲五月六月| 国内精品久久国产| 久久这里只有| 在线视频你懂得一区二区三区| 亚洲精品字幕| 国产亚洲欧美另类中文| 最新亚洲激情| 国产乱人伦精品一区二区| 在线高清一区| 99精品欧美一区二区三区| 国产欧美一区二区三区在线老狼| 国产精品欧美日韩| 欧美日韩极品在线观看一区| 欧美v国产在线一区二区三区| 欧美顶级大胆免费视频| 国产精品伦理| 一区二区三区视频在线| 宅男精品导航| 日韩一级精品视频在线观看| 欧美视频日韩| 欧美大片va欧美在线播放| 国产精品久久久久99| 亚洲福利一区| 亚洲精品激情| 欧美国产日韩一二三区| 久久久噜噜噜| 久久久亚洲成人| 久久精品国产清高在天天线| 国产精品进线69影院| 在线视频日韩精品| 一区二区精品| 欧美亚一区二区| 99精品久久久| 亚洲欧美日韩国产综合在线| 国产精品美女久久久久久2018| 亚洲精品免费网站| 制服诱惑一区二区| 久久久久久日产精品| 国产综合精品| 欧美成年网站| 欧美一级专区免费大片| 麻豆精品视频在线| 亚洲欧洲一区二区天堂久久| 欧美日韩视频一区二区| 亚洲一区亚洲| 亚洲七七久久综合桃花剧情介绍| 亚洲系列中文字幕| 亚洲第一页自拍| 欧美日韩免费一区| 久久成人18免费观看| 99视频一区二区三区| 牛牛国产精品| 久久精品国产精品亚洲综合 | 亚洲性人人天天夜夜摸| 雨宫琴音一区二区在线| 欧美日韩国产综合视频在线观看中文 | 国产日韩欧美日韩| 欧美大色视频| 欧美搞黄网站| 久久综合九色九九| 亚洲欧美一区二区原创| 一区二区三区视频观看| 亚洲毛片播放| 亚洲精品自在在线观看| 亚洲精选久久| 99成人在线| 亚洲精选成人| 亚洲欧美成人一区二区在线电影| 亚洲人成免费| 亚洲乱码国产乱码精品精可以看 | 亚洲午夜av在线| 亚洲精品国产欧美| 亚洲韩国日本中文字幕| 欧美国产一区二区三区激情无套| 久久综合伊人77777麻豆| 欧美+亚洲+精品+三区| 欧美高清在线一区二区| 亚洲精品综合在线| 亚洲欧美日韩另类精品一区二区三区 | 国产精品日韩一区二区| 国产日韩一区二区| 亚洲欧洲视频在线| 亚洲欧美日韩系列| 久久久久久穴| 日韩视频不卡| 久久亚洲一区二区| 国产精品久久久久久福利一牛影视| 国产欧美一区二区色老头 | 99国产精品| 亚洲在线一区二区三区| 欧美粗暴jizz性欧美20| 一区二区三区免费在线观看| 久久久91精品| 国产欧美日韩视频一区二区| 久久精品一区二区三区四区| 久久免费精品视频| 久久久久久成人| 美女精品在线| 亚洲综合社区| 亚洲一区二区三区视频播放| 亚洲三级免费| 国产日韩欧美二区| 欧美日韩裸体免费视频| 日韩视频中文| 国产亚洲午夜| 国产精品一区免费观看| 国产日韩欧美一区二区三区四区| 国产目拍亚洲精品99久久精品| 久久免费一区| 久久久久久伊人| 在线视频日本亚洲性| 国产亚洲精品久久久久婷婷瑜伽| 欧美激情一区二区三区在线视频观看 | 99在线精品视频| 欧美电影打屁股sp| 久久免费观看视频| 欧美成人午夜| 国产精品毛片大码女人| 136国产福利精品导航| 欧美在线不卡| 久久露脸国产精品| 亚洲精品视频中文字幕| 亚洲伦伦在线| 国产性做久久久久久| 亚洲国产精品久久久久秋霞蜜臀| 欧美激情久久久久| 久久乐国产精品| 欧美日韩美女一区二区| 久久精品99国产精品酒店日本| 另类酷文…触手系列精品集v1小说| 亚洲激情亚洲| 亚洲欧美国产精品va在线观看| 亚洲电影在线播放| 亚洲一区二区三区精品在线| 亚洲国产福利在线| 欧美一区2区三区4区公司二百| 亚洲人成啪啪网站| 欧美一区观看| 欧美在线视频网站| 国产精品永久入口久久久| 亚洲国产精品久久精品怡红院| 久久尤物视频| 亚洲全部视频| 亚洲精品欧美在线| 国内成+人亚洲| 亚洲视频一区在线| 日韩视频一区二区三区| 欧美激情精品久久久久久变态 | 性欧美大战久久久久久久久|