一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Redis - 詳解Redis數據結構之跳躍表

詳解Redis數據結構之跳躍表

2020-12-28 15:38sherlock_lin Redis

這篇文章主要介紹了Redis數據結構中的跳躍表的相關知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

 

1、簡介

 

我們先不談Redis,來看一下跳表。

 

1.1、業務場景

場景來自小灰的算法之旅,我們需要做一個拍賣行系統,用來查閱和出售游戲中的道具,類似于魔獸世界中的拍賣行那樣,還有以下需求:

拍賣行拍賣的商品需要支持四種排序方式,分別是:按價格、按等級、按剩余時間、按出售者ID排序,排序查詢要盡可能地快。還要支持輸入道具名稱的精確查詢和不輸入名稱的全量查詢。

這樣的業務場景所需要的數據結構該如何設計呢?拍賣行商品列表是線性的,最容易表達線性結構的是數組和鏈表。假如用有序數組,雖然查找的時候可以使用二分法(時間復雜度O(logN)),但是插入的時間復雜度是O(N),總體時間復雜度是O(N);而如果要使用有序鏈表,雖然插入的時間復雜度是O(1),但是查找的時間復雜度是O(N),總體還是O(N)。

那有沒有一種數據結構,查找時,有二分法的效率,插入時有鏈表的簡單呢?有的,就是 跳表。

 

1.2、skiplist

skiplist,即跳表,又稱跳躍表,也是一種數據結構,用于解決算法問題中的查找問題。

一般問題中的查找分為兩大類,一種是基于各種平衡術,時間復雜度為O(logN),一種是基于哈希表,時間復雜度O(1)。但是skiplist比較特殊,沒有在這里面

 

2、跳表

 

 

2.1、跳表簡介

跳表也是鏈表的一種,是在鏈表的基礎上發展出來的,我們都知道,鏈表的插入和刪除只需要改動指針就行了,時間復雜度是O(1),但是插入和刪除必然伴隨著查找,而查找需要從頭/尾遍歷,時間復雜度為O(N),如下圖所示是一個有序鏈表(最左側的灰色表示一個空的頭節點)(圖片來自網絡,以下同):

詳解Redis數據結構之跳躍表

鏈表中,每個節點都指向下一個節點,想要訪問下下個節點,必然要經過下個節點,即無法跳過節點訪問,假設,現在要查找22,我們要先后查找 3->7->11->19->22,需要五次查找。

但是如果我們能夠實現跳過一些節點訪問,就可以提高查找效率了,所以對鏈表進行一些修改,如下圖:

詳解Redis數據結構之跳躍表

我們每個一個節點,都會保存指向下下個節點的指針,這樣我們就能跳過某個節點進行訪問,這樣,我們其實是構造了兩個鏈表,新的鏈表之后原來鏈表的一半。

我們姑且稱原鏈表為第一層,新鏈表為第二層,第二層是在第一層的基礎上隔一個取一個。假設,現在還是要查找22,我們先從第二層查找,從7開始,7小于22,再往后,19小于22,再往后,26大于22,所以從節點19轉到第一層,找到了22,先后查找 7->19->26->22,只需要四次查找。

以此類推,如果再提取一層鏈表,查找效率豈不是更高,如下圖:

詳解Redis數據結構之跳躍表

現在,又多了第三層鏈表,第三層是在第二層的基礎上隔一個取一個,假設現在還是要查找22,我們先從第三層開始查找,從19開始,19小于22,再往后,發現是空的,則轉到第二層,19后面的26大于22,轉到第一層,19后面的就是22,先后查找 19->26>22,只需要三次查找。

由上例可見,在查找時,跳過多個節點,可以大大提高查找效率,skiplist 就是基于此原理。

上面的例子中,每一層的節點個數都是下一層的一半,這種查找的過程有點類似二分法,查找的時間復雜度是O(logN),但是例子中的多層鏈表有一個致命的缺陷,就是一旦有節點插入或者刪除,就會破壞這種上下層鏈表節點個數是2:1的結構,如果想要繼續維持,則需要在插入或者刪除節點之后,對后面的所有節點進行一次重新調整,這樣一來,插入/刪除的時間復雜度就變成了O(N)。

 

2.2、跳表層級之間的關系

如上所述,跳表為了解決插入和刪除節點時造成的后續節點重新調整的問題,引入了隨機層數的做法。相鄰層數之間的節點個數不再是嚴格的2:1的結構,而是為每個新插入的節點賦予一個隨機的層數。下圖展示了如何通過一步步的插入操作從而形成一個跳表:

詳解Redis數據結構之跳躍表

每一個節點的層數都是隨機算法得出的,插入一個新的節點不會影響其他節點的層數,因此,插入操作只需要修改插入節點前后的指針即可,避免了對后續節點的重新調整。這是跳表的一個很重要的特性,也是跳表性能明顯由于平衡樹的原因,因為平衡樹在失去平衡之后也需要進行平衡調整。

上圖最后的跳表中,我們需要查找節點22,則遍歷到的節點依次是:7->37->19->22,可見,這種隨機層數的跳表的查找時可能沒有2:1結構的效率,但是卻解決了插入/刪除節點的問題。

 

2.3、跳表的復雜度

跳表搜索的時間復雜度平均 O(logN),最壞O(N),空間復雜度O(2N),即O(N)

 

3、Redis中的跳表

 

在理解 Redis 的跳躍表之前,我們先回憶一下 Redis 的有序集合(sorted set)操作

  • 不重復但有序的字符串元素集合;
  • 每個元素均關聯一個double類型的score,Redis 根據score進行從小到大排序;
  • score可以重復,重復的按照插入順序進行排序;

示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
redis 127.0.0.1:6379> ZADD runoobkey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD runoobkey 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES
 
"redis"
"1"
"mongodb"
"2"
"mysql"
"4"

這個是 Redis 中的有序列表的基本操作,我們答題可以看出,在有序列表中,有一個浮點數作為 score, 當對應一個值,可以根據 score 精確查找和范圍查找,且效率很高

Redis 里面的這種操作的底層實現就是跳表。

上面理解了跳表,再去看 Redis 中的跳表就輕松多了,跳表的實現在 Redis 源碼目錄下 redis.h 文件中

 

3.1、zskiplistNode

zskiplistNode 表示跳表的一個節點,聲明如下:

?
1
2
3
4
5
6
7
8
9
typedef struct zskiplistNode {
  robj *obj;
  double score;
  struct zskiplistNode *backward;
  struct zskiplistLevel {
    struct zskiplistNode *forward;
    unsigned int span;
  } level[];
} zskiplistNode;

robj 類型是 Redis 中用C語言實現一種集合數據結構,它可以表示 string、hash、list、set 和 zset 五種數據類型,這里不做詳細說明,在跳表節點中,這個類型的指針表示節點的成員對象

score 表示分值,用于排序和范圍查找

level 是一個柔性數組,它表示節點的層級,每層都有一個前進指針 forward,用于指向相同層級指向表尾方向的下一個節點,而 span 則表示當前節點在當前層級中距離下一個節點的跨度,即兩個節點之間的距離。

初看上去,很容易以為跨度和遍歷節點有關,實際并不是,遍歷操作只用前進指針就夠了,跨度是用來計算排位(rank)的:在查找某個節點的過程中,沿途訪問過的所有層的跨度累計起來,就是目標節點在跳表中的排位。

下圖中,查找成員o3,只經歷了一層,排位為3

詳解Redis數據結構之跳躍表

在 Redis 中,每個節點的層級都是根據冪次定律(power law,越大的樹出現的概率越小)隨機生成的,它是1~32之間的一個數,作為level數組的大小,即高度

下圖分別展示了三個高度為1、3、5層的節點

詳解Redis數據結構之跳躍表

backward 是一個后退指針,每個節點都有一個,指向當前節點的表頭方向的下一個節點,用于從表尾進行遍歷

 

3.2、zskiplist

zskiplist 表示一個跳表,聲明如下:

?
1
2
3
4
5
typedef struct zskiplist {
  struct zskiplistNode *header, *tail;
  unsigned long length;
  int level;
} zskiplist;

header 和 tail 指針分別指向表頭和表尾節點

length 記錄了節點數量

level 記錄了所有節點中層級最高的節點的層級,表頭節點的層高不計算在內

下圖是一個跳表的示例,最左側是一個 zskiplist 結構,其右側是四個 zskiplistNode 節點,從左向右分別有32層、4層、2層、5層。每個節點向右的指針即前進指針 forward, BW 則表示后退指針 backward,每個節點依據節點的分值 score 進行排列

詳解Redis數據結構之跳躍表

到此這篇關于Redis數據結構中的跳躍表的文章就介紹到這了,更多相關Redis數據結構跳躍表內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/sherlock-lin/p/13960915.html

延伸 · 閱讀

精彩推薦
  • RedisRedis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • RedisRedis 事務知識點相關總結

    Redis 事務知識點相關總結

    這篇文章主要介紹了Redis 事務相關總結,幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • Redisredis實現排行榜功能

    redis實現排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關于Redis全量復制與部分復制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農5812019-11-18
  • RedisRedis如何實現數據庫讀寫分離詳解

    Redis如何實現數據庫讀寫分離詳解

    Redis的主從架構,能幫助我們實現讀多,寫少的情況,下面這篇文章主要給大家介紹了關于Redis如何實現數據庫讀寫分離的相關資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎,哨兵和集群都是建立在復制基礎上實現高可用的...

    李留廣10222021-08-09
主站蜘蛛池模板: 免费午夜影院 | 图片专区小说专区卡通动漫 | 特级毛片免费视频观看 | 美女被草漫画 | 丝瓜茄子绿巨人秋葵榴莲污 | 免费观看国产大片资源视频 | 四虎院影永久在线观看 | 欧美久久综合网 | 国产成人久视频免费 | 韩国最新理论片奇忧影院 | 午夜国产小视频 | 女人和男人搞鸡 | 短篇最污的乱淫伦小说全集 | 色综合色狠狠天天久久婷婷基地 | 精品国产国偷自产在线观看 | 翁熄性放纵交换300章 | 被夫上司侵犯了中文字幕 | 果冻传媒天美传媒在线小视频播放 | 国产精品自在线 | 久久学生精品国产自在拍 | 久久re视频精品538在线 | 4虎tv | 91对白在线| 久久这里只有精品国产精品99 | 午夜毛片在线观看 | 青山葵在线 | 日韩性事 | 91porny丨首页 | 免费亚洲视频在线观看 | 亚洲高清在线天堂精品 | 日本视频免费在线观看 | 天美蜜桃精东乌鸦传媒 | www黄| 7777色鬼xxxx欧美色夫 | 女人把扒开给男人爽 | 国产亚洲精品看片在线观看 | 日本不卡高清免费v日本 | 亚洲国产美女精品久久 | 国内精品九一在线播放 | 日本护士撒尿xxxx18 | 美女的让男人桶爽免费看 |