Redis核心数据结构之字典(一)

字典

概述

字典又称为符号表(symbol table)、关联数组(associative array)或映射(map),是一种保存键值对(key-value pair)的抽象数据结构,在字典中,一个键(key)可以和一个值(value)进行关联(或者说将键映射为值),这些关联的键和值就称为键值对。字典中的每个键都是独一无二的,程序可以在字典中根据键查找与之关联的值,或者通过键来更新值,又或者根据键来删除整个键值对等等

字典经常作为一种数据结构内置在很多高级编程语言里面,但Redis所使用的C语言并没有内置这种数据结构,因此Redis构建了自己的字典实现。字典在Redis中的应用相当广泛,比如Redis的数据库就是使用字典来作为底层实现的,对数据库的增删改查操作也是构建在对字典的操作之上的。

除了用来表示数据库之外,字典还是哈希键的底层实现之一,当一个哈希键包含的键值对比较多,又或者键值对中的元素都是比较长的字符串时,Redis就会使用字典作为哈希键的底层实现。

除了用来实现数据库和哈希键之外,Redis的不少功能也用到了字典

例子

  • 举个例子,当我们执行代码中的命令之后,会在数据库中创建一个键为"msg",值为"hello world"的键值对,这个键值对就是保存在代表数据库的字典里面的。
redis> SET msg "hello world"
OK
  • 举个例子,website是一个包含3个键值对的哈希键,这个哈希键的键都是一些数据库的名字,而键的值就是数据库的主页网址:如代码所示。website键的底层实现就是一个字典,字典中包含了3个键值对,例如:Redis-Redis.io、MariaDB-MariaDB.org、MongoDB-MongoDB.org
redis> HLEN webiste
(integer) 3
redis> HGETALL website
1) "Redis"
2) "Redis.io"
3) "MariaDB"
4) "MariaDB.org"
5) "MongoDB"
6) "MongoDB.org"

字典的实现

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

哈希表

Redis字典所使用的哈希表由dict.h/dictht结构定义:如代码所示
table属性是一个数组,数组中的每个元素都是一个指向dict.h/dictEntry结构的指针,每个dictEntry结构保存着一个键值对。size属性记录了哈希表的大小,也即是table数组的大小,而used属性则记录了哈希表目前已有节点(键值对)的数量。sizemask属性的值总是等于size-1,这个属性和哈希值一起决定一个键应该被放到table数组的哪个索引上面。

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

这是一个大小为4的空哈希表(没有包含任何键值对)
在这里插入图片描述

哈希表节点

哈希表节点使用dictEntry结构表示,每个dictEntry结构都保存着一个键值对,如代码所示.key属性保存着键值对中的键,而v属性保存着键值对中的值,其中键值对的值可以是一个指针,或者是一个uint64_t整数,又或者是一个int64_t整数。next属性是指向另一个哈希表节点的指针,这个指针可以将多个哈希值相同的键值对连接在一起,以此来解决键冲突(collision)的问题

typedef struct dictEntry {// 键void *key;union {void *val;uint64_t u64;int64_t s64;}v;// 指向下个哈希表节点,形成链表struct dictEntry *next;} dictEntry;
例子
  • 举个例子,该图就是通过next指针,将两个索引值相同的键K1和K0连接在一起的
    在这里插入图片描述

字典

Redis中的字典由dict.h/dict结构表示:如代码所示。
type属性和privdata属性是针对不同类型的键值对,为创建多态字典而设置的:

  • 1.type属性是一个指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定类型键值对
    的函数,Redis会为用途不同的字典设置不同的类型特定函数。
  • 2.而privdata属性则保存了需要传给那些类型特定函数的可选参数。
typedef struct dict {// 类型特定函数dictType *type;// 私有数据void *privdata;// 哈希表dictht ht[2];// rehash索引// 当rehash不在进行时,值为-1int trehashidx; // rehasing not in progress if rehashidx == -1
}dict;

ht属性是一个包含两个项的数组,数组中的每个项都是一个dictht哈希表,一般情况下,字典只使用ht[0]哈希表,ht[1]哈希表只会在对ht[0]哈希表进行rehash时使用。除了ht[1]之外,另一个和rehash有关的属性就是rehashidx,它记录了rehash目前的进度,如果目前没有在进行rehash,那么它的值为-1.

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 *key);// 销毁值的函数void (*valDestructor)(void *privdata, void *obj);
}dictType;

展示了一个普通状态下(没有进行rehash)的字典
v

哈希算法

当要将一个新的键值对添加到字典里面时,程序需要先根据键值对的键计算出哈希值和索引值,然后再根据
索引值,将包含新键值对的哈希表节点放到哈希表数组的指定索引上面。
Redis计算哈希值和索引值的方法如下:
#使用字典设置的哈希函数,计算键key的哈希值

hash = dict->type->hashFunction(key);

#使用哈希表的sizemask属性和哈希值,计算出索引值
#根据情况不同,ht[x]可以是ht[0]或者ht[1]

index = hash & dict->ht[x].sizemask;

当字典被用作数据库的底层实现,或者哈希键的底层实现时,Redis使用MurmurHash2算法来计算键的哈希值的,这种算法的优点在于,即使输入的键是有规律的,算法仍能给出一个很好的随机分布性,并且算法的计算速度也非常快。

例子

举个例子,如果要将一个键值对K0和V0添加到字典里面,
那么程序会使用语句

hash = dict->type->hashFunction(k0);

计算k0的哈希值.假设计算得出的哈希值为8,那么程序会继续使用语句:

index = hash & dict->ht[0].sizemask = 8 & 3 = 0;

计算出键K0的索引值0,这表示包含键值对K0和V0的节点应该被放置到
哈希表数组真的索引0位置上,如图所示
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/728757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenText Availability——适用于 Windows 和 Linux 服务器的高可用性和灾难恢复解决方案

OpenText Availability——适用于 Windows 和 Linux 服务器的高可用性和灾难恢复解决方案 连续复制,最大限度地减少数据丢失快速故障转移,最大限度地减少停机时间可忽略的性能影响支持物理、虚拟和基于云的系统平台 停机从多种途径侵扰 IT 企业。 从相…

最佳牛围栏(二分 + 前缀和)

最佳牛围栏 原题链接&#xff1a;https://www.acwing.com/problem/content/104/ 题目 思路 我们发现若是枚举答案的话&#xff0c;那么我们判断是否存在一个平均值大于等于mid&#xff0c;如果最优解是x&#xff0c;那么mid < x的时候&#xff0c;必然可以找到一段&#x…

算法---双指针练习-1(移动零)

移动零 1. 题目解析2. 讲解算法原理数组划分&#xff0c;数组分块&#xff08;核心思想&#xff09;如何做到 3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 数组划分&#xff0c;数组分块&#xff08;核心思想&#xff09; dest一般初始化为-1&#x…

计算机设计大赛 深度学习的视频多目标跟踪实现

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …

16、电源管理入门之驱动Runtime PM管理

目录 1. 框架介绍 1.1 为什么需要Runtime PM Framework? 1.2 系统框架图 2. Drivers 3. Runtime PM core 4. power domain framework 5. runtime pm的sysfs 6参考: Runtime PM管理也就是设备驱动里面的电源管理,即设备驱动结构体里面的struct dev_pm_ops,只控制设…

bun实现HTTP服务器

Bun 提供了原生 Bun.serve API。它实现了 fetch 以及Node.js的 http 和 https 模块。 这些模块已被重新实现&#xff0c;以使用 Bun 的快速内部 HTTP 基础设施。随意直接使用这些模块;像 Express 这样依赖于这些模块的框架应该开箱即用。有关详细的兼容性信息&#xff0c;请参阅…

【HarmonyOS】ArkTS-箭头函数

箭头函数 箭头函数是 比普通函数 更简洁 的一种函数写法 () > {}() > {// 函数体 }let 函数名 () > {// 函数体 }let 函数名 () > {// 函数体 } 函数名(实参1, 实参2)let 函数名 (形参1: 类型, 形参2: 类型) > {// 函数体 } 函数名(实参1, 实参2)let 函数名 …

变频器学习

西门子变频器 SINAMICS V20 入门级变频器 SINAMICS G120C

《Trustzone/TEE/安全-实践版》介绍

第一章&#xff1a;课程说明和准备 课程介绍和说明 资料准备 为什么使用qemu_v8环境&#xff1f; 为什么选择香橙派开发板&#xff1f; optee qemu_v8环境展示 香橙派optee环境展示 第二章&#xff1a;Qemu环境搭建 ubuntu20.04的安装(virtualboxubuntu20.04) 搭建optee qem…

利用“定时执行专家”循环执行BAT、VBS、Python脚本——含参数指定功能

目录 一、软件概述 二、VBS脚本执行设置 三、触发器设置 四、功能亮点 五、总结 在自动化办公和日常计算机任务管理中&#xff0c;定时执行脚本是一项非常重要的功能。今天&#xff0c;我将为大家带来一款名为“定时执行专家”的软件的评测&#xff0c;特别是其定时执行VB…

Unity3D学习之XLua实践——背包系统

文章目录 1 前言2 新建工程导入必要资源2.1 AB包设置2.2 C# 脚本2.3 VSCode 的环境搭建 3 面板拼凑3.1 主面板拼凑3.2 背包面板拼凑3.3 格子复合组件拼凑3.4 常用类别名准备3.5 数据准备3.5.1 图集准备3.5.2 json3.5.3 打AB包 4 Lua读取json表及准备玩家数据5 主面板逻辑6 背包…

寻找旋转排序数组中的最小值[中等]

优质博文IT-BLOG-CN 一、题目 已知一个长度为n的数组&#xff0c;预先按照升序排列&#xff0c;经由1到n次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组nums [0,1,2,4,5,6,7]在变化后可能得到&#xff1a; 【1】若旋转4次&#xff0c;则可以得到[4,5,6,7,0,1,2…

【自然语言处理六-最重要的模型-transformer-下】

自然语言处理六-最重要的模型-transformer-下 transformer decoderMasked multi-head attentionencoder和decoder的连接部分-cross attentiondecoder的输出AT(Autoregresssive)NAT transformer decoder 今天接上一篇文章讲的encoder 自然语言处理六-最重要的模型-transformer-…

吴恩达机器学习笔记十五 什么是导数 计算图 大型神经网络案例

假设函数 J(w)w^2&#xff0c;当 w3 时&#xff0c; J(w)3*39 当我们给w增加一个很小的量时&#xff0c;观察J(w)如何变化。 例如 w30.001&#xff0c; 则J&#xff08;w&#xff09;9.006001&#xff0c;因此当w3且增加一个变化量 ε 时&#xff0c;J(w)将会增加 6ε&#x…

Northwestern University-844计算机科学与技术/软件工程-机试指南【考研复习】

本文提到的西北大学是位于密歇根湖泊畔的西北大学。西北大学&#xff08;英语&#xff1a;Northwestern University&#xff0c;简称&#xff1a;NU&#xff09;是美国的一所著名私立研究型大学。它由九人于1851年创立&#xff0c;目标是建立一所为西北领地地区的人服务的大学。…

泛型 --java学习笔记

什么是泛型 定义类、接口、方法时&#xff0c;同时声明了一个或者多个类型变量&#xff08;如&#xff1a;<E>&#xff09;&#xff0c;称为泛型类、泛型接口&#xff0c;泛型方法、它们统称为泛型 可以理解为扑克牌中的癞子&#xff0c;给它什么类型它就是什么类型 如…

[Buuctf] [MRCTF2020]Transform

1.查壳 64位exe文件&#xff0c;没有壳 2.用64位IDA打开 找到主函数&#xff0c;F5查看伪代码 从后往前看&#xff0c;有一个判断语句&#xff0c;是两个数组进行比较的&#xff0c;我们双击byte_40F0E0查看里面的内容 所以能够推出byte_414040的内容&#xff0c;byte_4140…

音频库及分析软件介绍

搞音频的兄弟必须要看一下的&#xff0c;俗话说&#xff0c;工欲善其事必先利其器&#xff0c;好的音频分析软件&#xff0c;对于音频分析工程师来讲&#xff0c;可谓是非常重要的&#xff0c;下面由小编介绍一下&#xff1a;

opengl 学习(一)-----创建窗口

创建窗口 分类opengl 学习(一)-----创建窗口效果解析教程补充 分类 c opengl opengl 学习(一)-----创建窗口 demo: #include "glad/glad.h" #include "glfw3.h" #include <iostream> #include <cmath> #include <vector>using names…

数据结构与算法-线性查找

引言 在计算机科学领域&#xff0c;数据结构和算法是构建高效软件系统的核心要素。今天我们将聚焦于最基础且广泛应用的一种查找算法——线性查找&#xff0c;并探讨其原理、实现步骤以及实际应用场景。 一、什么是线性查找&#xff1f; 线性查找&#xff08;Linear Search&am…