redis系列之------链表
前言
链表提供了高效的节点重排能力, 以及顺序性的节点访问方式, 并且可以通过增删节点来灵活地调整链表的长度。
作为一种常用数据结构, 链表内置在很多高级的编程语言里面, 因为 Redis 使用的 C 语言并没有内置这种数据结构, 所以 Redis 构建了自己的链表实现。
大家可以把Redis的链表实现,和Java的LinkedList实现进行对比,看下哪个更加厉害一点。
链表定义
1 typedef struct listNode { 2 3 // 前置节点 4 struct listNode *prev; 5 6 // 后置节点 7 struct listNode *next; 8 9 // 节点的值 10 void *value; 11 12 } listNode;
多个 listNode
可以通过 prev
和 next
指针组成双端链表, 如图 3-1 所示。
虽然仅仅使用多个 listNode
结构就可以组成链表, 但使用 adlist.h/list
来持有链表的话, 操作起来会更方便:
1 typedef struct list { 2 3 // 表头节点 4 listNode *head; 5 6 // 表尾节点 7 listNode *tail; 8 9 // 链表所包含的节点数量 10 unsigned long len; 11 12 // 节点值复制函数 13 void *(*dup)(void *ptr); 14 15 // 节点值释放函数 16 void (*free)(void *ptr); 17 18 // 节点值对比函数 19 int (*match)(void *ptr, void *key);
我们可以看到,list包含链表的头节点,尾节点以及长度。这就为链表带来了很多的好处,如下:
- 双端: 链表节点带有
prev
和next
指针, 获取某个节点的前置节点和后置节点的复杂度都是 O(1) 。 - 无环: 表头节点的
prev
指针和表尾节点的next
指针都指向NULL
, 对链表的访问以NULL
为终点。 - 带表头指针和表尾指针: 通过
list
结构的head
指针和tail
指针, 程序获取链表的表头节点和表尾节点的复杂度为 O(1) 。 - 带链表长度计数器: 程序使用
list
结构的len
属性来对list
持有的链表节点进行计数, 程序获取链表中节点数量的复杂度为 O(1)。