深入了解Redis——数据结构:链表
链表
链表是一种数据结构,在redis中原生支持链表(list)的使用,redis链表主要具有以下特点:
- 能够保证节点的顺序
- 提供对节点的增删操作从而灵活改变链表的长度
- 提供对节点的高效排序能力
- 由于C语言没有内置原生支持链表,所以redis的链表实现是自己构建实现的
- redis自身很多功能用到了链表这种数据结构,如监视器、慢查询、发布订阅等等等等
节点及链表结构
- 链表的节点
查看redis的源码(adlist.h),可以看到链表的节点结构如下:
/*
* 双端链表节点
*/
typedef struct listNode {
// 前置节点
struct listNode *prev;
// 后置节点
struct listNode *next;
// 节点的值
void *value;
} listNode;
可以看出每一个节点由指向前一个和后一个节点的指针,以及节点存储的内容三部分组成。
- 多个节点组成链表,可以从源码看到(adlist.h):
/*
* 双端链表结构
*/
typedef struct list {
// 表头节点
listNode *head;
// 表尾节点
listNode *tail;
// 节点值复制函数
void *(*dup)(void *ptr);
// 节点值释放函数
void (*free)(void *ptr);
// 节点值对比函数
int (*match)(void *ptr, void *key);
// 链表所包含的节点数量
unsigned long len;
} list;
具体的结构可以抽象为如下的模式:
- head:表头指针
- tail:表尾指针
- len:链表长度计数
- dup:用于复制链表节点所保存的值的方法
- free:用于释放链表节点所保存的值的方法
- match:用于对比链表节点所保存的值和另一个输入值是否相等的方法
redis链表的特性
- 双端指针:每个节点都有指向前后节点的两个指针,使得获取前后节点的复杂度降低为O(1)
- 非环形链表:表头节点前指针和表尾节点的后指针都指向NULL,故链表的结束以NULL作为终点
- 链表长度计数器:使得链表的长度获取复杂度为O(1)
- 链表头和尾双指针:头尾双指针,使得查询复杂度降低
- 多态的支持:每个链表节点通过一个void*指针保存value,并且内置三个属性函数,使得链表支持可以保存各种不同类型的数据值