Redis系列之底层数据结构具体实现(双向列表)

419 阅读2分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

今天说一下Redis 列表类型的底层实现双向链表。

链表是一个比较常见的数据结构,C 语言本身不支持链表类型,但是列表类型需要用到,所以Redis自己实现了一个双向链表。

链表定义

链表节点的定义

typedef struct listNode{
  // 前置节点
  struct listNode *prev;
  // 后置节点
  struct listNode *next;
  // 节点的值
  void *value;
}listNode

链表结构List 定义

typedef struct list {
  // 表头结点
  listNode *head;
  // 表尾节点
  listNode *tail;
  // 链表所包含的节点数量
  unsigned long len;
  // 其他函数
  ...
}list;

整体结构图

listnode.png

注意 表头结点的 prev 指针和表尾结点的 next 指针都指向 null, 所以 Redis 的链表是一个无环链表。

双向链表的优缺点

优点

  • 由于链表节点中定义了当前节点的前置节点和后置节点,所以在查询时复杂度为O(1)。

  • 由于在List中定义了链表包含的节点,所以查询链表长度的复杂度为O(1),对用的命令为 LLEN。

  • 由于在List中定义了链表的表头节点和表尾节点,对链表的表头和表尾进行插入的复杂度都为O(1),查询表头和表尾数据同样复杂度为O(1),对应的命令为 LPUSH、 RPUSH、 LPOP、 RPOP 等。

  • 链表中的节点由prev 和 next 两个指针相连,所以可以不在一块连续的内存中,更合理的利用空间,但这也增加了寻址的时间。

  • 在操作过程中,删除、修改、增加数据,虽然在查询时,复杂度比较高,但是进行这些操作的时候却比较简单,不会影响其他的元素。

缺点

由于链表的结构导致,在进行范围查询和等值查询时,复杂度为O(N),因此在执行LRANGE、listIndex等命令的时候,如果链表很长,由于复杂度比较高,可能会造成阻塞。

结尾

其实Redis的List类型是由两种底层数据结构实现的,另外一种是压缩列表,听名字就能够联想到,这种结构可以更节省空间。下一篇接着说压缩列表的实现。