引言

跳跃表(skip list) 可以媲美平衡树(AVL Tree),是一种 插入/删除/搜索 都是 O(logN) 的数据结构。
它最大的优势是原理简单、容易实现、方便扩展、效率更高。
因此在一些热门的项目里用来替代平衡树,如 redis, leveldb 等。

在redis中,有序集合键与集群节点中用到跳跃表。

1、数据结构

跳跃表的数据结构有两部分组成:zskiplistNode和zskiplist,位于redis.h源码中。

1.1、跳跃表节点zskiplistNode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* ZSETs use a specialized version of Skiplists */
/*
* 跳跃表节点
*/
typedef struct zskiplistNode {
// 成员对象
robj *obj;
// 分值
double score;
// 后退指针
struct zskiplistNode *backward;
// 层
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 跨度
unsigned int span;
} level[];
} zskiplistNode;

1.2、跳跃表zskiplist

1
2
3
4
5
6
7
8
9
10
11
/*
* 跳跃表
*/
typedef struct zskiplist {
// 表头节点和表尾节点
struct zskiplistNode *header, *tail;
// 表中节点的数量
unsigned long length;
// 表中层数最大的节点的层数
int level;
} zskiplist;

2、使用

如下图所示,比如我们要查找8,先在最上层L2查找,发现在1和9之间;
然后去L1层查找,发现在5和9之间;
然后去L0查找,发现在7和9之间,然后找到8。

跳跃表.jpg

图片及例子来源于:Redis基本类型及其数据结构

3、注意

  • 同一个跳跃表中,多个节点的score可以相同,但是成员对象必须唯一
  • 按照score,从小到大排序
  • 如果score相同,按照成员对象大小排序

tencent.jpg