没错,本篇我们要说一说链表在Redis中的应用。本打算写Redis中的列表,但想来想去觉得列表仅仅是Redis链表的一部分,并不能完全说明链表这一数据结构在Redis中的应用。那就说说数据结构链表吧。小伙伴们,开始啦!

注:链表作为列表的底层实现是有条件的。当列表元素数量较多,或者是元素都是特别长的字符串时,才会使用链表作为列表的底层实现;当元素数量特别少,并且元素是特别短的字符串或者是特别小的整型数字时,将使用压缩列表来作为列表的底层实现。如图所示:


基于Redis数据库设计与实现 redis数据结构设计_基于Redis数据库设计与实现

列表中的数据结构示意图

2.1 数据结构:链表

C语言中没有内置这种数据结构(例如Java实现了链表结构 LinkedList),所以Redis需要自己实现链表结构。链表是一种基本的数据结构,就不再详细的说明了。那对于Redis的链表是怎么实现的呢?

2.1.1  链表节点

Redis中的链表节点是怎么实现的呢?每一个链表节点都是使用 ListNode  结构体实现的,ListNode 结构体定义在adlist.h 头文件中。定义如下:

typedef struct ListNode{
    // 前(后)置节点
    struct ListNode *prev;
    struct ListNode *next;
    // 值
    void *value;
}ListNode;

由上述定义可知:

  • Redis中链表是一个双向链,每一个节点都指向前后节点。
  • 每个节点值的类型都是void,可知节点可以保存任意类型的值。也就是说,一个链表中可以保存不同类型的数据。

由多个ListNode组成的链表结构,如下图所示:

                 

基于Redis数据库设计与实现 redis数据结构设计_Redis_02

站在链表结构上来讲,多个节点已经可以组成一个基本的链表了,但对于操作来说,还是需要一些其他信息来管理这个链表。这些信息包括链表长度、头(尾)节点、判断两个节点是否相等、释放节点空间、复制节点,上图仅仅由ListNode 组成的链表无法方便的完成。(注意:“无法方便的完成” 是指可以通过复杂的操作完成,就是复杂、不方便)

2.1.2  list结构体

由于仅仅由ListNode组成的链表不易管理,使用list来持有链表,那么,操作起来就easy多了。list结构体定义在adlist.h中,定义如下:

typedef struct list{
    // 节点头、尾、链表长度
    ListNode *head;
    ListNode *tail;
    unsigned int  len;
    // 复制节点、释放节点、对比节点
    void *(*dup)(void *ptr);
    void *(*free)(void *prt);
    int *(*match)(void *ptr,void *key);
    
}

由上述定义可知:

  • 获取链表长度的复杂度O(1),无需遍历整个链表
  • 获取头尾节点的复杂度O(1)

还有一条就是链表是无环的