简简单单说下Redis 有序集合

简简单单说下Redis 有序集合

什么是redis 有序集合

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

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

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

有序集合的成员是惟一的,但分数却能够重复。性能

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

因为有序集合能够根据分数对元素进行排序,所以有序集合可用于排行榜、学生成绩排名等用途。3d

有序集合的底层实现

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

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

说一说ziplist

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

压缩列表内的元素,会按照分值,从小到大排序。若是分值相同,则按照元素成员的大小,从小到大排序。大体以下图所示:blog

8b3161c5648d557657c01e543ded662f.png

说一说skiplist

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

它的实现大体以下图所示:索引

3fec7869a6eb7c70d17f9c53f6ab2c87.png

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

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

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

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

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

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

相关文章
相关标签/搜索