背景
redis集合是数据无序,有序集合是数据有序。
但是它和列表的有序有点不一样,列表是数据有序,而有序集合是有个单独的分数score字段来排序,score的值可以重复,但是value的值不能重复——这就像学生的考试分数可能一样,但是学号不一样。
数据结构
内部数据结构
1.压缩列表ziplist
2.跳表skiplist
和映射一样,都是有这两种实现方式。使用压缩列表时的区别是,唯一不同的是,有序集合的压缩列表条件是1.元素数量百位数(100,而映射是500)2.字节数量十位数(50)。
另外一种,映射使用的是hashtable,而有序集合使用的是跳表skiplist。
如何确保数据不重复?
1.压缩列表
会比较数据。当然,映射也是比较数据。
2.跳表 还是比较。
为什么不像集合一样,使用整数集合intset和hashtable?
1.为什么不使用intset,而是使用压缩列表?
有序集合有score和value字段,有字符串的情况多一些,而整数集合是少量整数,所以使用了压缩列表,而没有使用整数集合intset。
2.为什么不使用hashtable,而是使用跳跃链表skiptable?
为了速度,hashtable的比较速度是N,因为数据不能重复,所以插入之前必须先要比较数据。而跳跃列表的速度是N/间隔数量。
压缩列表如何实现有序集合?或者说,连续内存如何实现集合?都是一样的。如果是集合,那么就是一个节点是一个元素;如果是有序集合,因为有score和value两个字段,那么实际上就是两个节点,各自占一个元素。再延伸一下,映射的key/value也是一样的原理,就是两个节点,key和value各自一个节点。
把下图中的key和value节点换为score和value节点即可
跳跃链表skiplist
链表是单向或双向指向前置/后置节点,这是水平层面的指针指向,而跳跃链表是垂直层面的指针指向,即多出来的指针指向的不是前置/后置节点,而是中间隔了N个节点,这样做的目的就是加快遍历的速度,以前是N,现在N/间隔数量。
垂直层面的级别可以是多了一个指针,这是一级跳跃链表,多了两个,就是二级跳跃链表。
优点
加快链表的遍历速度。
缺点
多出来的指针,每个指针都要占用多余的内存。
典型的以内存换速度的算法。速度的思想和平衡树、二叉查找类似。
数据有序
跳跃链表和压缩列表的节点不一样,压缩列表的score和value是两个节点,而跳跃链表的score和value是在同一个节点的两个字段,之所以不一样,是因为压缩列表是连续内存 起始位置+大小/偏移量 这样的数据结构,而跳跃链表是 类+数据 这样的数据结构。
不管是哪一种内部数据结构,都是按照score的值进行排序。
数据有序
不管是按数据本身有序的列表,还是按score来排序的额有序集合,只要有序,都可以按范围来获取数据。不过,一个是按索引的范围来获取范围数据,一个是按score的范围来获取范围数据。
参考
黄建宏