当前位置:   article > 正文

12- Redis 中的 链表 数据结构

12- Redis 中的 链表 数据结构

Redis 的 List 对象的底层实现之一就是链表。C 语言本身没有链表这个数据结构,所以 Redis 自己设计了一个链表数据结构。

1. 链表节点结构设计

先来看看【链表节点】结构的样子:

  1. typedef struct listNode {
  2.    //前置节点
  3.    struct listNode *prev;
  4.    //后置节点
  5.    struct listNode *next;
  6.    //节点的值
  7.    void *value;
  8. } listNode;

有前直节点和后置节点,可以看得出,这是一个双向链表。

2. 链表结构设计

不过,Redis 在 listNode 结构体基础上又封装了 list 这个数据结构,这样操作起来会更方便,链表结构如下:

  1. typedef struct list {
  2.    //链表头节点
  3.    listNode *head;
  4.    //链表尾节点
  5.    listNode *tail;
  6.    //节点值复制函数
  7.    void *(*dup)(void *ptr);
  8.    //节点值释放函数
  9.    void (*free)(void *ptr);
  10.    //节点值比较函数
  11.    int (*match)(void *ptr, void *key);
  12.    //链表节点数量
  13.    unsigned long len;
  14. } list;

list 结构为链表提供了链表头指针 head、链表尾节点 tail、链表节点数量 len 以及可以自定义实现的 dup、free、match 函数。

举个例子,下面是由 list 结构和 3 个 listNode 结构组成的链表:

3. 链表的优势与缺陷

Redis 的链表实现优点如下:

  • listNode 链表节点的结构里带有 prev 和 next 指针,获取某个节点的前置节点或后置节点的时间复杂度只需 O(1),而且这两个指针都可以指向 NULL,所以链表是无环链表

  • list 结构因为提供了表头指针 head 和 表尾节点 tail,所以获取链表的表头节点和表尾节点的时间复杂度只需 O(1)

  • list 结构因为提供了链表节点数量 len,所以获取链表中的节点数量的时间复杂度只需 O(1)

  • listNode 链表节使用 void* 指针保存节点值,并且可以通过 list 结构的 dup、free、match 函数指针为节点设置该节点类型特定的函数,因此链表节点可以保存各种不同类型的值

链表的缺陷也是有的:

  • 链表每个节点之间的内存都是不连续的,意味着无法很好的利用 CPU 缓存。能很好利用 CPU 缓存的数据结构就是数组,因为数组的内存是连续的,这样就可以充分利用 CPU 缓存来加速访问。

  • 还有一点,保存一个链表节点的值都需要一个链表节点结构头的分配,内存开销较大

因此,Redis 3.0 的 List 对象在数据量比较少的情况下,会采用【压缩列表】作为底层数据结构的实现,它的优势就是节省内存空间,并且是内存紧凑型的数据结构。

不过,压缩列表存在性能问题(具体问题后面会说),所以 Redis 在 3.2 版本设计了新的数据结构 quicklist,并将 List 对象的底层数据结构改由 quicklist 实现。

然后在 Redis 5.0 设计了新的数据结构 listpack,沿用了压缩列表紧凑型的内存布局,最终在最新的 Redis 版本,将 Hash 对象和 Zset 对象的底层数据结构实现之一的压缩列表,替换成由 listpack 实现。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/675685
推荐阅读
相关标签
  

闽ICP备14008679号