一、Redis的数据结构有哪些
redis的数据结构包含: 简单动态字符串 、 链表 、 字典 、 跳跃表 、 整数集合 、 压缩列表 。
简单动态字符串 :redis没有采用C语言的内置字符串而是自定义了一种叫 简单动态字符串 (SDS),它兼容了C语言的字符串结构(保留了C语言字符串的格式以便使用C语言字符串的库)极其优点于一身的简单动态字符串,还融入了它自己的优点。 例如:
-
快速获取字符串的长度 ,结构体中存储了字符串的长度,即便是再怎么长的字符串都可以以 O(1) 的速度获取字符串的长度。
-
杜绝缓存溢出 ,SDS的空间分配策略完全杜绝 了C语言中的溢出隐患,每当字符串API修改时,sdscat都会进行空间预判并自动扩容字符串空间,最后再拼 接字符串,而不需要程序员手动扩容。
-
减少修改字符串时带来的内存重分配次数 ,SDS 结构体中有一个free属性,用来记录未使用的空间长度,当SDS的API对一个SDS进行修改时,会自动计算SDS所需要的长度进行分配额外的未使用空间,俗称空间预分配。同理如果字符串不需要那么多free未使用的空间,会进行惰性释放空间的行为。
-
二进制安全 ,SDS可以存储类似图片、音频、压缩文件等这样的二进制数据。还可以存储空格分割的字符串。
-
兼容部分C字符串函数 。
链表 : 链表在Redis的应用很广泛,例如列表键的底层设计之一就是链表。链表是由多个节点组成的,它具有以下特点。 例如:
-
双端 ,链表的每个节点都有prev和next指针,可以快速获取某一个前置节点和后置节点的信息,复杂度为O(1)。
-
无环 ,表头节点的prev指针和表尾节点的next都指向NILL,对链表的访问以null为终点。
-
带表头指针和表尾指针 ,通过list结构的head和tail指针,可以获取链表的表头和表尾节点,复杂度为O(1)。
-
带链表长度计数器 ,list结构的len属性存储了链表节点的计数,获取节点的数量时间复杂度为O(1)。
-
多态 ,链表节点使用void*指针保存节点值,可以通过list结构体中的dup,free,match三个属性节点值设置类型特定函数,所以链表可以保存各种不同类型的值。
字典 :字典可以理解为关联数组或映射、以及符号表。是用来保存键值对的抽象数据结构。字典中的键都是独一无二的,可以通过键查找对应的值,以及更新删除等操作。
字典是采用哈希表作为底层实现的。一个哈希表里面可以有多个哈希节点,每个哈希节点就保存了一个字典中的键值对。 例如:
-
当一个新的键值对要添加到字典中,程序需要先根据键值对的键计算出哈希值和索引值,然后再根据索引值将包含键值对的哈希表节点放到哈希数组指定的索引上。
-
既然采用了 哈希算法 ,就会遇到 键冲突 。当两个以上的键被分配到了同一个索引上面,就称发生了键冲突。Redis的哈希表采用了 链地址法 来解决键冲突 。即多个哈希表节点采用next指针构成一个 单向链表 。使用单向链表链接起来就解决了键冲突的问题。因为是单向链表,并没有指针指向链表的表尾,所以为了速度考虑,每次新的节点都会在链表的表头位置插入。复杂度为O(1)。
-
哈希表保存的键值对会越来越多,在对哈希表进行 扩展 和 收缩 操作时,程序需要将现有哈希表包含的所有键值对 rehash到新的哈希表 中,并且这个rehash过程并不是一次性完成的,而是 渐进式地完成 的。
跳跃表 :跳跃表是一种有序数据结构,它通过在每个节点中维持 多个指向其他节点的指针 ,从而达到 快速访问节点 的目的。redis使用跳跃表作为有序集合键的底层实现之一。
-
跳跃表是使用( 跳跃表信息 )和( 跳跃表节点信息 )两个结构体定义的。
-
每个跳跃表的 层高 都是1到32之间的随机数
-
在同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是 唯一 的
-
跳跃表中的节点 按照分值大小进行排序 ,当分值相同时