Redis的數據類型之有序集合 · zset

書接上回

上一篇我們學習的 set集合這一數據類型。其內部是由insethashtable這種兩種數據結構編碼的。
如果不記得了,那就來坐穿梭機回去看看吧。 開始穿梭

接下來,我們繼續學習一個新的數據類型, 有序集合. zset.

zset簡介

zset ,中文名字叫 有序集合. 序這個字,在Redis的實現是 score 字段。我們先不急這個字段,後面會介紹。

Redis中有序的數據類型,還有一個就是我們前面學習的 list 了。 它們還都可以獲得某一定範圍內的元素。

zset 的優點是: list 通過鏈表實現,在兩端操作數據都很方便. 但是操作中間的數據就比較慢了。 zset 是用 hashtableskiplist 來實現的。即使是操作中間數據,速度也很快. 時間複雜度爲: O(logN)

zset 的缺點就是: 就是比較耗費內存。

zset類型的應用場景

  • 存儲學生成績快速做成績排名功能。
  • 排行榜,比如:列出某用戶當前的全球排名, 比賽中勝場數排名。
  • 帶權重的消息隊列功能

zset的基本命令

zadd

  • 語法

ZADD key [NX|XX] [CH] [INCR] score member [score member ...]

  • 解釋

member添加有序集合中.

如果member存在,會更新memberscore值。

  • NX 表示存在相同的member就會設置失敗,NX的作用就是 新增member,不會修改Member

  • XX 表示不存在相同的member就會設置失敗。所以: XX 總是更新元素。不會新增元素

  • CH(change): 返回修改的元素個數。更改的元素是添加的新元素以及已爲其更新分數的現有元素。因此,命令行中指定的具有與過去相同分數的元素將不計算在內。注意:通常,ZADD的返回值僅計算添加的新元素的數量。

  • INCR: 指定此選項後,ZADD的行爲類似於ZINCRBY。在此模式下只能指定一對得分元素。

  • 演示

## 設置一個元素
127.0.0.1:6379> ZADD k67 1 m1
(integer) 1
## 設置多個元素
127.0.0.1:6379> ZADD k67 2 m2 3 m3 4 m4 5 m5
(integer) 4

## 演示 NX 語義,只能新增.
127.0.0.1:6379> ZADD k67 NX 5 m5
(integer) 0
127.0.0.1:6379> ZADD k67 NX 6 m6
(integer) 1
127.0.0.1:6379> ZADD k67 NX 6 m6
(integer) 0

## 演示 XX 語言,只能修改
127.0.0.1:6379> ZADD k67 XX 7 m7
(integer) 0
127.0.0.1:6379> ZADD k67 7 m7
(integer) 1
## 進行修改,注意返回值. 如果要返回個數,則加 CH
127.0.0.1:6379> ZADD k67 XX 7 m7
(integer) 0
127.0.0.1:6379> ZADD k67 XX 77 m7
(integer) 0

## 演示CH, 返回修改的個數
127.0.0.1:6379> ZADD k67 CH 8 m8 9 m9 10 m10
(integer) 3
127.0.0.1:6379> ZADD k67 CH 8 m8 999 m9 10 m10
(integer) 1

## 演示INCR, 增長
127.0.0.1:6379> ZADD k67 11 m11
(integer) 1
## 此時 score 表示的是步長
127.0.0.1:6379> ZADD k67 INCR 10 m11
"21"

## 查看設置的值。
127.0.0.1:6379> ZRANGE k67 0 -1 WITHSCORES
 1) "m1"
 2) "1"
 3) "m2"
 4) "2"
 5) "m3"
 6) "3"
 7) "m4"
 8) "4"
 9) "m5"
10) "5"
11) "m6"
12) "6"
13) "m8"
14) "8"
15) "m10"
16) "10"
17) "m11"
18) "21"
19) "m7"
20) "77"
21) "m9"
22) "999"

zscore

  • 語法

ZSCORE key member

  • 解釋

zset score

查看對應元素的score

* 當`key`不存在或者`member`不存在的時候,返回`(nil)`

返回score的值。

  • 演示
# 驗證k68不存在的時候,返回nil
127.0.0.1:6379> ZSCORE k68 m1
(nil)
127.0.0.1:6379> ZADD k68 1 m1
(integer) 1
# 返回元素的score值
127.0.0.1:6379> ZSCORE k68 m1
"1"
# 驗證 member 不存在的時候,返回
127.0.0.1:6379> ZSCORE k68 m2
(nil)

zincrby

  • 語法

ZINCRBY key increment member

  • 解釋

zset increment by
* increment: 步長。
* member: 指定的成員

爲有序集合key的成員memberscore值加上 increment

如果key或者member不存在, 則新增一個元素. 相當於 zadd.

  • 演示
# 插入一個不存在的key。
127.0.0.1:6379> ZINCRBY k69 10 m1
"10"
127.0.0.1:6379> ZRANGE k69 0 -1 WITHSCORES
1) "m1"
2) "10"
#累加
127.0.0.1:6379> ZINCRBY k69 10 m1
"20"
127.0.0.1:6379> ZRANGE k69 0 -1 WITHSCORES
1) "m1"
2) "20"
# 累加一個負數
127.0.0.1:6379> ZINCRBY k69 -30 m1
"-10"
127.0.0.1:6379> ZRANGE k69 0 -1 WITHSCORES
1) "m1"
2) "-10"

zcard

  • 語法

ZCARD key

  • 解釋

返回 有序集合的key中的元素個數.即member的個數。
不存在的時候,返回0.

  • 演示
# 返回member的個數
127.0.0.1:6379> ZADD k70 1 m1 2 m2 3 m3
(integer) 3
127.0.0.1:6379> ZCARD k70
(integer) 3
127.0.0.1:6379> ZADD k70 4 m4 5 m5
(integer) 2
127.0.0.1:6379> ZCARD k70
(integer) 5
# 不存在的時候,返回0
127.0.0.1:6379> EXISTS k70_1
(integer) 0
127.0.0.1:6379> ZCARD k70_1
(integer) 0

zcount

  • 語法

ZCOUNT key min max

  • 解釋

返回 score值在minmax 之間的元素的個數。包括等於 minmax

  • 演示
127.0.0.1:6379> ZADD k71 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
127.0.0.1:6379> ZCOUNT k71 2 5
(integer) 4
#不存在的key或者不在區間內時,返回0
127.0.0.1:6379> zcount k71_1 0 10
(integer) 0
127.0.0.1:6379> zcount k71 11 12
(integer) 0
127.0.0.1:6379> zcount k71 12 11
(integer) 0
127.0.0.1:6379> 

zrange

  • 語法

ZRANGE key start stop [WITHSCORES]

  • 解釋

這個命令我們已經用過,就是返回指定開始結束位置上的元素. 從 0 開始。

  • 演示
127.0.0.1:6379> ZRANGE k72 1 3
1) "m2"
2) "m3"
3) "m4"
127.0.0.1:6379> ZRANGE k72 1 3 WITHSCORES
1) "m2"
2) "2"
3) "m3"
4) "3"
5) "m4"
6) "4"

zrevrange

  • 語法

ZREVRANGE key start stop [WITHSCORES]

  • 解釋

返回有序集合中指定區間的成員。
其中成員的位置按 score 值遞減(從大到小)來排列。 具有相同 score 值的成員按字典序的逆序(reverse lexicographical order)排列。

  • 演示
127.0.0.1:6379> ZADD k73 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
# 使用 zrange 正序返回數據
127.0.0.1:6379> ZRANGE k73 0 3 WITHSCORES
1) "m1"
2) "1"
3) "m2"
4) "2"
5) "m3"
6) "3"
7) "m4"
8) "4"

# 使用 zrevrange 倒序返回數據
127.0.0.1:6379> ZREVRANGE k73 0 3 WITHSCORES
1) "m10\x11"
2) "10"
3) "m9"
4) "9"
5) "m8"
6) "8"
7) "m7"
8) "7"

zrangebyscore

  • 語法

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

  • 解釋

zset range by score

類似 zrange, 不過是按照 score 的值進行排序的。

[LIMIT offset count], 是從offset開始,返回count個。

  • 演示
# 返回 score值在 [9,10]之間的member。
127.0.0.1:6379> ZADD k74 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
127.0.0.1:6379> ZRANGEBYSCORE k74 9 10 WITHSCORES
1) "m9"
2) "9"
3) "m10\x11"
4) "10"

# 從第2個(區間內索引爲1)開始,返回1個元素
127.0.0.1:6379> ZRANGEBYSCORE k74 9 10 WITHSCORES LIMIT 1 1
1) "m10\x11"
2) "10"

zrevrangebyscore

  • 語法

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

  • 解釋

返回有序集 key 中, score 值介於 maxmin 之間(默認包括等於 maxmin )的所有的成員。有序集成員按 score 值遞減(從大到小)的次序排列。

注意各個參數的位置哦。這裏和 zrevrange 的參數不一樣。

  • 演示
127.0.0.1:6379> ZADD k75 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
127.0.0.1:6379> ZREVRANGEBYSCORE k75 8 6 WITHSCORES 
1) "m8"
2) "8"
3) "m7"
4) "7"
5) "m6"
6) "6"
127.0.0.1:6379> ZREVRANGEBYSCORE k75 8 6 WITHSCORES  LIMIT 1  1
1) "m7"
2) "7"

zrank

  • 語法

ZRANK key member

  • 解釋

返回有序集 key 中成員 member 的排名。其中有序集成員按 score 值遞增(從小到大)順序排列

  • 演示
127.0.0.1:6379> ZADD k76 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
127.0.0.1:6379> zrank k76 m4
(integer) 3
127.0.0.1:6379> zrank k76 m10
(integer) 9

zrevrank

  • 語法

ZREVRANK key member

  • 解釋

返回有序集 key 中成員 member 的排名。其中有序集成員按 score 值遞減(從大到小)排序。

排名以 0 爲底,也就是說, score 值最大的成員排名爲 0

  • 演示
127.0.0.1:6379> ZADD k77 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
127.0.0.1:6379> ZREVRANK k77 m10
(integer) 0
127.0.0.1:6379> ZREVRANK k77 m4
(integer) 6

zrem

  • 語法

ZREM key member [member ...]

  • 解釋

zset remove

移除有序集 key 中的一個或多個成員,不存在的成員將被忽略。

key 存在但不是有序集類型時,返回一個錯誤。

  • 演示
127.0.0.1:6379> ZADD k78 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
# 刪除m2,m3,m4
127.0.0.1:6379> ZREM k78 m2 m3 m4
(integer) 3
127.0.0.1:6379> ZRANGE k78 0 -1 WITHSCORES
 1) "m1"
 2) "1"
 3) "m5"
 4) "5"
 5) "m6"
 6) "6"
 7) "m7"
 8) "7"
 9) "m8"
10) "8"
11) "m9"
12) "9"
13) "m10"
14) "10"

zremrangebyrank

  • 語法

ZREMRANGEBYRANK key start stop

  • 解釋

移除有序集 key 中,指定排名(rank)區間內的所有成員。

區間分別以下標參數 startstop 指出,包含 startstop 在內。

  • 演示
127.0.0.1:6379> ZADD k79 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
# 刪除排名第2到排名第4的member
127.0.0.1:6379> ZREMRANGEBYRANK k79 1 3
(integer) 3
127.0.0.1:6379> ZRANGE k79 0 -1 WITHSCORES
 1) "m1"
 2) "1"
 3) "m5"
 4) "5"
 5) "m6"
 6) "6"
 7) "m7"
 8) "7"
 9) "m8"
10) "8"
11) "m9"
12) "9"
13) "m10"
14) "10"

zremrangebyscore

  • 語法

ZREMRANGEBYSCORE key min max

  • 解釋

移除有序集 key 中,所有 score 值介於 minmax 之間(包括等於 minmax )的成員。

  • 演示
127.0.0.1:6379> ZADD k80 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
# 刪除 score>=1 and score <=9 的元素
127.0.0.1:6379> ZREMRANGEBYSCORE k80 1 9
(integer) 9
127.0.0.1:6379> zrange k80 0 -1  WITHSCORES
1) "m10"
2) "10"

zrangebylex

  • 語法

ZRANGEBYLEX key min max [LIMIT offset count]

  • 解釋

當有序集合的所有成員都具有相同的分值時, 有序集合的元素會根據成員的字典序(lexicographical ordering)來進行排序, 而這個命令則可以返回給定的有序集合鍵 key 中, 值介於 minmax 之間的成員。

注意:

合法的 minmax 參數必須包含 ( 或者 [ , 其中 ( 表示開區間(指定的值不會被包含在範圍之內), 而 [ 則表示閉區間(指定的值會被包含在範圍之內)。

特殊值 +-min 參數以及 max 參數中具有特殊的意義, 其中 + 表示正無限, 而 - 表示負無限。 因此, 向一個所有成員的分值都相同的有序集合發送命令 ZRANGEBYLEX <zset> - +, 命令將返回有序集合中的所有元素

lex:
表示如果score相等,則按照member的字典順序排序。
此外這個命令, 比如ZRANGBYSCORE稍微強大一點兒. 可以指定區間範圍, 當只知道member,不知道score的時候,可以是使用帶有 lex 的命令。

  • 演示
127.0.0.1:6379> zadd k81 1 a 2 b 3 c 4 d 5 f 6 g
(integer) 6
# 返回 score值在a的score值和c的score值之間的member
# 即: score> Score(a) && score <= Score(c)
127.0.0.1:6379> ZRANGEBYLEX k81 (a  [c 
1) "b"
2) "c"

# 返回 小於等於c的Score值的元素
127.0.0.1:6379> ZRANGEBYLEX k81 -  [c 
1) "a"
2) "b"
3) "c"

# 返回所有元素
127.0.0.1:6379> ZRANGEBYLEX k81 - + 
1) "a"
2) "b"
3) "c"
4) "d"
5) "f"
6) "g"

zlexcount

  • 語法

ZLEXCOUNT key min max

  • 解釋

對於一個所有成員的分值都相同的有序集合鍵 key 來說, 這個命令會返回該集合中, 成員介於 minmax 範圍內的元素數量。

  • 演示
127.0.0.1:6379> zadd k82 1 a 2 b 3 c 4 d 5 f 6 g
(integer) 6
127.0.0.1:6379> ZLEXCOUNT k82 2 5
(error) ERR min or max not valid string range item
127.0.0.1:6379> ZLEXCOUNT k82 a b
# 大於Score(a),小於等於Score(b)的member,只有b.
127.0.0.1:6379> ZLEXCOUNT k82 (a [b
(integer) 1
# 大於Score(a),小於等於Score(d)的member,有b.c.d,三個
127.0.0.1:6379> ZLEXCOUNT k82 (a [d
(integer) 3

zremrangebylex

  • 語法

ZREMRANGEBYLEX key min max

  • 解釋

對於一個所有成員的分值都相同的有序集合鍵 key 來說, 這個命令會移除該集合中, 成員介於 minmax 範圍內的所有元素。

  • 演示
127.0.0.1:6379> zadd k83 1 a 2 b 3 c 4 d 5 f 6 g
(integer) 6
# 刪除 score值在 (Score(a),Score(c)] 之間的member
127.0.0.1:6379> ZREMRANGEBYLEX k83 (a [c
(integer) 2
# 刪除了,b,c
127.0.0.1:6379> zrange k83 0 -1
1) "a"
2) "d"
3) "f"
4) "g"

zscan

  • 語法

ZSCAN key cursor [MATCH pattern] [COUNT count]

  • 解釋

這是一個查詢命令。 同 SCAN 命令. 可以參考這篇文章 010-其他命令

SCAN 命令是一個基於遊標的迭代器(cursor based iterator): SCAN 命令每次被調用之後, 都會向用戶返回一個新的遊標, 用戶在下次迭代時需要使用這個新遊標作爲 SCAN 命令的遊標參數, 以此來延續之前的迭代過程。

  • 演示
127.0.0.1:6379> ZADD k84 1 m1 2 m2 3 m3 4 m4 5 m5 6 m6 7 m7 8 m8 9 m9 10 m10
(integer) 10
127.0.0.1:6379> zscan k84 0 MATCH m* COUNT 3
1) "0"
2)  1) "m1"
    2) "1"
    3) "m2"
    4) "2"
    5) "m3"
    6) "3"
    7) "m4"
    8) "4"
    9) "m5"
   10) "5"
   11) "m6"
   12) "6"
   13) "m7"
   14) "7"
   15) "m8"
   16) "8"
   17) "m9"
   18) "9"
   19) "m10"
   20) "10"

zunionstore

  • 語法

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]

  • 解釋
    計算給定的一個或多個有序集合的並集,其中給定 key 的數量必須以 numkeys 參數指定,並將該並集(結果集)儲存到 destination 。
    如果key相同的時候,對應的score值會相加。

    • WEIGHTS: 使用 WEIGHTS 選項,你可以爲 每個 給定有序集 分別 指定一個乘法因子(multiplication factor),每個給定有序集的所有成員的 score 值在傳遞給聚合函數(aggregation function)之前都要先乘以該有序集的因子。
    • AGGREGATE: 使用 AGGREGATE 選項,你可以指定並集的結果集的聚合方式。
      默認使用的參數 SUM ,可以將所有集合中某個成員的 score 值之 和 作爲結果集中該成員的 score 值;使用參數 MIN ,可以將所有集合中某個成員的 最小 score 值作爲結果集中該成員的 score 值;而參數 MAX 則是將所有集合中某個成員的 最大 score 值作爲結果集中該成員的 score 值。
  • 演示

127.0.0.1:6379> ZADD k85_1 1 m1 2 m2 3 m3
(integer) 3
127.0.0.1:6379> ZADD k85_2 1 m1 4 m4 5 m5
(integer) 3
127.0.0.1:6379> ZUNIONSTORE k85 2 k85_1 k85_2
(integer) 5
127.0.0.1:6379> zrange k85 0 -1 WITHSCORES
 1) "m1"
 2) "2"
 3) "m2"
 4) "2"
 5) "m3"
 6) "3"
 7) "m4"
 8) "4"
 9) "m5"
10) "5"

# 演示 Weights參數: WEIGHTS 2 3
# 指: 第一個zset的所有元素 *2 ,第二個有序集合中的元素 *3
127.0.0.1:6379> ZUNIONSTORE k85 2 k85_1 k85_2 WEIGHTS 2 3
(integer) 5
127.0.0.1:6379> ZRANGE k85 0 -1 WITHSCORES
 1) "m2"
 2) "4"
 3) "m1"
 4) "5"
 5) "m3"
 6) "6"
 7) "m4"
 8) "12"
 9) "m5"
10) "15"
# 演示 Weights參數: WEIGHTS 2 4
# 指: 第一個zset的所有元素 *2 ,第二個有序集合中的元素 *3
127.0.0.1:6379> ZUNIONSTORE k85 2 k85_1 k85_2 WEIGHTS 2 4
(integer) 5
127.0.0.1:6379> ZRANGE k85 0 -1 WITHSCORES
 1) "m2"
 2) "4"
 3) "m1"
 4) "6"
 5) "m3"
 6) "6"
 7) "m4"
 8) "16"
 9) "m5"
10) "20"

zinterstore

  • 語法

  • 解釋

計算給定的一個或多個有序集的交集,其中給定 key 的數量必須以 numkeys 參數指定,並將該交集(結果集)儲存到 destination

默認情況下,結果集中某個成員的 score 值是所有給定集下該成員 score 值之和.

  • 演示
127.0.0.1:6379> zadd k86_1 1 m1 2 m2 3 m3 4 m4
(integer) 4
127.0.0.1:6379> ZADD k86_2 20 m2 30 m3 50 m5
(integer) 3
127.0.0.1:6379> ZINTERSTORE k86 2 k86_1 k86_2 
(integer) 2
# 取交集(默認相加)
127.0.0.1:6379> zrange k86 0 -1 WITHSCORES
1) "m2"
2) "22"
3) "m3"
4) "33"

# WEIGTHS 參數和上面的 ZUNIONSTORE命令一樣.
# 這裏演示一下, AGGREGATE參數
# 默認使用的是SUM. 就是本命令中上面的例子了.
# 下面演示MIN 和 MAX
127.0.0.1:6379> ZINTERSTORE k86 2 k86_1 k86_2 AGGREGATE MIN
(integer) 2
127.0.0.1:6379> ZRANGE k86 0 -1 WITHSCORES
1) "m2"
2) "2"
3) "m3"
4) "3"

127.0.0.1:6379> ZINTERSTORE k86 2 k86_1 k86_2 AGGREGATE MAX
(integer) 2
127.0.0.1:6379> ZRANGE k86 0 -1 WITHSCORES
1) "m2"
2) "20"
3) "m3"
4) "30"

zset的內部結構

這裏我們主要看skiplist,如果忘記了hashtable,就看着這篇文章

我們從命令zadd入手,找到zsetadd通用方法zaddGenericCommand(c,ZADD_NONE);來看一下。省略了部分代碼。

...
if (server.zset_max_ziplist_entries == 0 ||
            server.zset_max_ziplist_value < sdslen(c->argv[scoreidx+1]->ptr))
{
    /// 創建 OBJ_ENCODING_SKIPLIST 編碼的結構
    zobj = createZsetObject();
} else {
    /// 創建 OBJ_ZSET 編碼的結構
    zobj = createZsetZiplistObject();
}
....

來看一下 createZsetObject()方法的實現,就再清晰不過了。

/// 創建 Zset 對象。
robj *createZsetObject(void) {
    zset *zs = zmalloc(sizeof(*zs));
    robj *o;

    zs->dict = dictCreate(&zsetDictType, NULL);
    zs->zsl = zslCreate();
    o = createObject(OBJ_ZSET, zs);
    o->encoding = OBJ_ENCODING_SKIPLIST;
    return o;
}

到這裏,就是我們和 zset這種數據類型的初次深入見面了。 我們先看下 zset 這種結構體的定義。

/// 有序集合的結構定義
typedef struct zset {
    /// 字典,鍵爲成員,值爲score
    /// 用於支持 O(1) 複雜度的按成員分值操作。
    dict *dict;
    /// 跳躍表,按分值排序成員
    /// 用於支持平均複雜度爲 O(logN)的按分值定位成員以及範圍的操作。
    zskiplist *zsl;
} zset;

dict前面已經看過了,這裏來看下zskiplist

skiplist

/// 跳躍表
typedef struct zskiplist {
    /// 表頭,表尾
    struct zskiplistNode *header, *tail;
    /// 表中節點的數量
    unsigned long length;
    /// 表中層數最大的節點的層數
    int level;
} zskiplist;

typedef struct zskiplistNode {
    sds ele;
    /// 分數
    double score;
    /// 後退的指針
    struct zskiplistNode *backward;
    /// 層
    struct zskiplistLevel {
        /// 前進指針
        struct zskiplistNode *forward;
        /// 跨度
        unsigned long span;
    } level[];
} zskiplistNode;

總結

  • 本章是一個新的常用數據類型, ZSET 有序集合。底層的數據結構是使用的是 skipListhashtable . 關於Skiplist的初步瞭解文章穿梭機Redisskiplist的實現源碼解讀(請期待,已經安排上了)
  • 然後簡單介紹了 Redis ZSET數據類型的基礎使用場景. 關鍵字有 有序排名權重等.
  • ZSET20 個常有命令。 後面我會針對這 20 個命令的實現進行簡單的分享.
  • 然後簡單的看了一下Redis中的數據結構的實現,還是那句話,Redis的數據結構是動態編碼的, ZSET是有hashtableskiplist 實現的。 skiplist 是一個非常高效的數據結構,增刪查的效率都是 O(logN). 實現原理可以參考這篇文章直通車,裏面有幾種流行的語言的實現,可以針對自己擅長的語言進行查看。

最後

希望和你成爲朋友!我們一起學習~
最新文章盡在公衆號【方家小白】,期待和你相逢在【方家小白】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章