redis 系列8 數據結構之整數集合

原文: redis 系列8 數據結構之整數集合

一.概述html

  整數集合(intset)是集合鍵的底層實現之一, 當一個集合只包含整數值元素,而且這個集合元素數量很少時, Redis就會使用整數集合做爲集合鍵的底層實現。下面建立一個只包含5個元素的集合鍵,而且集合中全部元素都是整數值,那麼這個集合鍵的底層實現就會是整數集合。 接着添加非整數值,集合鍵的底層實現就會是hashtable。redis

127.0.0.1:6379> sadd numbers 1 3 5 7 9 (integer) 5
127.0.0.1:6379> object encoding numbers "intset"
127.0.0.1:6379> sadd numbers 'one' (integer) 1
127.0.0.1:6379> object encoding numbers "hashtable"

 

二. 整數集合實現數組

  整數集合是Redis用於保存整數值的集合抽象數據結構,它能夠保存類型爲int16_t, int32_t, int64_t的整數值,而且保證集合中不會出現重複元素。數據集合定義以下:數據結構

// 每一個intset.h/intset結構表示一個整數集合
           typedef struct intset { //編碼方式
 uint32_t encoding; //集合包含的元素數量
 uint32_t length; //保存元素的數組
 int8_t contents[]; }intset;

  (1) contents數組是整數集合的底層實現,整數集合的每一個元素都是contents數組的一個數組項(item),各個項在數組中按值從小到大有序排列,而且數組中不包含重複項。以下面腳本:dom

127.0.0.1:6379> sadd record 5 3 4 5 6 0 (integer) 5
127.0.0.1:6379> smembers record 1) "0"
2) "3"
3) "4"
4) "5"
5) "6"

  (2) length屬性記錄了整數集合包含的元素數量,也便是contents數組的長度。雖然contents屬性聲明爲int8_t類型的數組,但實現上contents數組並不保存任何int8_t類型的值,contents數組的真正類型取決於encoding屬性的值。函數

  a. 若是encoding 屬性的值爲intset_enc_int16,那麼contents就是一個int16_t類型的數組,數組裏的每一個項都是一個int16_t類型的整數值(範圍在 -32768 ~ 32767)。以下圖encoding屬性的值有5個整數型,根據這些整數值得出encoding爲int16_t類型。ui

  b. 若是encoding屬性的值爲intset_enc_int32, 那麼數組裏每一個項就是一個int32_t類型的整數值(範圍在 -2147483648 ~ 2147483647)。還有encoding屬性的值爲intset_enc_int64類型的,數組裏每一個項取取值範圍更大。編碼

  須要注意的是:假設contents數組保存的值爲2147483647, 1,2,3 四個整數值。 但只有第一個整數值須要用int32_t類型來保存,而其它三個值能夠用int16_t類型來保存。不過根據整數集合的升級規則,當一個底層的int16_t數組的整數集合添加一個int64_t類型的整數值時,整數集合中全部元素都會被轉換成int64_t類型。 因此contents數組保存的整數值都是int64_t類型的。spa

 

三. 升級3d

   當咱們要將一個新元素添加到整數集合裏面,而且新元素的類型比整數集合現有全部元素的類型都要長時,整數集合須要先進行升級,而後才能將新元素添加到整數集合中。假設:集合中包含三個int16_t類型的元素,值分別是1,2,3 。由於每一個元素都佔用16位空間,因此整數集合底層數組的大小 爲3 * 16 =48位。現將int32_t的數值65535添加進去,這裏程序須要對整數集合進行升級。

  升級整數集合並添加新元素共分三步進行:

    (1) 根據新元素的類型,擴展整數集合底層數組的空間大小 ,併爲新元素分配空間。分配空間後,如今整數集合4個元素的底層數組大小爲4 *32 =128位, 此時前三位仍是48位空間,以下圖所示:

    (2) 將底層數組現有的全部元素都轉換成與新元素相同的類型(須要從int16_t 轉成int32_t所需的空間) ,轉換後元素位置有序不變,以下圖所示:

    (3) 將新元素添加到底層數組裏面,以下圖所示:

四. 升級的好處

  4.1 提高靈活性

    爲了不類型錯誤,一般不會將兩種不一樣類型的值放在同一個數據結構裏面,經過升級處理能夠隨意地將int16_t, int32_t, , int64_t 類型的整數添加到集合中,而沒必要擔憂出現類型錯誤。

       4.2 節約內存

    要讓一個數組能夠同時保存int16_t,int32_t, , int64_t三種類型的值,最簡單的作法就是直接使用int64_t類型的數組做爲整數集合的底層實現,不過這樣浪費內存空間。

 

五.   降級

  整數集合不支持降級操做,一旦對數組進行了升級,編碼就會一直保持升級後的狀態。即便集合裏只有一個須要使用int64_t類型的元素被刪除了,整數集合的編碼仍然會維持intset_enc_int64, 底層數組也仍然會是int64_t類型,以下圖所示:

 

六. 整數集合API

函數

做用

intsetNew

建立一個新的壓縮列表

intsetAdd

將給定元素添加到整數集合裏面

intsetRemove

從整數集合中移除給定元素

intsetFind

檢查給定值是否存在於集合

intsetRandom

從整數集合中隨機返回一個元素

intsetGet

取出底層數組在給定索引上的元素

intsetLen

返回整數集合包含的元素個數

intsetBloblen

返回整數集合佔用的內存字節數

相關文章
相關標籤/搜索