【面试】Redis底层数据结构——SkipList跳跃表

SkipList跳跃表

有序的数据结构,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。

平均时间复杂度: O ( l o g N ) O(logN)

底层无索引的链表:
跳跃表-底层数据链路

带索引,如果需要找中间的某个节点,比如寻找 42 ,过程大概是这样的:
在这里插入图片描述

数据结构

哈希表结构

作为字典的底层实现

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;//指向zskiplistNode的头、尾节点
    unsigned long length;//底层节点的个数
    int level;//当前最高索引层数
} zskiplist;

跳跃表节点

typedef struct zskiplistNode {
    sds ele;
    double score;//分数
    struct zskiplistNode *backward;//前一个节点的指针
    struct zskiplistLevel {
        struct zskiplistNode *forward;//下一个节点的指针
        unsigned int span;
    } level[];//该节点在哪一些层级嗯。
} zskiplistNode;

在这里插入图片描述

插入节点

在最底层的数据链表中插入数据,然后调整索引;
其中每一层的索引链表中是否需要增加新增的节点,其实并没有什么标准答案,我们尽量做到索引的平均分布即可,常用的就是【随机判断】决定是否需要新增或调整索引,当有新节点插入的时候,通过概率算法判断这个节点需要插入到几级节点中。
比如:

  • 底层数据链表有 N 个元素,随机选择 N/2 个元素作为 1 级索引,随机选择 N/4 个元素作为 2 级索引…一直到顶层索引;
  • 新插入数据节点,1/2 概率不插入任何一级索引,1/4 概率返回需要插入 1 级索引,1/8 概率返回需要插入到 2 级索引,以此类推;
  • 这里要注意一点,插入 2 级索引的时候,同时也需要插入 1 级索引;也就是插入 n 级索引的时候,同时也要插入 1~( n-1 ) 级索引。
    在这里插入图片描述

删除节点

删除数据节点,并删除每一层的索引节点

总结

  1. 可以把跳跃表看成多个有序链表(最底层的数据链表+多层索引链表);
  2. 查找的过程中,从最长层开始查找,找到对应的区间再到下一层查找 ;
  3. 每个节点都有两个指针,分别指向右边和下边;
  4. 插入新节点时,随机判断该节点是否要插入索引,最高插入几级索引;
  5. 插入 n 级索引的时候,同时也要插入 1~(n-1) 级索引;
  6. 跳跃表和红黑树等平衡树相比,更容易实现,并且不需要维护平衡性;
  7. Redis 中的 ZSet 的一种实现方式是 skipList 与 hashTable 的结合;
  8. Google 的 LevelDB 、Facebook 的 RocksDB ,它们都是使用了跳跃表这种数据结构。

猜你喜欢

转载自blog.csdn.net/weixin_42322309/article/details/105954389