双端链表的实现由listNode 和list 两个数据结构构成,下图展示了由这两个结构组成的一
个双端链表实例:
typedef struct listNode { //双端链表的节点
// 前驱节点
struct listNode *prev; //listNode 带有prev 和next 两个指针,因此,对链表的遍历可以在两个方向上进行:从表头到表 尾,或者从表尾到表头。
// 后继节点
struct listNode *next;
// 值
void *value;
}
typedef struct list { //双端链表本身
// 表头指针
listNode *head; //list 保存了head 和tail 两个指针,因此,对链表的表头和表尾进行插入的复杂度为(1) ——这是高效 实现LPUSH 、RPOP 、RPOPLPUSH 等命令的关键
// 表尾指针
listNode *tail;
// 节点数量
unsigned long len; //list 带有保存节点数量的len 属性,所以计算链表长度的复杂度仅为(1) ,这也保证了LLEN 命令不 会成为性能瓶颈
// 复制函数 用于新增节点
void *(*dup)(void *ptr);
// 释放函数 用于删除节点
void (*free)(void *ptr);
// 比对函数
int (*match)(void *ptr, void *key);
}
小结:
双端链表及其节点的性能特性如下:
– 节点带有前驱和后继指针,访问前驱节点和后继节点的复杂度为O(1) ,并且对链表
的迭代可以在从表头到表尾和从表尾到表头两个方向进行;
– 链表带有指向表头和表尾的指针,因此对表头和表尾进行处理的复杂度为O(1) ;
– 链表带有记录节点数量的属性,所以可以在O(1) 复杂度内返回链表的节点数量(长
度);