一、linkedlist 简介

由于 C 语言没有内置链表这种数据结构,于是 Redis 构建了自己的链表实现。linkedlist 是一个双端链表,也是 list 数据类型的底层实现之一。当一个 list 包含了数量比较多的元素,又或者 list 中包含的元素都是比较长的字符串时,Redis就会使用 linkedlist 作为 list 的底层实现。当一个 lsit 只包含少量的元素,并且每个 list 要么就是小整数值,要么就是长度比较短的字符串,那么 Redis 就会使用 ziplist 作为 list 的底层实现。

二、linkedlist 结构

每个链表节点使用一个 adlist.h/listNode 结构来表示:

redis skiplist数据结构 redis数据结构list底层_双端链表


pre 指针指向前一个节点,next 指针指向后一个节点,value 指向当前节点对应的数据对象。


虽然仅仅使用多个 listNode 结构就可以组成链表, 但使用 adlist.h/list 来持有链表的话, 操作起来会更方便:

redis skiplist数据结构 redis数据结构list底层_redis skiplist数据结构_02


list 结构为链表提供了表头指针 head、表尾指针 tail,以及链表长度计数器 len,而 dup、free 和 match 成员则是用于实现多态链表所需的类型特定函数:

1、dup 函数用于复制链表节点所保存的值;

2、free 函数用于释放链表节点所保存的值;

3、match 函数则用于对比链表节点所保存的值和另一个输入值是否相等。

双端链表结构图:

redis skiplist数据结构 redis数据结构list底层_redis skiplist数据结构_03

三、linkedlist 特性

1、双端链表:带有指向前置节点 prev 和后置节点 next 的指针,获取这两个节点的复杂度为 O(1)

2、无环:表头节点的 prev 和表尾节点的 next 都指向 NULL,对链表的访问以 NULL 结束

3、带表头指针和表尾指针:获取表头节点 head 和表尾节点 tail 的复制度为 O(1)

4、链表长度计数器:带有 len 属性,获取链表长度的复杂度为 O(1)

5、多态:链表节点使用 void* 指针保存节点值,可以保存不同类型的值

缺点:查找效率偏低,只能使用顺序查找

四、总结

双端链表 linkedlist 主要有两个作用:

1、作为 Redis 的 list 数据类型底层实现方法之一;

2、作为通用数据结构可以被其他功能模块使用;

双端链表实现简单,Redis 对双端链表加以改造,添加保存节点长度的字段,以及实现自己的迭代指针,使得一些数据操作变得简单。