首页 > 其他 > 详细

第四章 字典

时间:2021-02-22 00:05:19      阅读:16      评论:0      收藏:0      [点我收藏+]

在字典中,一个键(key)可以和一个值(value)进行关联(或者说将键映射为值),这些关联的键和值就称为键值对。

4.1 字典的实现

  Redis的字段使用哈希表作为底层实现。

  4.1.1 哈希表

typedef struct ditch{
    //哈希表数组
    dictEntry **table;
    
    //哈希表大小
    unsigned long size;

    //哈希表大小掩码,用于计算索引值,等于size-1
    unsigned long sizemask;

    //该哈希表已有节点的数量
   unsigned long used;

}dictht;

 

  table是一个数组,其中每个元素是指向一个哈希表节点的指针。

  size记录了table的大小。sizemask和哈希值一起决定一个键应该被放到table数组的哪个索引上。

技术分享图片

  4.1.2 哈希表节点

  每个dictEntry结构保存着一个键值对。其中值可以是一个指针,或者uint64_t整数,或者int64_t整数。next属性指向另一个哈希表节点的指针,这个指针可以将多个哈希值相同的键值对连接在一起,解决哈希冲突的问题。

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

}dictEntry;

 

  4.1.3 字典

  Redis中的字典结构:

typedef struct dict{
    //类型特定函数
    dictType *type;

    //私有数据
    void *privdata;

    //哈希表
    dicht ht[2];

    //rehash 索引,当rehash不在进行时,值为-1  
    int trehashidx;
}dict

 

  type和privdata是为了多态字典而设计的,其中type指向了一个dictType结构,里面定一个了一系列操作键值对的函数,而privdata存放了函数需要的入参。

typedef struct dictType{
    //计算哈希值的函数
    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);
  
    //销毁键的函数
    void (*keyDestructor)(void *privdata, void *key);

    //销毁值的函数
    void (*valDestructor)(void *privdata, void *obj);
}dictType;

 

  ht属性是一个包含两个项的数组,数组中的每个项都是一个dictht哈希表,一般情况下,字典只使用ht[0]哈希表,ht[1]哈希表只会在rehash时使用,rehashidx记录了rehash的进度。

技术分享图片

4.2 哈希算法

  先计算key的哈希值,根据哈希值和sizemask计算索引值。根据索引值将键存放到指定位置。

4.3 解决键冲突

  当有两个及以上的键被分到同一个索引上时,产生了哈希冲突,Redis的解决方法是链地址法,将冲突的部分排成链表。因为没有指向链表表尾的指针,出于速度考虑,最新插入的放在表头位置。

4.4 rehash

  1. 为ht[1]分配空间
    1. 如果是扩展操作,取第一个大于等于ht[0].used*2的2的n次方幂
    2. 如果是收缩操作,取第一个大于等于ht[0].used的2的n次方幂
  2. 将ht[0]中的键值对重新映射到ht[1]中
  3. 将ht[0]空间释放,将ht[1]设置为h[0],将ht[0]设置为ht[1],并在ht[1]处创建一个新的空白哈希表,为下次rehash做准备

4.5 渐进式rehash

  渐进是指当键值对太多的情况,并不会一次全部重新分配完。

  1. 为ht[1]分配空间,字典同是持有ht[0]和ht[1]两个哈希表
  2. 将rehashidx初始化为0
  3. 每次对字典执行增删改查操作时,程序还会额外将ht[0]表在rehashidx索引上所有的键值对rehash到ht[1]中,当操作完毕时,将rehashidx+1
  4. 最终,ht[0]的所有键值对全部迁移完,将rehashidx重置为-1

  在渐进rehash期间,新增的键值对,一律保存在ht[1]中。删改查则先在ht[0]中查找,未找到再去ht[1]中查找。

 

第四章 字典

原文:https://www.cnblogs.com/walker993/p/14425825.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!