Hash字典

数据结构

凡是Hash字典,首先得有一个数组,这个数组是用来存储<Key, Value>对中的Value。
<Key, Value>对中的Key,是用来计算Value在数组中的下标位置。
一般的做法是,将Key通过特定的Hash算法得到一个整数值,然后将这个整数值与数组长度求余,计算的结果就是这个Value在数组中的位置。
然而当出现Hash冲突,也就是不同的Key得到相同的Hash值的时候,不同的Value将会保存到数组中的同一个位置。那么这个时候数组中就不能单纯的只存储Value了,就要将数组中的元素链表化,变成如下图所示:


image.png

数组中的每个元素,不仅要保存Value,还需要保存Key,以及指向下一个节点的指针。
所以当出现Hash冲突的时候,不同的<Key, Value>对都分配到了同一个数组下标位置,这时候这些不同的<Key, Value>对组成了一个链表,这个数组下标下存储的是一个链表。

Redis中的Hash字典,原理上是类似的,只是在上面包装了一下,加了一些特有的工程信息。
主要包含三部分:字典,Hash表,Hash表节点

Hash表

typedef struct dictht {
  dictEntry **table; //指针数组,用于存储键值对
  unsigned long size; //table数组的大小
  unsigned long sizemask; //掩码 = size - 1
  unsigned long used; //table数组中已存元素个数
} dictht

这里的sizemask的用途是,某个<Kev, Value>对的数组下标值 = Hash(Key) & sizemask。其计算结果等同于Hash(Key)%size,但是因为是位运算,计算效率要比求余运算快得多。

Hash表节点

Hash表中的元素是用dictEntry来封装的。

typedef struct dictEntry{
  void *key;
  union {
    void *val;
    uint64_t u64;
    int64_t s64;
    double d;
  } v;
  struct dictEntry *next;
} dictEntry

简单点理解就是,dictEntry里面包含了key, value,以及指向下一个dictEntry的next指针。

字典

对hash表进行一层封装,把一些特殊的操作封装到字典里面,比如计算hash值,rehash等。

typedef struct dict{
  dictType *type;  //dictType里面封装了这个字典需要的一些特殊的操作,比如计算key的hash值
  void *privatedata;  //传给dictType里面那些操作所需的参数数据
  dictht ht[2];  //两个hash表,大部分情况下只使用ht[0],在扩容的情况下需要用到另外一个
  long rehashidx;  //rehash的进度,也就是记录目前ht[0]这个table里面哪个数组下标正在rehash
  unsigned long iterators; //当前运行的迭代器数
} dict;

所以Redis Hash字典的整个结构图如下:


image.png
  1. 当往Hash字典中加入<Key, Value>对时,首先在Dict的type中根据Key计算出Hash值;
  2. 然后获取dictht[0].sizemask,通过Hash(key)&dictht[0].sizemask,得到这个<Key, Value>对在dictht[0].table数组中的位置。
  3. 将传入的<Key, Value>封装成一个新的dictEntry存入计算出来的位置。

扩容和缩容

当持续往字典里面添加<Key, Value>对后,字典空间慢慢会不够,这个时候就需要扩容。

  1. 申请一块新空间,大小为原来的两倍,并且往上取2的N次方。比如原来字典里面的数组长度是3,扩容的时候要申请大小为8的空间,因为3的两倍是6,6不是2的N次方,所以往上到8;
  2. 将字典的rehashidx设置为0. 并将ht[1]指向这块扩容后的新空间, ht[1]的size, sizemask, used都相应的更新;
  3. 所有的插入操作都rehash到ht[1]。查找,删除,更新则兼顾ht[0]和ht[1];
  4. 最后把ht[0]里面老的元素都rehash到ht[1],rehashidx设置为正在rehash的ht[0]里面元素的下标值;
  5. 删除ht[0]里面的元素,对调ht[0]和ht[1],将rehashidx设置为-1;
    缩容也是类似的流程。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 上一篇文章详细介绍了Redis的五种常用数据类型,每种数据类型在内存中的数据结构都会因情况而异。接下来,我会用几篇...
    Javar阅读 1,884评论 0 2
  • 哈希表在C++中对应的是map数据结构,但在Redis中称作dict(字典)。Redis只是用了几个简单的结构体和...
    linux大本营阅读 490评论 0 0
  • 1、字典,又称符号表(symbol table)、关联数组(associative array)、或者映射(map...
    大飞飞_s8阅读 375评论 2 0
  • Redis 之字典和跳表 字典 Redis整个数据库其实就是一个大的字典 以上命令实际上就是设置了数据库字典中一个...
    lxfeng阅读 1,052评论 0 0
  • 一、概念 字典, 又称符号表(symbol table)、关联数组(associative array)或者映射(...
    Vic_is_new_Here阅读 484评论 0 0