哈希表

结构定义dict.h/dictht

  1. /*
  2. * 哈希表
  3. *
  4. * 每个字典都使用两个哈希表,从而实现渐进式 rehash 。
  5. */
  6. typedef struct dictht {
  7.  
  8. // 哈希表数组
  9. dictEntry **table;
  10.  
  11. // 哈希表大小
  12. unsigned long size;
  13.  
  14. // 哈希表大小掩码,用于计算索引值
  15. // 总是等于 size - 1
  16. unsigned long sizemask;
  17.  
  18. // 该哈希表已有节点的数量
  19. unsigned long used;
  20.  
  21. } dictht;

table是一个数组, 每个元素是一个指向dict.h/dictEntry 结构的指针.

哈希表节点

  1. /*哈希表节点*/
  2. typedef struct dictEntry {
  3. // 键
  4. void *key;
  5. // 值
  6. union {
  7. void *val;
  8. uint64_t u64;
  9. int64_t s64;
  10. } v;
  11. // 指向下个哈希表节点,形成链表
  12. struct dictEntry *next;
  13.  
  14. } dictEntry;

next属性指向下一个节点, 形成链表, 解决哈希冲突.

字典

  1. /*
  2. * 字典
  3. */
  4. typedef struct dict {
  5. // 类型特定函数
  6. dictType *type;
  7. // 私有数据
  8. void *privdata;
  9. // 哈希表
  10. dictht ht[];
  11. // rehash 索引
  12. // 当 rehash 不在进行时,值为 -1
  13. int rehashidx; /* rehashing not in progress if rehashidx == -1 */
  14. // 目前正在运行的安全迭代器的数量
  15. int iterators; /* number of iterators currently running */
  16. } dict;

type 和 privdata属性都是针对不同类型的键值对, 为创建多态字典设置.

  1. /*
  2. * 字典类型特定函数
  3. */
  4. typedef struct dictType {
  5. // 计算哈希值的函数
  6. unsigned int (*hashFunction)(const void *key);
  7. // 复制键的函数
  8. void *(*keyDup)(void *privdata, const void *key);
  9. // 复制值的函数
  10. void *(*valDup)(void *privdata, const void *obj);
  11. // 对比键的函数
  12. int (*keyCompare)(void *privdata, const void *key1, const void *key2);
  13. // 销毁键的函数
  14. void (*keyDestructor)(void *privdata, void *key);
  15. // 销毁值的函数
  16. void (*valDestructor)(void *privdata, void *obj);
  17. } dictType;

ht数组包含两个哈希表,  一般情况下操作ht[0],  ht[1] 只有在ht[0]哈希表进行rehash时使用.  rehashidx, 记录了rehash的进度, 没有则为 -1 ;

哈希算法

Redis 使用MurmurHash2算法计算哈希值

解决键冲突

链地址法,  采用头插法,  时间复杂度为O(1).

rehash

1. 为 ht[1] 分配空间 : 如果是扩容,  分配大小为 第一个大于等于 ht[0] .used * 2 的 2的n次幂; 如果是收缩,  分配空间大小为  第一个大于等于 ht[0] .used 的 2的n次幂.

2.  将ht[0] 上的键值对 通过重新计算键的哈希值和索引重新分配到ht[1] 上.

3. 这时ht[0] 将变为空表,  释放ht[0],  将ht[1] 设置为ht[0],  并在ht[1]创建一个空表, 为下次rehash做准备.

渐进式rehash

在字典维持一个索引计数器 rehashidx, 设置为0, 表示正式工作.

在对字典执行添加, 删除, 查找或修改时,  将 rehashidx 索引上的所有键值对 rehash 到 hd[1], 完成后 rehashidx++;

当ht[0] 上的所有键值对被 rehash到 ht[ 1 ], 设置 rehashidx = - 1, 表示操作已经完成了.

在此期间操作数据, 会使用ht[0] 和 ht[1]两个hash表,  例如要找某个键值, 会先在ht[0] 找, 没有就去ht[ 1 ] 找.  新增操作都保存到ht[ 1 ] 中. 保证了ht[0] 只减不增, 最终为空.

Redis设计与实现 (三): 字典的更多相关文章

  1. [Redis]Redis的设计与实现-链表/字典/跳跃表

    redis的设计与实现:1.假如有一个用户关系模块,要实现一个共同关注功能,计算出两个用户关注了哪些相同的用户,本质上是计算两个用户关注集合的交集,如果使用关系数据库,需要对两个数据表执行join操作 ...

  2. Redis学习笔记(三) 字典

    Redis的字典使用哈希表作为底层实现,一个哈希表中可以有多个哈希表节点,而每个哈希节点就保存在字典中的一个键值对. redis字典所用的哈希表由disht结构定义. typedef struct d ...

  3. Redis 设计与实现 4:字典

    Redis 中,字典是基础结构.Redis 数据库数据.过期时间.哈希类型都是把字典作为底层结构. 字典的结构 哈希表 哈希表的实现代码在:dict.h/dictht ,Redis 的字典用哈希表的方 ...

  4. Redis底层探秘(三):字典

    字典,又称为符号表(symbol table).关联数组(associative array)或映射(map),是一种用于保存键值对的抽象数据结构. 字典经常作为一种数据结构内置在很多高级编程语言里面 ...

  5. Redis设计与实现(一~五整合版)【搬运】

    Redis设计与实现(一~五整合版) by @飘过的小牛 一 前言 项目中用到了redis,但用到的都是最最基本的功能,比如简单的slave机制,数据结构只使用了字符串.但是一直听说redis是一个很 ...

  6. 《Redis设计与实现》读书笔记

    <Redis设计与实现>读书笔记 很喜欢这本书的创作过程,以开源的方式,托管到Git上进行创作: 作者通读了Redis源码,并分享了详细的带注释的源码,让学习Redis的朋友轻松不少: 阅 ...

  7. 《Redis设计与实现》

    <Redis设计与实现> 基本信息 作者: 黄健宏 丛书名: 数据库技术丛书 出版社:机械工业出版社 ISBN:9787111464747 上架时间:2014-6-3 出版日期:2014 ...

  8. 探索Redis设计与实现9:数据库redisDb与键过期删除策略

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  9. 探索Redis设计与实现6:Redis内部数据结构详解——skiplist

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

随机推荐

  1. Django---自定义admin组件思维导图

  2. jQuery全屏图片焦点图

    在线演示 本地下载

  3. jQuery UI 自定义样式的日历控件

    在线演示 本地下载

  4. oracle时间的获取,前一天,上一个星期,上一个月

    –前一天的开始时刻 SELECT to_date(to_char(TRUNC(SYSDATE-1),’yyyy-mm-dd’) || ‘00:00:00’,’yyyy-mm-dd hh24:mi:ss ...

  5. JavaEE之注解

    1注解:Annotation注解,是一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次,给计算机,JVM提供解读信息的. 2注解的作用:编译检查:代码分析,编 ...

  6. var与this定义变量的区别以及疑惑

    我们知道: var可以定义一个局部变量,当然如果var定义在最外层的话,就是全局的局部变量,也就算是全局变量了. 而this关键字定义的变量准确的说应该算是成员变量.即定义的是调用对象的成员变量. 另 ...

  7. scala学习手记36 - 容器基础

    scala的容器包括Set.List和Map.三种容器的特征和Java中一样.scala为每种容器都提供了可变和不可变两种版本,分别位于scala.collection.mutable或scala.c ...

  8. LeetCode第[34]题(Java):Search for a Range

    题目:搜索目标范围 难度:Medium 题目内容: Given an array of integers nums sorted in ascending order, find the starti ...

  9. C# 语言版本

    (摘自:维基百科)https://en.wikipedia.org/wiki/C_Sharp_(programming_language) Versions Version Language spec ...

  10. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...