Appearance
Redis Zset(有序集合)
概述
Zset是Redis中一种特殊的数据结构,它在Set的基础上为每个元素关联了一个分数(score),使得元素可以按照分数进行排序。
底层实现
编码方式
Zset支持两种底层实现:
ziplist(压缩列表)
- 元素数量 < 128 且 每个元素 < 64字节
- 优点:内存紧凑
- 缺点:插入/删除O(N)
skiplist + dict(跳表 + 哈希表)
- 元素数量 >= 128 或 有元素 >= 64字节
- 优点:查找/插入O(logN)
- 缺点:内存开销较大
数据结构
c
// Redis源码中的zset结构
typedef struct zset {
dict *dict; // 哈希表,O(1)查找元素
zskiplist *zsl; // 跳表,按score有序
} zset;跳表原理
Level 3: [head] -----> [node5: score=90] ----------------------> [NULL]
Level 2: [head] -> [node2: score=20] -> [node5: score=90] -> [NULL]
Level 1: [head] -> [node1: score=10] -> [node2: score=20] -> [node3: score=50] -> [node5: score=90] -> [NULL]
Level 0: [head] -> [node1] -> [node2] -> [node3] -> [node4] -> [node5] -> [NULL]跳表本质是多层链表,最高32层,每层是原链表的有序子集。
常用命令
基本操作
bash
# 添加元素
ZADD mykey 100 member1 # 添加单个
ZADD mykey 100 member1 200 member2 300 member3 # 批量添加
# 获取分数
ZSCORE mykey member1
# 获取排名(从0开始,score升序)
ZRANK mykey member1
ZREVRANK mykey member1 # 倒序排名
# 分数范围查询
ZRANGEBYSCORE mykey 100 200 # 升序
ZREVRANGEBYSCORE mykey 200 100 # 降序
# 元素数量
ZCARD mykey
# 分数范围元素数量
ZCOUNT mykey 100 200有序集合操作
bash
# 获取元素(带分数)
ZRANGE mykey 0 -1 WITHSCORES
# 交集
ZUNIONSTORE dest 2 key1 key2
# 并集权重
ZUNIONSTORE dest 2 key1 key2 WEIGHTS 1 2
# 交集
ZINTERSTORE dest 2 key1 key2面试考点
Q1: Zset为什么用跳表而不是红黑树?
答案:
- 跳表实现更简单,代码可读性好
- 范围查询(ZRANGE)更高效:O(logN + M),红黑树需要O(logN + M)
- 跳表插入不需要旋转,比红黑树更简单
- 内存利用率更高:平均每个节点1.33个指针
Q2: Zset如何实现排名计算?
答案:
- 使用ZRANK命令,从跳表中找到元素在第几层
- 沿搜索路径向下累加rank
- 时间复杂度O(logN)
Q3: Zset的ziplist转skiplist条件?
答案:
- 元素数量 >= 128
- 或 任意元素长度 >= 64字节
Q4: Zset的应用场景?
答案:
- 排行榜(游戏排行榜、热门文章)
- 延时队列(按时间戳排序的任务)
- 权重队列(带权重的任务调度)
- 分布式锁(带过期时间的锁)
