Skip to content
困难

一句话答案

跳表是多层有序链表,逐层跳跃实现 O(logn) 查找,Redis 选它因为实现简单、范围查询方便、并发友好。

核心要点

ZSet 的双重底层结构(同时维护两个):

ZSet
├── hashtable(哈希表):member → score 的映射
│   作用:O(1) 查找某个 member 的 score(ZSCORE 命令)

└── skiplist(跳表):按 score 排序的有序索引
    作用:O(log N) 范围查询、排名查询(ZRANGE、ZRANK 命令)

为什么要同时维护两个结构?

  • 只有跳表:ZSCORE 需要 O(log N),不够快
  • 只有哈希表:无法做有序范围查询(ZRANGE、ZRANGEBYSCORE)
  • 两者结合:以额外内存换取两种查询都 O(1)/O(log N)

编码切换(小数据量优化内存):

当同时满足以下两个条件时,使用 listpack(紧凑型双向链表,省内存):
  - 元素数量 <= 128(默认)
  - 每个元素 value 长度 <= 64 字节(默认)

超过任一阈值 → 转换为 skiplist + hashtable
追问与易错

追问方向:

  • ZSet 什么时候用 ziplist?
  • 跳表层数怎么决定?
  • 为什么概率是 1/4?

易错点:

  • ❌ 跳表和红黑树性能一样——跳表范围查询更好
  • ❌ ZSet 的 skiplist 就是标准跳表——Redis 做了优化

💡 记忆锚点

跳表 = 书的目录系统:底层是逐页翻(链表),加了章目录、节目录(多级索引)后O(logN)快速定位。Redis选跳表不选红黑树,因为跳表范围查询天然顺序遍历,实现简单,面试记住"实现简单+范围查询方便"两个理由。