Redis中ZSet的底层数据结构跳跃表skiplist,你真的了解吗?
跳跃表(skiplist)是一种可以替代平衡树的数据结构,它允许快速的插入、删除、查找操作,所有操作的平均时间复杂度都是O(logN)。在Redis中,ZSet的底层实现就是跳跃表。
跳跃表的主要特点是:
- 每个节点不仅包含一个指向下一个节点的指针,还可能包含多个指向后续节点的指针,称为“层”(level)。
- 节点在层中的分布不是连续的,而是通过指针的链式操作来实现。
- 查找、插入、删除操作可以在对数平均时间内完成。
下面是一个简单的C语言实现的跳跃表节点和跳跃表结构的示例代码:
#include <stdlib.h>
// 跳跃表节点结构体
typedef struct skiplistNode {
int key;
struct skiplistNode *backward;
struct skiplistNode *down;
struct skiplistNode *next[];
} skiplistNode;
// 跳跃表结构体
typedef struct skiplist {
skiplistNode *header, *tail;
int level;
} skiplist;
// 初始化一个跳跃表
skiplist *skiplistCreate(void) {
int i;
skiplist *sl = malloc(sizeof(*sl));
sl->header = malloc(sizeof(*sl->header));
sl->header->backward = NULL;
sl->header->down = NULL;
for (i = 0; i < SKIPLIST_MAXLEVEL; i++) {
sl->header->next[i] = NULL;
}
sl->tail = NULL;
sl->level = 1;
return sl;
}
// 插入一个节点
void skiplistInsert(skiplist *sl, int key) {
skiplistNode *update[SKIPLIST_MAXLEVEL], *x;
int i;
// 分配一个新节点
x = malloc(sizeof(*x));
x->key = key;
// 生成一个随机层数
int level = random() % SKIPLIST_MAXLEVEL;
x->backward = NULL;
x->down = NULL;
for (i = 0; i < level; i++) {
x->next[i] = NULL;
}
// 找到每层插入位置的前驱节点
for (i = 0; i < level; i++) {
update[i] = sl->header;
while (update[i]->next[i] && update[i]->next[i]->key < key) {
update[i] = update[i]->next[i];
}
}
// 建立前后节点的链接关系
for (i = 0; i < level; i++) {
x->next[i] = update[i]->next[i];
update[i]->next[i] = x;
// 如果有下一层,则建立向下的指针
if (x->next[i]) {
x->next[i]->backward = x;
}
}
// 更新头部和尾部指针
if (sl->level < level) {
sl->level = level;
}
if (x->next[0]) {
x->backward = x->next[0];
x->next[0]->backward = x;
}
sl->tail = x;
}
// 查找一个节点
skiplistNode *skiplistSearch(skiplist *sl, int key) {
skiplistNode *x = sl->header;
for (int i = sl->level - 1; i >= 0; i--) {
while (x->next[i] && x->next[i
评论已关闭