### 2.7.7 有序集合对象(zset)
有序集合对象的编码(encoding)可以是`ziplist`、 `skipist`
当有序集合对象同时满足以下两个条件时,使用ziplist编码,否则使用skiplist编码:
- 所有元素长度小于64字节(可以通过`zset-max-ziplist-value`设置)
- 元素数量小于128个(可以通过`zset-max-ziplist-entries`设置)
----
skiplist编码的对象使用zset作为底层数据结构:
```c
typedef struct zset {
zskiplist *zsl;
dict *dict;
};
```
- zsl中按分值c从小到大排列了所有元素,可以对集合进行范围操作:ZRANK、ZRANGE等
- dict为所有元素创建了一个从成员到分值的映射,程序可以用O(1)的复杂度根据成员查找分值等,如ZSCORE
- 通过指针共享相同元素
----
```c
redis> ZADD price 8.5 apple 5.0 banana 6.0 cherry
(integer) 3
```
如果price键使用ziplist编码,则其值对象如下所示:
```
redisObject
type: REDIS_ZSET
encoding: REDIS_ENCODING_ZIPLIST
ptr -> ziplist: {
zlbytes, zltail, zllen,"banana", 5.0, "cherry", 6.0, "apple", 8.5, zlend
}
...
```
如果price键使用skiplist编码,则其值对象如下所示:
```
redisObject
type: REDIS_ZSET
encoding: REDIS_ENCODING_SKIPLIST
ptr -> zset: {
dict: {
dict, ..., h[0]: {
dictht, ..., table: {
(stringObject:"banana") -> 5.0
(stringObject:"apple") -> 8.5
(stringObject:"cherry") -> 6.0
}, ...
},...
},
zsl: {
(header: ...), (tail: ...), (level: 5), (length: 3)
}
}
...
```
----
有序集合命令的实现:
命令 | ziplist的实现 | skiplist的实现
---- | ---- | ----
ZAdd | 调用ziplistInsert函数,将成员和分值作为两个结点分别插入到压缩列表 | 先调用zslInsert函数插入跳跃表,再调用dictAdd函数插入到字典
ZCard | 调用ziplistLeng函数,将结果除以2后返回 | 返回跳跃表的length属性
ZCount | 遍历压缩列表,统计分值在给定范围内的结点数量 | 遍历跳跃表,统计分值在给定范围内的结点数量
ZRange | 从表头到表尾遍历压缩列表,返回给定索引范围内的所有元素 | 从表头到表尾遍历跳跃表,返回给定索引范围内的所有元素
ZRevRange | 从表尾到表头遍历压缩列表,返回给定索引范围内的所有元素 | 从表尾到表头遍历跳跃表,返回给定索引范围内的所有元素
ZRank | 从表头到表尾遍历压缩列表,查找指定元素,返回途径结点数,即排位 | 从表头到表尾遍历跳跃表,查找指定元素,返回途径结点数,即排位
ZRevRank | 从表尾到表头遍历压缩列表,查找指定元素,返回途径结点数,即排位 | 从表尾到表头遍历跳跃表,查找指定元素,返回途径结点数,即排位
ZRem | 遍历压缩列表,删除所有包含给定成员的结点,及其下一个值结点 | 遍历跳跃表,删除所有包含了给定成员的跳跃表结点,并在字典中解除被删除元素的成员和值的关联
ZScore | 遍历压缩列表,查找指定成员结点,取出其下一个结点即值结点 | 直接在字典中取出给定成员所对应的值
- 空白目录
- 精简版Spring的实现
- 0 前言
- 1 注册和获取bean
- 2 抽象工厂实例化bean
- 3 注入bean属性
- 4 通过XML配置beanFactory
- 5 将bean注入到bean
- 6 加入应用程序上下文
- 7 JDK动态代理实现的方法拦截器
- 8 加入切入点和aspectj
- 9 自动创建AOP代理
- Redis原理
- 1 Redis简介与构建
- 1.1 什么是Redis
- 1.2 构建Redis
- 1.3 源码结构
- 2 Redis数据结构与对象
- 2.1 简单动态字符串
- 2.1.1 sds的结构
- 2.1.2 sds与C字符串的区别
- 2.1.3 sds主要操作的API
- 2.2 双向链表
- 2.2.1 adlist的结构
- 2.2.2 adlist和listNode的API
- 2.3 字典
- 2.3.1 字典的结构
- 2.3.2 哈希算法
- 2.3.3 解决键冲突
- 2.3.4 rehash
- 2.3.5 字典的API
- 2.4 跳跃表
- 2.4.1 跳跃表的结构
- 2.4.2 跳跃表的API
- 2.5 整数集合
- 2.5.1 整数集合的结构
- 2.5.2 整数集合的API
- 2.6 压缩列表
- 2.6.1 压缩列表的结构
- 2.6.2 压缩列表结点的结构
- 2.6.3 连锁更新
- 2.6.4 压缩列表API
- 2.7 对象
- 2.7.1 类型
- 2.7.2 编码和底层实现
- 2.7.3 字符串对象
- 2.7.4 列表对象
- 2.7.5 哈希对象
- 2.7.6 集合对象
- 2.7.7 有序集合对象
- 2.7.8 类型检查与命令多态
- 2.7.9 内存回收
- 2.7.10 对象共享
- 2.7.11 对象空转时长
- 3 单机数据库的实现
- 3.1 数据库
- 3.1.1 服务端中的数据库
- 3.1.2 切换数据库
- 3.1.3 数据库键空间
- 3.1.4 过期键的处理
- 3.1.5 数据库通知
- 3.2 RDB持久化
- 操作系统
- 2021-01-08 Linux I/O 操作
- 2021-03-01 Linux 进程控制
- 2021-03-01 Linux 进程通信
- 2021-06-11 Linux 性能优化
- 2021-06-18 性能指标
- 2022-05-05 Android 系统源码阅读笔记
- Java基础
- 2020-07-18 Java 前端编译与优化
- 2020-07-28 Java 虚拟机类加载机制
- 2020-09-11 Java 语法规则
- 2020-09-28 Java 虚拟机字节码执行引擎
- 2020-11-09 class 文件结构
- 2020-12-08 Java 内存模型
- 2021-09-06 Java 并发包
- 代码性能
- 2020-12-03 Java 字符串代码性能
- 2021-01-02 ASM 运行时增强技术
- 理解Unsafe
- Java 8
- 1 行为参数化
- 1.1 行为参数化的实现原理
- 1.2 Java 8中的行为参数化
- 1.3 行为参数化 - 排序
- 1.4 行为参数化 - 线程
- 1.5 泛型实现的行为参数化
- 1.6 小结
- 2 Lambda表达式
- 2.1 Lambda表达式的组成
- 2.2 函数式接口
- 2.2.1 Predicate
- 2.2.2 Consumer
- 2.2.3 Function
- 2.2.4 函数式接口列表
- 2.3 方法引用
- 2.3.1 方法引用的类别
- 2.3.2 构造函数引用
- 2.4 复合方法
- 2.4.1 Comparator复合
- 2.4.2 Predicate复合
- 2.4.3 Function复合
- 3 流处理
- 3.1 流简介
- 3.1.1 流的定义
- 3.1.2 流的特点
- 3.2 流操作
- 3.2.1 中间操作
- 3.2.2 终端操作
- 3.3.3 构建流
- 3.3 流API
- 3.3.1 flatMap的用法
- 3.3.2 reduce的用法
- 3.4 collect操作
- 3.4.1 collect示例
- 3.4.2 Collector接口