Redis笔记1-数据结构

1、简单动态字符串

Redis不直接使用C传统的字符串表示,构建了简单动态字符串(Simple Dynamic String, SDS)的抽象类型,并将SDS作为Redis的默认字符串表示

SDS定义

struct sdshdr{
    
    
  int len;  //记录buf数组已使用字节的数量,等于SDS所保存字符串长度
  int free;  //记录buf数组未使用字节的数量
  char buf[];  //字节数组,用于保存字符串
}

SDS优点

重用C库函数

SDS遵循C字符串以空字符结尾的惯例,因此可以重用一部分C库的函数

常数复杂度获取字符串长度

获取字符串长度时间复杂度为O(1)。(访问SDS.len属性)

杜绝缓冲区溢出

当SDS的API需要对SDS进行修改,API会先检查SDS的空间释放满足修改要求,如果不满足会自动扩充

减少修改字符串时内存重分配次数

内存重分配解释:
对于一个包含N个字符的C字符串,其底层实现是一个N+1字符长的数组,每次增加或缩短一个字符串都要对字符串数组进行内存重分配

  • 增长字符串:先通过内存重分配扩展底层数组空间大小,否则造成缓冲区溢出
  • 缩短字符串:需通过内存重分配释放不再使用的空间,否则造成内存泄露

通过free属性记录的未使用空间,实现空间预分配和惰性空间释放

Redis作为数据库,需频繁增删字符串,太多内存重分配的操作会影响性能,因此通过free属性解除字符串长度和底层数组长度的关联。

二进制安全

C字符串的字符必须符合某种编码(如ASCII),并且除了末尾,不能包含空字符,会被误认为结尾。因此C字符串只能保存文本数据,而不能保存二进制数据(如图片,音频)。
SDS的API会以处理二进制的方式处理buf数组的数据,这也是buf属性称为字节数组的原因
并且使用len属性判断字符串是否结束。

SDS API

在这里插入图片描述
在这里插入图片描述

2、链表

Redis也构建了自己的链表实现,列表键的实现之一就是链表。
当列表键包含数量较多的元素,或包含的元素都是比较长的字符串,就会使用链表作为列表键的底层实现。
发布与订阅,慢查询,监视器等功能也用到链表,Redis服务器本身还使用链表保存多个客户端的状态信息,以及使用链表构建客户端输出缓冲区。

链表和链表节点实现

链表节点:ListNode

typedef struct listNode{
    
    
  struct listNode *prev;
  struct listNode *next;
  void *value;
}

多个ListNode可以组成双链表。

链表:list

typedef struct list{
    
    
  listNode* head;
  listNode* tail;
  unsigned long len;  //链表节点数量
  void *(*dup)(void *ptr);  //节点值复制函数
  void *(*free)(void *ptr); //节点值释放函数 
  int (*match)(void *ptr, void *key);  //节点值对比函数
}

dup、free、match成员是用于实现多态链表所需的类型特定函数

特性总结

  • 双端:prev和next指针获取前置和后置节点,复杂度O(1)
  • 无环:表头的prev和表尾的next指向NULL
  • 带表头指针和表尾指针:head和tail获取表头和表尾节点,复杂度O(1)
  • 带链表长度计数器:len属性
  • 多态:用void*指针保存节点值,可以保存不同类型的值

链表和链表节点API

在这里插入图片描述
在这里插入图片描述

3、字典

4、跳表

5、集合

6、压缩列表

7、对象

(待补充)

猜你喜欢

转载自blog.csdn.net/MinutkiBegut/article/details/115235915