第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁(yè) 慕課教程 后端通用面試教程 后端通用面試教程 Redis數(shù)據(jù)結(jié)構(gòu)(二)

1. 前言

上一章節(jié)介紹了 SDS 數(shù)據(jù)結(jié)構(gòu),即 Redis 最基礎(chǔ)的 Key-Value 存儲(chǔ)實(shí)現(xiàn),本章節(jié)繼續(xù)介紹 Redis 底層的高級(jí)數(shù)據(jù)結(jié)構(gòu)。

Redis 的五種基本結(jié)構(gòu)中還有一個(gè)叫做 zset 的數(shù)據(jù)結(jié)構(gòu),zset 保證了每個(gè)值的唯一性,這方面性質(zhì)同傳統(tǒng)的 set 集合,也可以對(duì)每個(gè)值賦予 score,按照 score 進(jìn)行排序。這種高級(jí)性質(zhì)依賴于底層的跳躍表數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)。

2. SkipList

2.1 SkipList 數(shù)據(jù)結(jié)構(gòu)

面試官提問(wèn): Redis zset 數(shù)據(jù)結(jié)構(gòu)的底層實(shí)現(xiàn)是什么?為什么要使用跳躍表?

題目解析:

在介紹跳躍表(SkipList,簡(jiǎn)稱跳表)之前,我們可以以單鏈表數(shù)據(jù)結(jié)構(gòu)作為對(duì)比。

圖片描述

(單鏈表結(jié)構(gòu)示意圖)

在單鏈表中,我們查詢一個(gè)元素的時(shí)間復(fù)雜度是 O (N),其中 N 是鏈表的長(zhǎng)度,因?yàn)樾枰O個(gè)遍歷節(jié)點(diǎn),單鏈表不支持?jǐn)?shù)組的隨機(jī)插入和刪除,也不支持?jǐn)?shù)組的自動(dòng)排序,顯然不適合作為 zset 的實(shí)現(xiàn)方式。

跳躍表的基礎(chǔ)定義可參考維基百科定義

參考定義,我們給出 C 語(yǔ)言的結(jié)構(gòu)體定義:

typedef struct zskiplistNode {
    sds ele;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned int span;
    } level[];
} zskiplistNode;

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;
    int level;
} zskiplist;

候選人需要描述跳表的數(shù)據(jù)結(jié)構(gòu),可以通過(guò)畫(huà)圖或者其他方式給出定義。

圖片描述
?

(典型的跳躍表結(jié)構(gòu),圖片來(lái)自網(wǎng)絡(luò),侵刪)

從結(jié)構(gòu)體可以看出,節(jié)點(diǎn)有不同的定義:

  • sds:存儲(chǔ)的字符串對(duì)象;
  • score:分?jǐn)?shù),跳表中所有節(jié)點(diǎn)按照 score 由大到小排列;
  • backward:指向后退節(jié)點(diǎn)的指針;
  • forward:指向下一個(gè)節(jié)點(diǎn)的指針;
  • level:數(shù)組,數(shù)組中的每一個(gè)元素包括了指向其他節(jié)點(diǎn)的指針,level 的長(zhǎng)度在 1 到 32(2^5)之間。

其中跳表的主要組成結(jié)構(gòu)有:

  • 表頭:表示跳表的入口;
  • 表尾:表示跳表的尾部,數(shù)值全部都是 NULL;
  • 節(jié)點(diǎn):保存具體數(shù)值,并且具有層結(jié)構(gòu);
  • 層:就是上述 level 定義中的單個(gè)元素,保存前一個(gè)節(jié)點(diǎn)的指針,以及該層下個(gè)節(jié)點(diǎn)向前跨越的數(shù)值(span)。

跳表的查詢過(guò)程本質(zhì)上是自上而下的二分查找,插入和查詢過(guò)程都相對(duì)復(fù)雜,這里不做贅述。

在闡述基本定義之后,我們需要關(guān)注跳躍表的核心特點(diǎn):

  • 本質(zhì)是隨機(jī)化數(shù)據(jù)結(jié)構(gòu),可以在對(duì)數(shù)(logN)時(shí)間內(nèi)完成對(duì)數(shù)據(jù)的查找、插入、刪除操作;
  • 跳躍表在 Redis 的唯一應(yīng)用,就是作為有序集合支撐底層數(shù)據(jù)結(jié)構(gòu)。

2.2 跳躍表 vs 二叉樹(shù)

面試官提問(wèn): 二叉查找樹(shù)也能實(shí)現(xiàn)對(duì)數(shù)時(shí)間的查找插入特性,為什么還要使用跳躍表?

題目解析:

面試官經(jīng)常會(huì)拿跳表和其他數(shù)據(jù)結(jié)構(gòu)進(jìn)行對(duì)比,依次同時(shí)考察候選人數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)能力。

雖然二叉查找樹(shù)(Binary Search Tree)也滿足插入、查找、刪除時(shí)間復(fù)雜度為 O (logN),但是在極端情況下,如果插入的數(shù)據(jù)滿足完全有序(例如 1,2,3,4 …),則每次插入二手樹(shù)都是右節(jié)點(diǎn),這時(shí)二叉查找樹(shù)會(huì)退化為線性鏈表,查詢時(shí)間復(fù)雜度退化為 O(N)。相對(duì)于二叉查找樹(shù),跳躍表的表現(xiàn)更穩(wěn)定。

2.3 跳躍表 vs 紅黑樹(shù)

面試官提問(wèn): 紅黑樹(shù)也能實(shí)現(xiàn)對(duì)數(shù)時(shí)間的查找插入特性,為什么還要使用跳躍表?

題目解析:

紅黑樹(shù)(Red Black Tree)是二叉查找樹(shù)的一種變形,查找、插入、刪除的時(shí)間復(fù)雜度也是 O (logN),為什么 Redis 不使用紅黑樹(shù)作為 zset 的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)?

關(guān)于這一點(diǎn),Redis 的官方解釋已經(jīng)很全面:

There are a few reasons:

  1. They are not very memory intensive. It’s up to you basically. Changing parameters about the probability of a node to have a given number of levels will make then less memory intensive than btrees.
  2. A sorted set is often target of many ZRANGE or ZREVRANGE operations, that is, traversing the skip list as a linked list. With this operation the cache locality of skip lists is at least as good as with other kind of balanced trees.
  3. They are simpler to implement, debug, and so forth. For instance thanks to the skip list simplicity I received a patch (already in Redis master) with augmented skip lists implementing ZRANK in O(log(N)). It required little changes to the code.

總結(jié)下來(lái)就是兩點(diǎn)原因:

(1)相對(duì)于 B 樹(shù) / 紅黑樹(shù),跳躍表修改節(jié)點(diǎn)對(duì)內(nèi)存的變量影響小;

(2)性能接近紅黑樹(shù),但是跳表編碼實(shí)現(xiàn)更簡(jiǎn)單,方便調(diào)試,簡(jiǎn)單來(lái)說(shuō)就是編碼完整的紅黑樹(shù)實(shí)現(xiàn)麻煩且不直觀。

3. 小結(jié)

本章節(jié)介紹了跳躍表的基本數(shù)據(jù)結(jié)構(gòu)定義、插入查找的時(shí)間復(fù)雜度,以及和其他數(shù)據(jù)結(jié)構(gòu)的對(duì)比。跳表是常見(jiàn)的 Redis 底層數(shù)據(jù)結(jié)構(gòu),希望大家能夠深入理解并掌握。