redis 系列5 數據結構之字典(上)

一. 概述web

  字典又稱符號表(symbol table),關聯數組(associative array), 映射(map),是一種用於保存鍵值對(key-value pair)的抽象數據結構。在字典中,一個key和一個value進行關聯稱爲鍵值對。在字典中每一個鍵都是惟一的,程序能夠在字典中根據鍵查找關聯的值,或經過鍵更新刪除值等操做。在C語言中並無內置這種數據結構,所以Redis構建了本身的字典實現。在Redis中應用普遍, 對數據庫的增,刪,查,改 都是構建在對字典的操做之上的。redis

-- 例1
127.0.0.1:6379> set msg "hello world"
OK
127.0.0.1:6379> get msg
"hello world"

  在例1中數據庫建立一個鍵爲"msg",值爲"hello world"的鍵值對,這個鍵值對就是保存在數據庫的字典裏面。字典仍是哈希鍵的底層實現之一,當哈希鍵包含的鍵值對比較多,或者鍵值對中的元素都是比較長的字符串時,Redis就會使用字典做爲哈希鍵的底層實現。mongodb

-- 例2: website是一個包含3個鍵值對的哈希鍵(也叫哈希表),哈希鍵(key)爲 website,哈希鍵的節點鍵是:數據庫名字,哈希鍵的節點值是:網址
    127.0.0.1:6379> hmset website redis "Redis.io" mariadb "mariadb.org" mongodb "mongodb.org" 
OK
127.0.0.1:6379> hlen website
(integer) 3
127.0.0.1:6379> hgetall website
1) "redis"
2) "Redis.io"
3) "mariadb"
4) "mariadb.org"
5) "mongodb"
6) "mongodb.org"

  在例2中,website哈希鍵的底層實現就是一個字典。字典中包含了3個鍵值對。字典除了用來實現數據庫和哈希鍵之處,Redis在後續學習中會看到各類不一樣應用。數據庫

 

二. 字典的實現數組

   一個哈希(鍵)表裏面能夠有多個哈希節點(key-vlaue), 每一個哈希節點保存了字典的一個鍵值對。下面三個小節將分別介紹Redis的哈希表,哈希表節點,以及字典的實現。數據結構

  2.1 哈希表定義ide

typedef struct dictht
      {
         //哈希表數組,C語言中,*號是爲了代表該變量爲指針,有幾個* 號就至關因而幾級指針,這裏是二級指針,理解爲指向指針的指針
         dictEntry **table;

         //哈希表大小
         unsigned long size;

         //哈希表大小掩碼,用於計算索引值
         unsigned long sizemask;

         //該哈希已有節點的數量
          unsigned long used;

      }dictht;

    上面table屬性是一個數組,數組中的每一個元素都是一個指向dict.h/dictEntry結構的指針,每一個dictEntry結構保存着一個鍵值對,size屬性記錄了哈希表的大小,也是table數組的大小,而used屬性則記錄哈希表目前已有節點(鍵值對)的數量。sizemask屬性的值老是等於 size-1(從0開始),這個屬性和哈希值一塊兒決定一個鍵應該被放到table數組的哪一個索引上面。函數

    例如:上面例2中,哈希表叫website,  對應一個dictht 結構,鍵值對table數組值是[3], 哈希表size值是3,索引值sizemask值是2,已有節點數量used值是3。學習

  2.2 哈希表節點定義 (鍵值對)ui

//哈希表節點定義dictEntry結構表示,每一個dictEntry結構都保存着一個鍵值對。
    typedef struct dictEntry
      {
         //
         void *key;
         //
         union{
           void *val;
            uint64_tu64;
            int64_ts64;
            }v;

         // 指向下個哈希表節點,造成鏈表
         struct dictEntry *next;
      }dictEntry;

    上面dictEntry 結構中,key屬性保存着鍵值中的鍵,而v屬性則保存着鍵值對中的值,其中鍵值(v屬性)能夠是一個指針,或uint64_t整數,或int64_t整數。 next屬性是指向另外一個哈希表節點的指針,這個指針能夠將多個哈希值相同的鍵值對鏈接在一塊兒,解決鍵衝突問題。

    下圖經過next指針,將兩個索引值相同(索引是2)的鍵k1和k0鏈接在一塊兒。

  2.3 字典定義

// Redis中的字典由dict.h/dict結構表示
          typedef struct dict
      {
         //類型特定函數
         void *type;

         //私有數據
         void *privdata;

         //哈希表
         dictht ht[2];

         // rehash 索引
         int  trehashidx; 
      }dict;

     type屬性和privdata屬性是針對不一樣類型的鍵值對,爲建立多態字典而設置的,type屬性是一個指向dictType結構的指針,每一個dictType用於操做特定類型鍵值對的函數,Redis會爲用途不一樣的字典設置不一樣的類型特定函數。 而privdata屬性則保存了須要傳給給那些類型特定函數的可選參數。

 typedef struct dictType
      {
         //計算哈希值的函數 
        unsigned int  (*hashFunction) (const void *key);

         //複製鍵的函數
         void *(*keyDup) (void *privdata,const void *key);

         //複製值的函數
         void *(*keyDup) (void *privdata,const void *obj);

          //複製值的函數
         void *(*keyCompare) (void *privdata,const void *key1, const void *key2);

         //銷燬鍵的函數
         void (*keyDestructor) (void *privdata, void *key);

         //銷燬值的函數
         void (*keyDestructor) (void *privdata, void *obj);
      }dictType;
View Code

    ht屬性是一個包含兩個項的數組,數組中的每一個項都是一個dictht哈希表, 通常狀況下,字典只使用ht[0] 哈希表, ht[1]哈希表只會對ht[0] 哈希表進行rehash時使用。另外一個和rehash有關的屬性是rehashidx,它記錄了rehash目前的進度,若是目前沒有進行rehash,值爲-1。下面圖是一個沒有進行rehash的字典。

  rehash是指漸進式的哈希,一張表是舊錶,一張表是新表,當hashtable的大小須要動態改變的時候,舊錶中的元素就往新開闢的新表中遷移,當下一次變更大小,當前的新表又變成了舊錶,以此達到資源的複用和效率的提高。

相關文章
相關標籤/搜索