redis--字典

字典

字典,又称关联数组或映射,是一种用于保存键值对的抽象数据结构。在字典中,一个键key和一个值value进行关联;字典中的每个键都是独一无二的。

字典的实现

redis的字典使用哈希表作为底层实现,一个哈希表可以有很多节点,而每个节点就保存了字典中的一个键值对。

哈希表

定义结构如下:

typedef struct dictht {
    //哈希表数组
    dictEntry **table;
    //哈希表大小
    unsigned long size;
    //哈希表大小掩码,用于计算索引值
    unsigned long sizemask
    //该哈希表已有的节点数量
    unsigned long used;
}dictht;

结构示意图如下:

哈希表

哈希表节点

哈希表节点使用dictEntry结构表示,每个节点都保存着一个键值对:

typedef struct dictEntry {
    //键
    void *key;
    //值,可以是一个指针,uint64_t整数,int64_t整数
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    }v;
    //指向下一个哈希表节点,形成链表
    struct dictEntry *next;
}dictEntry;

结构图如下:

哈希表节点

字典

redis中的字典结构如下:

typedef struct dict {
    //类型特定函数
    dictType *type;
   //私有数据
   void *privdata;
   //哈希表
   dictht ht[2];
   //rehash索引,不进行rehash时,值为-1
   int trehashidx;
}
  • type属性是一个指向dictType结构的指针,每个dictType保存了一组用于操作特定类型键值对的函数,redis会为用途不同的字典设置不同类型特定函数。
  • privdata属性,则保存了需要传递给那些类型特定函数的可选参数。
typedef struct dicType {
    //计算哈希值得函数
    unsigned int (*hashFunction) (const void *key);
    //复制键的函数
    void *(*keyDup) (void * privdata,const void *key);
    //复制值得函数
    void *(*valDup) (void *privdata,const void *obj);
    //对比键的函数
    int (*keyCompare) (void *privdata,const void *key1,const void key2)
    //销毁键的函数
    int (*keyDestructor) (void *privdata,void *key);
    //销毁值得函数
    void (*valDestructor) (void *privdata,void *obj);
}

普通状态下的字典如图所示:

在这里插入图片描述

ht是包含两个项的数组,每个项都是一个哈希表,字典只用ht[0]哈希表,ht[1]哈希表只会在对ht[0]哈希表进行rehash时使用。当两个及以上的键值对分配到了哈希数组中的同一个索引上,成为冲突,通过单链表的形式解决

哈希算法

当要将一个新的键值对添加到字典里时,程序需要先根据键值对的键计算出哈希值和索引值,然后再根据索引值,将包含新键值对的哈希表节点放到哈希表数组的指定索引上面。

redis使用MurmurHah2算法来计算哈希值。

新节点总是在已有节点的前边。

rehash

随着操作的不断执行,哈希表的键值对会增加或者减少,为了让负载因子维持在合理的范围内,哈希表需要扩展或者收缩。

  • 步骤如下:
    • 为字典的ht[1]哈希表分配空间,这个空间取决于要执行的操作,以及ht[0]当前包含的键值对数量。
      • 如果是执行扩展操作,那么ht[1]的大小为:ht [0].used * 2n + 1
      • 如果执行的是收缩操作,那么ht[1]的大小为:ht [0].used * 2n
    • 将保存在ht[0]中ed所有键值对rehash到ht[1]中,rehash指的是重新计算哈希值和索引,然后将键值对放到哈希表指定的位置上。
    • 当ht[0]迁移完之后,释放ht[0],将ht[1]的值设为ht[0],并在ht[1]上创建一个空的哈希表,为下一次rehash做准备。
渐进式rehash

rehash操作不是一次性,集中式的完成,而是分多次渐进式的完成的。在rehash期间,每对字典的添加,删除,查找或者更新操作时,都会进行rehash操作;在渐进式rehash期间,新添加的键值对一律会添加到ht[1]中,而不对ht[0]进行操作。

字典api
函数作用时间复杂度
dictCreate创建一个新的字典O(1)
dictAdd将给定的键值对添加到字典中O(1)
dictReplace将给定的键值对添加到字典中,如果已经存在,那么用新的值取代原有的值。O(1)
dictFetchValue返回给定键的值O(1)
dictGetRandomKey从字典中随机返回一个键值对O(1)
dictDelete从字典中删除给定键所对应的键值对O(1)
dictRelease释放给定字典,以及字典中包含的所有键值对O(N) N为字典包含的键值对数量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值