跳跃表(Skip List)是一种基于链表的数据结构,它可以实现诸如有序集合(Sorted Set)等数据结构,能够提供平均 O(log n) 的查找效率。Redis中就使用跳跃表来实现有序集合。

1. 跳跃表简介

在一般的链表中,如果我们需要查询一个元素,可能需要遍历链表,这样的时间复杂度是O(n)。而跳跃表通过维护一个多层的链表,为链表查询提供了“快速通道”。

在跳跃表中,每一个节点包含多个“层”,每一层都有一个前进指针指向下一个节点,通过这种方式,跳跃表能够在横向和纵向上进行查询,大大提高了查询效率。

2. Redis中的跳跃表实现

在Redis中,跳跃表由zskiplistzskiplistNode两种结构构成:

typedef struct zskiplistNode {
    robj *obj;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned int span;
    } level[];
} zskiplistNode;

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;
    int level;
} zskiplist;

其中,zskiplist保存了跳跃表的信息,包括头节点、尾节点以及长度等信息,而zskiplistNode则用于表示跳跃表的节点。

每个跳跃表节点包含以下信息:

  • 层(level):每个节点包含多个层,每一层都包含一个前进指针(forward)和一个跨度(span)。
  • 前进指针(forward):指向同一层中的下一个节点。通过前进指针,跳跃表可以在同一层中快速地定位目标节点。
  • 跨度(span):记录前进指针所跨越的节点个数。跨度的作用是在跳跃表中快速定位目标节点。
  • 后退指针(backward):指向同一层中的前一个节点。通过后退指针,跳跃表可以在同一层中快速地定位前一个节点。

在Redis的有序集合中,跳跃表起到了至关重要的作用。通过高效的查找、插入和删除操作,为Redis提供了强大的性能支持。

3. 跳跃表的查询、插入与删除

跳跃表的查询、插入和删除操作都能够在O(log n)的时间复杂度内完成,这是因为跳跃表中的每一个节点都包含了多个层,这些层通过前进指针和后退指针,实现了在不同层之间的快速跳转。