redis核心数据结构

redis核心数据结构

1.使用redis

李蛋同志的老爱人,redis,著名内存数据库

内置多种数据结构包括

字符串对象(string)

redis核心数据结构_第1张图片

如图所示: raw编码方式时可以更改的,因为其为指针方式链接
但是embstr就不能给够更改,redis规定,如果字符串长度超过39就选择raw,小于的话就直接 sdshdr,至于最大的区别那就是内存是不是连续的了。只是亲手实现过raw,没有弄过embstr。

list对象

list对象分为两种,第一种就是ziplist,这种就是一大块内存空间,不够了再用,变长数组实现,node之间用固定符号间隔。就比较牛逼。(我没有实现过),但是简单来讲就是插入复杂度O(n),不能太大,否贼会崩溃哦。

redis核心数据结构_第2张图片

dict对象(变长数组+murmurhash实现)

这个我太熟悉了,字典的实现有很多种实现方式,但是我唯独喜欢这个实现方式,先encoding对应的插入对象,然后对string进行murmurhash,这样就直接插入了。(听起来很简单是吧)

这里面有很多变长数组实现的技巧,比如长度必须是2n,必须要有一个mask时2n-1,这样取余的时候就使用位运算了,同时下面要讲的一个非常牛逼的位运算的算法就能够在这个基础上实现了。另外如果我没记错,使用这种技巧可以让hash的碰撞率大大降低

穿插一下为什么能够大大降低碰撞率

如果你是2n的长度,那么你的mask就是2n-1,底层就是1111…,每一位都是1,长度设置又合理的话,所以&的话,假设数字出现均匀的,那么所有的1都有机会变成0,也就是每一个数的出现都是均匀的,散列也就均匀,如果你不是2^n-1,那这就很尴尬了,减一之后就会出现有0穿插进去,而有0的那一位,就没有办法变成1了,也就是这一位为0的所有数字都不可能出现,散列的概率就发生了偏移,那就完蛋了;)。

比如长度为9时候,3&(9-1)=0 2&(9-1)=0 ,都在0上,碰撞了;
比如长度为8时候,3&(8-1)=3 2&(8-1)=2 ,不同位置上,不碰撞;

所以当你使用&来进行取余的时候,就必须使用2^n的长度,这样才够好。那我为什么要使用&来取余呢?因为快呀。

你以为这就完了吗?native

这个数据结构最难受的地方出现了,那就是如果变长数组的长度发生变化,你需要rehash。。。

因为7%4和7%8可是不同哦?

你encode了,你murmurhash了,你插入了,突然就需要rehash了,所以。。。

那么问题就变成了:如何在长度变了之后,将原来的hash过的对象,rehash到新的散列表中???

你想一次性hash完吗? 别天真了,你hash的时候还要不要响应外界请求?

所以必须两个都存在,必须有两个hash队列,轮换着来。每hash一个新的对象到新的队列,就hash两个旧的对象到新的队列。完美。这样就搞定了。

native。

如果来了一个7的查询,如何快速判断这个7在新的队列还是在旧的队列中呢?

这个地方暂缺,我有时间写,很复杂的位运算,但是很有名。好像是reverse位然后迭代的一系列复杂位运算,非常难写,但是不难理解。

Set对象

两种实现,实现较为简单,不多逼逼

一种intset

redis核心数据结构_第3张图片

一种hashtable实现,上面的字典

redis核心数据结构_第4张图片

有序集合对象

没错,如何实现链表查询为Ologn,跳跃表

我整整写了一个星期的数据结构,这个数据结构充分体现了跳跃的层级结构的思想。

多层级链表结构实现链表node的快速定位。

你们自己百度跳跃表吧。

你可能感兴趣的:(redis)