ZSet 底层跳表原理
面试官问:"Redis ZSet 的底层结构是什么?"
小刘说:"跳表和哈希表。"
面试官追问:"跳表是怎么实现的?为什么不用红黑树?"
小刘说:"...跳表更快?"
面试官继续追问:"跳表每一层是怎么决定跳多远的?"
小刘彻底卡住了。
跳表是 Redis 面试中的高频深水区题。这道题能说清楚"跳表 vs 红黑树"和"为什么跳表用随机层级"的候选人,对数据结构有较深的理解。
一、跳表的数据结构 🔴
1.1 跳表 vs 链表
1.2 跳表节点结构
1.3 跳表图示
二、跳表的操作 🔴
2.1 查找过程
2.2 插入过程
2.3 层级概率模型
三、跳表 vs 红黑树 🟡
3.1 为什么 Redis 用跳表而不是红黑树?
Redis 选择跳表的原因:
- 范围查询更简单:跳表天然按序排列,范围查询只需找到起点然后顺序遍历
- 实现简单:跳表只有插入/删除,没有旋转操作
- 便于逆序遍历:跳表每个节点有 backward 指针
3.2 ❌ 错误示范
候选人原话:"跳表比红黑树快,所以 Redis 选跳表。"
问题诊断:两者复杂度相同。Redis 选跳表是因为实现简单和范围查询方便,不是因为性能差异。
候选人原话 2:"跳表的层数是固定的。"
问题诊断:跳表每层的跨度是随机的,通过概率模型决定。随机层数保证了跳表的平衡性。
【面试官心理】 这道题我能从多个角度追问。比如我会问:"跳表和红黑树的内存占用差多少?"能说出"跳表每个节点有多个 forward 指针,红黑树只有 2~3 个"的候选人,说明他真正理解了两者的空间差异。
四、ZSet 的双重索引 🟡
4.1 为什么 ZSet 需要 dict?
4.2 一致性保证
4.3 内存开销
【面试官心理】 ZSet 的双重索引是 Redis 设计中的经典权衡问题。能说清楚 dict 和 skiplist 各司其职、以及为什么需要 dict 的候选人,说明他对 Redis 的数据结构设计有深入理解。