redis 內(nèi)部數(shù)據(jù)結(jié)構(gòu)(1.4)-跳躍表

跳躍表示意圖

位于圖片最左邊的是 zskiplist 結(jié)構(gòu)吹散, 該結(jié)構(gòu)包含以下屬性,右邊是各個(gè)跳躍表節(jié)點(diǎn)
左邊的zskiplist結(jié)構(gòu)包括了一下幾個(gè)屬性:

  • header :指向跳躍表的表頭節(jié)點(diǎn)空民。
  • tail :指向跳躍表的表尾節(jié)點(diǎn)。
  • level :記錄目前跳躍表內(nèi)界轩,層數(shù)最大的那個(gè)節(jié)點(diǎn)的層數(shù)(表頭節(jié)點(diǎn)的層數(shù)不計(jì)算在內(nèi))。2^5=32
  • length :記錄跳躍表的長(zhǎng)度浊猾,也即是,跳躍表目前包含節(jié)點(diǎn)的數(shù)量(表頭節(jié)點(diǎn)不計(jì)算在內(nèi))葫慎。

位于 zskiplist 結(jié)構(gòu)右方的是四個(gè) zskiplistNode 結(jié)構(gòu), 該結(jié)構(gòu)包含以下屬性:

  • 層(level):節(jié)點(diǎn)中用 L1 幅疼、 L2 米奸、 L3 等字樣標(biāo)記節(jié)點(diǎn)的各個(gè)層悴晰, L1 代表第一層, L2 代表第二層,以此類推铡溪。每個(gè)層都帶有兩個(gè)屬性:前進(jìn)指針和跨度漂辐。前進(jìn)指針用于訪問位于表尾方向的其他節(jié)點(diǎn),而跨度則記錄了前進(jìn)指針?biāo)赶蚬?jié)點(diǎn)和當(dāng)前節(jié)點(diǎn)的距離棕硫。在上面的圖片中髓涯,連線上帶有數(shù)字的箭頭就代表前進(jìn)指針,而那個(gè)數(shù)字就是跨度哈扮。當(dāng)程序從表頭向表尾進(jìn)行遍歷時(shí)纬纪,訪問會(huì)沿著層的前進(jìn)指針進(jìn)行。
  • 后退(backward)指針:節(jié)點(diǎn)中用 BW 字樣標(biāo)記節(jié)點(diǎn)的后退指針滑肉,它指向位于當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)包各。后退指針在程序從表尾向表頭遍歷時(shí)使用。
  • 分值(score):各個(gè)節(jié)點(diǎn)中的 1.0 靶庙、 2.0 和 3.0 是節(jié)點(diǎn)所保存的分值问畅。在跳躍表中,節(jié)點(diǎn)按各自所保存的分值從小到大排列六荒。
  • 成員對(duì)象(obj):各個(gè)節(jié)點(diǎn)中的 o1 护姆、 o2 和 o3 是節(jié)點(diǎn)所保存的成員對(duì)象。

跳躍表節(jié)點(diǎn)

節(jié)點(diǎn)的結(jié)構(gòu)體

typedef struct zskiplistNode {

    // 后退指針
    struct zskiplistNode *backward;

    // 分值
    double score;

    // 成員對(duì)象
    robj *obj;

    // 層
    struct zskiplistLevel {

        // 前進(jìn)指針
        struct zskiplistNode *forward;

        // 跨度
        unsigned int span;

    } level[];

} zskiplistNode;

跳躍表節(jié)點(diǎn)的 level 數(shù)組可以包含多個(gè)元素掏击, 每個(gè)元素都包含一個(gè)指向其他節(jié)點(diǎn)的指針卵皂, 程序可以通過這些層來(lái)加快訪問其他節(jié)點(diǎn)的速度,一般來(lái)說(shuō)铐料, 層的數(shù)量越多渐裂, 訪問其他節(jié)點(diǎn)的速度就越快豺旬。每次創(chuàng)建一個(gè)新跳躍表節(jié)點(diǎn)的時(shí)候钠惩, 程序都根據(jù)冪次定律 (power law,越大的數(shù)出現(xiàn)的概率越凶逶摹)隨機(jī)生成一個(gè)介于 1 和 32 之間的值作為 level 數(shù)組的大小篓跛, 這個(gè)大小就是層的“高度”。圖 5-2 分別展示了三個(gè)高度為 1 層坦刀、 3 層和 5 層的節(jié)點(diǎn)愧沟, 因?yàn)?C 語(yǔ)言的數(shù)組索引總是從 0 開始的, 所以節(jié)點(diǎn)的第一層是 level[0]鲤遥, 而第二層是 level[1]沐寺, 以此類推。

帶有不同層高的節(jié)點(diǎn)

前進(jìn)指針

每個(gè)層都有一個(gè)指向表尾方向的前進(jìn)指針(level[i].forward 屬性)盖奈, 用于從表頭向表尾方向訪問節(jié)點(diǎn)混坞。
圖 5-3 用虛線表示出了程序從表頭向表尾方向, 遍歷跳躍表中所有節(jié)點(diǎn)的路徑:

  • 迭代程序首先訪問跳躍表的第一個(gè)節(jié)點(diǎn)(表頭), 然后從第四層的前進(jìn)指針移動(dòng)到表中的第二個(gè)節(jié)點(diǎn)究孕。
  • 在第二個(gè)節(jié)點(diǎn)時(shí)啥酱, 程序沿著第二層的前進(jìn)指針移動(dòng)到表中的第三個(gè)節(jié)點(diǎn)。
  • 在第三個(gè)節(jié)點(diǎn)時(shí)镶殷, 程序同樣沿著第二層的前進(jìn)指針移動(dòng)到表中的第四個(gè)節(jié)點(diǎn)绘趋。
  • 當(dāng)程序再次沿著第四個(gè)節(jié)點(diǎn)的前進(jìn)指針移動(dòng)時(shí)颗管, 它碰到一個(gè) NULL , 程序知道這時(shí)已經(jīng)到達(dá)了跳躍表的表尾拷呆, 于是結(jié)束這次遍歷茬斧。
Paste_Image.png

后退指針

前進(jìn)指針可以跳躍项秉,后退指針只能每次退回一層慷彤。

分值和成員

節(jié)點(diǎn)的分值(score 屬性)是一個(gè) double 類型的浮點(diǎn)數(shù), 跳躍表中的所有節(jié)點(diǎn)都按分值從小到大來(lái)排序岁诉。

節(jié)點(diǎn)的成員對(duì)象(obj 屬性)是一個(gè)指針涕癣, 它指向一個(gè)字符串對(duì)象前标, 而字符串對(duì)象則保存著一個(gè) SDS 值。

在同一個(gè)跳躍表中只搁, 各個(gè)節(jié)點(diǎn)保存的成員對(duì)象必須是唯一的俭尖, 但是多個(gè)節(jié)點(diǎn)保存的分值卻可以是相同的: 分值相同的節(jié)點(diǎn)將按照成員對(duì)象在字典序中的大小來(lái)進(jìn)行排序, 成員對(duì)象較小的節(jié)點(diǎn)會(huì)排在前面(靠近表頭的方向)明肮, 而成員對(duì)象較大的節(jié)點(diǎn)則會(huì)排在后面(靠近表尾的方向)柿估。

舉個(gè)例子, 在圖 5-7 所示的跳躍表中的妖, 三個(gè)跳躍表節(jié)點(diǎn)都保存了相同的分值 10086.0 足陨, 但保存成員對(duì)象 o1 的節(jié)點(diǎn)卻排在保存成員對(duì)象 o2和 o3 的節(jié)點(diǎn)之前, 而保存成員對(duì)象 o2 的節(jié)點(diǎn)又排在保存成員對(duì)象 o3 的節(jié)點(diǎn)之前星虹, 由此可見宽涌, o1 蝶棋、 o2 、 o3 三個(gè)成員對(duì)象在字典中的排序?yàn)?o1 <= o2 <= o3 兼贸。

跳躍表

使用一個(gè) zskiplist 結(jié)構(gòu)來(lái)持有這些節(jié)點(diǎn)溶诞, 程序可以更方便地對(duì)整個(gè)跳躍表進(jìn)行處理罕偎, 比如快速訪問跳躍表的表頭節(jié)點(diǎn)和表尾節(jié)點(diǎn)很澄, 又或者快速地獲取跳躍表節(jié)點(diǎn)的數(shù)量(也即是跳躍表的長(zhǎng)度)等信息。
zskiplist 結(jié)構(gòu)的定義如下:

typedef struct zskiplist {

    // 表頭節(jié)點(diǎn)和表尾節(jié)點(diǎn)
    struct zskiplistNode *header, *tail;

    // 表中節(jié)點(diǎn)的數(shù)量
    unsigned long length;

    // 表中層數(shù)最大的節(jié)點(diǎn)的層數(shù)
    int level;

} zskiplist;

header 和 tail 指針分別指向跳躍表的表頭和表尾節(jié)點(diǎn)俏站, 通過這兩個(gè)指針肄扎, 程序定位表頭節(jié)點(diǎn)和表尾節(jié)點(diǎn)的復(fù)雜度為 O(1) 。通過使用 length屬性來(lái)記錄節(jié)點(diǎn)的數(shù)量旭等, 程序可以在 O(1) 復(fù)雜度內(nèi)返回跳躍表的長(zhǎng)度衡载。level 屬性則用于在 O(1)復(fù)雜度內(nèi)獲取跳躍表中層高最大的那個(gè)節(jié)點(diǎn)的層數(shù)量痰娱, 注意表頭節(jié)點(diǎn)的層高并不計(jì)算在內(nèi)梨睁。

跳躍表在redis中用于實(shí)現(xiàn)有序集合
關(guān)于跳躍表的增刪改查demo可以看這個(gè)http://blog.csdn.net/ict2014/article/details/17394259

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市官辈,隨后出現(xiàn)的幾起案子钧萍,更是在濱河造成了極大的恐慌政鼠,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件万搔,死亡現(xiàn)場(chǎng)離奇詭異瞬雹,居然都是意外死亡酗捌,警方通過查閱死者的電腦和手機(jī)涌哲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門哪廓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涡真,“玉大人分俯,你說(shuō)我怎么就攤上這事缸剪⌒咏冢” “怎么了讥此?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵卒稳,是天一觀的道長(zhǎng)他巨。 經(jīng)常有香客問我,道長(zhǎng)捻爷,這世上最難降的妖魔是什么也榄? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任甜紫,我火速辦了婚禮囚霸,結(jié)果婚禮上激才,老公的妹妹穿的比我還像新娘瘸恼。我一直安慰自己,他們只是感情好揣云,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布邓夕。 她就那樣靜靜地躺著阎毅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪矿咕。 梳的紋絲不亂的頭發(fā)上碳柱,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天莲镣,我揣著相機(jī)與錄音瑞侮,去河邊找鬼半火。 笑死钮糖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酌住。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肄满!你這毒婦竟也來(lái)了稠歉?” 一聲冷哼從身側(cè)響起汇陆,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤怒炸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后毡代,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阅羹,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勺疼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捏鱼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片执庐。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖导梆,靈堂內(nèi)的尸體忽然破棺而出轨淌,到底是詐尸還是另有隱情,我是刑警寧澤看尼,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布递鹉,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏禀挫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧僻造,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)隙券。三九已至游桩,卻和暖如春盹憎,著一層夾襖步出監(jiān)牢的瞬間镰吵,已是汗流浹背盼产。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工蜈项, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跑芳。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓盆佣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親穆咐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子遗淳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • typedef struct zskiplistNode {struct zskiplistLevel {stru...
    c84f3109853b閱讀 567評(píng)論 0 0
  • 本文為筆者對(duì)在學(xué)習(xí)Redis過程中所收集資料的一個(gè)總結(jié)陕贮,目的是為了以后方便回顧相關(guān)的知識(shí),大部分為非原創(chuàng)內(nèi)容卜录。特此...
    EakonZhao閱讀 14,414評(píng)論 0 9
  • 跳躍表(zskiplist)是一種有序的數(shù)據(jù)結(jié)構(gòu),通過在一個(gè)節(jié)點(diǎn)中維持多個(gè)指向其他節(jié)點(diǎn)的指針,從而達(dá)到從當(dāng)前節(jié)點(diǎn)快...
    舒小賤閱讀 741評(píng)論 0 1
  • 人生難免有幾場(chǎng)可有可無(wú)的罵戰(zhàn)坛增,但是在被罵的時(shí)候是蔫的荒叼,罵完過了24小時(shí)才想起來(lái)要反擊嫁乘,又有什么意義呢?反射弧長(zhǎng)到可...
    古一顧閱讀 270評(píng)論 0 0
  • 我是Han,一個(gè)在萃取營(yíng)被叫做神秘男子的人 。 我在萃取營(yíng)最大的優(yōu)勢(shì)就是起步低邮绿,對(duì)粤铭,你沒有看錯(cuò),起步低就是我最大的...
    思遠(yuǎn)同學(xué)閱讀 256評(píng)論 4 2