Redis数据结构二之SDS和双向链表

这篇具有很好参考价值的文章主要介绍了Redis数据结构二之SDS和双向链表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文首发于公众号:Hunter后端
原文链接:Redis数据结构二之SDS和双向链表

这一篇笔记介绍一下 SDS(simple dynamic string)和双向链表。

以下是本篇笔记目录:

  1. SDS
    1. 常数复杂度获取字符串长度
    2. 杜绝缓冲区溢出
    3. 减少修改字符串带来的内存重分配次数
    4. 二进制安全
    5. 兼容C字符串函数
  2. 双向链表

1、 SDS

SDS,simple dynamic string,即简单动态字符串

SDS 在 Redis 2.9 版本中数据结构如下:

struct sdshdr {
    int len;
    int free;
    char buf[];
};

在这个结构中,len 表示 buf 数组中已使用字节的数量,free 表示 buf 数组中未使用字节的数量,buf 则表示是一个 char 类型的数组。

Redis 没有复用 C字符串,有以下几个方面的考虑和优点。

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

C字符串并不记录自身的长度信息,如果要获取C字符串的长度,必须遍历整个字符串然后计数。

SDS 结构中有 len 属性记录 SDS 本身的长度,可以直接获取。

2. 杜绝缓冲区溢出

因为 C字符串并不记录自身的长度信息,在执行某些操作,比如拼接字符串的时候,并不会自动查询是否拥有足够内存,那么这个操作可能就会造成缓冲区溢出的问题

而 SDS 执行相应的字符串修改时,其 API 会先检查 SDS 的空间是否需求,不满足则会进行扩展,这个空间分配策略也就是下面要讲的

3. 减少修改字符串带来的内存重分配次数

C字符串每次进行字符串修改时,程序都需要手动进行内存重分配的操作,而 SDS 通过空间预分配和惰性空间释放两种策略对此进行了优化

空间预分配

当 SDS API 对一个 SDS 进行修改并需要对 SDS 进行空间扩展时,程序不仅会为 SDS 分配修改所需要的空间,还会为其分配额外的未使用空间

如果修改之后,SDS 的长度,也就是结构中的 len 属性小于 1MB,那么程序会额外分配同样大小的未使用空间,这个时候,len 属性和 free 属性将相同

如果修改之后,SDS 的长度,也就是结构中的 len 属性大于等于 1MB,那么程序会额外分配 1MB 的未使用空间

惰性空间释放

当需要对SDS保存的字符串进行缩短时,程序并不会重新分配内存来回收多出来的字节,而是会使用 free 属性将这些字节记录下来,以备后面使用

4. 二进制安全

C字符串保存的字符结尾都是以空字符结尾,所以字符串中间不能包含空字符,否则程序读入空字符的时候就会被认为是字符串结尾,因此C字符串只能保存文本数据,不能保存图片、音频等这样的二进制数据

而 SDS 的 API 都是以处理二进制的方式来处理 SDS 中存放在 buf 里的数据,程序不会对数据做任何限制、过滤,所以 SDS 的 API 都是二进制安全的

SDS 使用 len 属性值而不是空字符串来判断字符串是否结束

5. 兼容C字符串函数

虽然SDS的API都是二进制安全的,但是仍然遵循C字符串以空字符结尾的惯例,而且在为 buf 数组分配空间的时候总是会多分配一个字节来容纳这个空字符,所以保存文本数据的 SDS 可以重用一部分C中的函数

以下是 SDS 与 C字符串区别的总结:

C字符串 SDS
获取字符串长度复杂度为 O(N) 获取字符串长度复杂度为O(1)
API是不安全的,可能会造成缓冲区溢出 API是安全的,不会造成缓冲区溢出
修改字符串长度N次必须执行N次内存重分配 修改长度N次最多需要执行N次内存重分配
只能保存文本数据 可以保存文本或者二进制数据
可以使用<string.h>库中函数 可以使用部分

在之后的的 Redis 版本对 SDS 的结构有过更新,将 free 属性换成了 alloc,这个属性表示的意思是分配的空间长度。和之前的 free 属性比较,其关系是 alloc = free + len

2、 双向链表

C 语言没有链表这个结构,所以 Redis 自己设计了一个链表数据结构。

在 Redis 中,链表节点的结构拥有指向前置节点和后置节点的属性。

链表结构则包含链表表头节点、表尾节点、节点长度等属性,便于快速获取链表相关信息。

双向链表是列表对象的底层实现之一,什么情况下使用双向链表作为列表对象的底层实现我们之后再介绍。

以下是链表节点的结构:

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

}listNode;

在链表节点中,拥有前置节点和后置节点的指针构成双向的链表。

以下是链表的结构:

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

在链表结构中,有表头节点和表尾节点可快速定位到链表的头部和尾部,以及用有 len 属性表示链表包含的节点数量。

如果想获取更多后端相关文章,可扫码关注阅读:
Redis数据结构二之SDS和双向链表文章来源地址https://www.toymoban.com/news/detail-482376.html

到了这里,关于Redis数据结构二之SDS和双向链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构—双向链表

    目录 1.  链表的种类 2.  最实用的两种链表类型 3.  实现双向带头循环链表                   3.1 创建头节点         3.2 实现双向循环功能—返回头指针         3.3  尾插           3.4 头插         3.5 尾删         3.6 头删 4.  实现两个重要接口函数  

    2023年04月23日
    浏览(69)
  • 数据结构双向链表

    Hello,好久不见,今天我们讲链表的双向链表,这是一个很厉害的链表,带头双向且循环,学了这个链表,你会发现顺序表的头插头删不再是一个麻烦问题,单链表的尾插尾删也变得简单起来了,那废话不多说,让我们开始我们的学习吧! 首先我们要了解它的物理和逻辑结构

    2024年02月11日
    浏览(45)
  • 数据结构——双向链表

    🍇系列专栏:🌙数据结构 🍉  欢迎关注:👍点赞🍃收藏🔥留言 🍎 博客主页:🌙_麦麦_的博客_CSDN博客-领域博主 🌙如果我们都不能够拥有黑夜,又该怎样去仰望星空?   目录 一、前言 二、正文——双向链表的实现 2.1模块化 2.2 数据类型与结构体定义  2.3链表的初始化

    2024年02月02日
    浏览(48)
  • 数据结构---双向链表

    单向链表:一块内存指向下一个内存。 单链表存在一些缺陷: 1.查找速度慢。 2.不能从后往前找。 3.找不到前驱。 链表的结构分为8种: 1.单向和双向 2.带头和不带头 带头的链表有一个带哨兵位的头结点,这个节点不存储有效数据。 好处 :尾插更方便,不需要二级指针了,

    2024年02月02日
    浏览(46)
  • 数据结构-双向链表

    在单链表那一篇博客中介绍了单链表和双向链表的优缺点,所以此篇博客直接分享怎样实现一个带头双向循环链表。 单链表博客: 首先我们需要写一个结构体,双向带头链表的话需要一个前驱指针prev和一个后驱指针next,前驱指针的作用是方便找尾节点,因为头节点的prev指

    2024年02月05日
    浏览(52)
  • 数据结构 - 双向链表

    文章目录 目录 文章目录 前言 一、什么是双向链表? 双向链表有什么优势? 二、双向链表的设计和实现 1.设计思想 尾增 : 在链表的末尾添加新的元素  头插 : 在链表头部插入节点  删除 : 根据val的值删除节点  查找 : 根据索引的值查找并返回节点 总结 大家好,今天给大家讲解

    2024年02月09日
    浏览(40)
  • 数据结构——实现双向链表

    怎么说呢?光乍一听名字好像很难的样子是吧,那如果你这样认为的话,可就要让你大跌眼镜了哦,其实双向带头循环链表从操作和理解上来说都是要易于单项不带头不循环链表(俗称单链表)的。 咱们就来见识见识吧!希望真的能让你们“大跌眼镜”哈! 双向带头循环链

    2024年02月07日
    浏览(56)
  • 【数据结构】链表的分类和双向链表

    本篇是基于上篇单链表所作,推荐与上篇配合阅读,效果更加 http://t.csdnimg.cn/UhXEj 链表的结构非常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构: 我们一般叫这个头为哨兵位 我们上回讲的单链表就是不带头单项不循环链表。 今天我们要讲带头双向循环的链表。 不过

    2024年01月25日
    浏览(39)
  • 数据结构入门 — 链表详解_双向链表

    数据结构入门 — 双向链表详解 博客主页链接:https://blog.csdn.net/m0_74014525 关注博主,后期持续更新系列文章 文章末尾有源码 *****感谢观看,希望对你有所帮助***** 第一篇:数据结构入门 — 链表详解_单链表 第二篇:数据结构入门 — 链表详解_双向链表 第三篇:数据结构入门

    2024年02月11日
    浏览(48)
  • 数据结构:详解【链表】的实现(单向链表+双向链表)

    1.顺序表的问题和思考 问题: 中间/头部的插入删除,时间复杂度为O(N)。 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗。 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据

    2024年03月26日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包