redis 集合中的最小值 redis集合有没有限制_链表


什么是redis 有序集合

redis有5种数据类型,包括:

  1. string 字符串:可以为整形、浮点型和字符串,统称为元素。
  2. list 列表:可以作为队列使用。
  3. set 集合: 一个集合内,所有元素各部相同。
  4. hash hash散列值: 即字典,key值唯一。
  5. sortedSet 有序集合。

和集合一样,有序集合也是 string 类型元素的集合,且元素不允许重复。不同的是,有序集合的每个元素都会关联一个 double 类型的分数(score)。redis 通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数却可以重复。

有序集合查找任意数据的时间复杂度是O(1),插入、删除操作的时间复杂度是O(logN)。

由于有序集合可以根据分数对元素进行排序,因此有序集合可用于排行榜、学生成绩排名等用途。

有序集合的底层实现

出于对性能的考虑,有序集合底层有两类实现:

  1. 当有序集合保存的元素数量小于128个,并且所有元素的长度都小于64字节时,有序集合对象使用ziplist实现。
  2. 当不满足上述条件时,有序集合对象使用skiplist+字典实现。

说一说ziplist

ziplist(压缩列表)实现的有序集合对象中,每个元素是用需要使用两个连续的压缩列表节点保存,第一个节点保存元素的成员,第二个节点保存元素的分值,分值为double 类型。

压缩列表内的元素,会按照分值,从小到大排序。如果分值相同,则按照元素成员的大小,从小到大排序。大致如下图所示:


redis 集合中的最小值 redis集合有没有限制_redis 集合中的最小值_02


说一说skiplist

skiplist(跳跃表)采用了链表加多级索引的结构。它使用了空间换时间的设计思路,在存储时建立了很多级索引。使得在跳跃表中查找、插入和删除的时间复杂度都是O(logN)。

它的实现大致如下图所示:


redis 集合中的最小值 redis集合有没有限制_redis 集合中的最小值_03


  1. 最下一层是链表,有序的保存所有的数据。
  2. 原始链表以上,都为索引层。在每级索引的基础上,每隔几个节点抽出一个节点,形成更上一级索引。
  3. 每个节点不直接保存数据,而是保存指针,这样能减少对空间的消耗。
  4. 当查找某条数据时,会先从上往下在索引层遍历,找到该数据所在的索引范围。通过索引层节点的指针,不断下降到下一层,直到原始链表这一层。继续遍历,直到找到该节点,或者通过逻辑判断该节点不存在。
  5. 当插入或删除时,也会先查找到位置,插入到链表中或从链表中删除,并动态更新索引层,维护索引与原始链表大小之间的平衡。例如链表中结点多了,索引结点就相应地增加一些,避免查找,插入,删除操作性能下降。

为什么有序集合需要同时使用跳跃表和字典来实现?

有序列表使用skiplist(跳跃表)+字典实现,是为了保证查找和范围型操作(ZRANK、ZRANGE等)都能尽可能快的执行。

例如只使用跳跃表,查找单个成员,复杂度为O(logN)。

例如只使用字典,由于字典是无序的,范围型的操作,会需要使用至少O(NlogN)时间复杂度和额外的O(N)空间对数据排序,再进行范围型操作。

而同时使用跳跃表+字典,查找单个成员,可以直接在字典中查找,复杂度为O(1),范围型操作则在跳跃表中操作,复杂度为O(lngN)。