【Redis】02底层数据结构-字典

介绍

字典又称为符号表(symbol table)、关联数组(associative array)或映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构。例如:redis中的所有key到value的映射,就是通过字典结构维护,还有hash类型的键值。
通过redis中的命令感受一下哈希键:

127.0.0.1:6379> HSET user name Mike 
(integer) 1
127.0.0.1:6379> HSET user passwd 123456
(integer) 1
127.0.0.1:6379> HSET user sex male
(integer) 1
127.0.0.1:6379> HLEN user       //user就是一个包含3个键值对的哈希键
(integer) 3
127.0.0.1:6379> HGETALL user
1) "name"
2) "Mike"
3) "passwd"
4) "123456"
5) "sex"
6) "male"

字典的实现

redis的字典是由哈希表实现的,一个哈希表有多个节点,每个节点保存一个键值对。

定义
//哈希表
typedef struct dictht { 
    //存放一个数组的地址,数组存放着哈希表节点dictEntry的地址。
    dictEntry **table; 
    //哈希表table的大小,初始化大小为4
    unsigned long size;     
    //用于将哈希值映射到table的位置索引。它的值总是等于(size-1)。
    unsigned long sizemask; 
    //记录哈希表已有的节点(键值对)数量
    unsigned long used;     
} dictht;
//哈希表的节点
typedef struct dictEntry {
    //key
    void *key;                 
     //value
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;                       
    //指向下一个hash节点,用来解决hash键冲突(collision)
    struct dictEntry *next;     
} dictEntry;

//字典
typedef struct dict {
    //指向dictType结构,dictType结构中包含自定义的函数,这些函数使得key和value能够存储任何类型的数据。
    dictType *type;
    //私有数据,保存着dictType结构中函数的参数。
    void *privdata;    
     //两张哈希表。
    dictht ht[2];
    //rehash的标记,rehashidx==-1,表示没在进行rehash
    long rehashidx;       
    //正在迭代的迭代器数量
    int iterators;     
} dict;

图示

image.png

rehash

  • 扩展或收缩
    • 扩展:ht[1]的大小为第一个大于等于ht[0].used * 2的 2n2n 。
    • 收缩:ht[1]的大小为第一个大于等于ht[0].used的 2n2n 。
  • 将所有的ht[0]上的节点rehash到ht[1]上。
  • 释放ht[0],将ht[1]设置为第0号表,并创建新的ht[1]。
  • 渐进式rehash
    • 字典结构dict中的rehashidx为-1时表示不进行rehash,当rehashidx值为0时,表示开始进行rehash。
    • 删除、更新、查找在ht[0]和ht[1]上都进行;新增只在ht[1]上操作;保证ht[0]上的数据只减不删。
    • 当rehash时进行完成时,将rehashidx置为-1,表示完成rehash。

hash冲突

  • 通过链接法(chaining)来解决冲突
  • dictEntry 节点组成的链表是个单向链表,没有指向链表表尾的指针, 所以为了速度考虑, 程序总是将新节点添加到链表的表头位置(复杂度为 O(1))

猜你喜欢

转载自www.cnblogs.com/wtb123456/p/12797986.html