由Redis学习数据结构--字典
字典的定义
字典,是一种保存键值对(key value pair)的抽象数据结构。
字典中的每一个键都是独一无二的,我们可以通过键查找,更新,删除与之关联的值。
Redis中用C语言实现了字典,其本质即为哈希表(Hash table)的一层wrapper。
哈希表
Redis中的字典具有很高的查询速度,这主要得益于其基于哈希表的底层实现。
在字典中,假如其键为key
,它的值(value)储则存在f(key)
上,故我们可以很快地通过f()
找到需要操作的值,而不需要遍历。
其中f()
函数为散列函数,其本身很大程度上决定着字典的效率,我们将在下文简单介绍Redis所使用的散列函数。
哈希冲突
在某些时候,不同的键会产生相同的值,我们称为哈希冲突。此时我们就需要对冲突进行解决。
在Redis中,我们使用了链地址法(separatechaining)来解决键冲突。具体为每个哈希表节点都有一个next指针,多个节点以此形成一个单向链表,以解决键冲突的问题。
载荷因子
散列表的载荷因子定义为:
α = 填入表中的元素个数 / 散列表的长度
α 是散列表装满程度的标志因子。由于表长是定值, α与“填入表中的元素个数”成正比,所以,α越大,表明填入表中的元素越多,产生冲突的可能性就越大;反之,α越小,标明填入表中的元素越少,产生冲突的可能性就越小。实际上,散列表的平均查找长度是载荷因子 α的函数,只是不同处理冲突的方法有不同的函数。
载荷因子一定程度上决定着哈希表的效率。为了使Redis的负载因子维持在一个合理的范围,当哈希表中保存的键值对过多或过少时,我们就会对哈希表进行相应的扩展或收缩。这个过程称为rehashing。
相关结构
字典
其中ht
为哈希表数组,第一个用来储存数据,第二个用来rehashing
|
|
操作字典的一些方法
此结构体保存了一些函数指针,它主要是为了多态。
|
|
哈希表
其中table
是一个数组,保存着键值对的指针。
|
|
键值对
其中next指针主要是为了解决哈希冲突的问题。
|
|
操作函数
新建一个字典
|
|
向字典中添加键值对
- 判断是否在rehashing,如果是则停止。
- 新建一个键值对,并将其加在哈希表最前面。
- 重置键。
- 重置值。
|
|
具体向字典中加入键和值的为两个宏。
如果字典本身提供了操作的方法,优先使用字典提供的。
|
|
删除字典中的某个键值对
|
|
查找值
|
|
rehashing
随着操作的进行,为了使得荷载因子维持在一个合理的范围,我们需要对哈希表进行相应的扩张或缩小。
- 如果执行的是扩张操作,那么ht[1],即第二个哈希表的大小为2,否则为
- 将保存在ht[0]中所有的键值对rehashing到第二个哈希表上
- 将原来的ht[1]设为ht[0],释放原来的ht[0],并准备一个新的哈希表,设为ht[1]
|
|