Redis 数据结构-双向链表
Redis 数据结构-双向链表
最是人间留不住,朱颜辞镜花辞树。
1、简介
Redis 之所以快主要得益于它的数据结构、操作内存数据库、单线程和多路 I/O 复用模型,进一步窥探下它常见的五种基本数据的底层数据结构。
Redis 常见数据类型对应的的底层数据结构。
- String:简单动态字符串。
- List:双向链表、压缩列表。
- Hash:压缩列表、哈希表。
- Sorted Set:压缩列表、跳表。
- Set:哈希表、整数数组。

2、双向链表
C 语言是没有内置链表这种结构,而当一个列表键包含较多的元素,或者列表中包含的元素都是比较长的字符串的时,Redis 就会使用链表作为 list 的底层实现,就自己实现了双向链表,相当于Java 语言中的LinkedList,但又不完全是。
单纯的链表优缺点:
- 双向链表数据结构,支持前后顺序遍历。
- 不需要连续的的内存空间,插入和删除的时间复杂度是 O(1) 级别的,效率较高。
- 比起数组它的缺点就是查询较慢(时间复杂度O(n))。

常见使用场景
双向链表的特性经常被用于异步队列的使用。实际开发中将需要延后处理的任务结构体序列化成字符串,放入Redis 的队列中,另一个线程从这个列表中获取数据进行后续的业务逻辑。

链表节点结构
从redis/src/adlist.h 源码文件中查看链表节点结构设计。

1 typedef struct listNode {
2 struct listNode *prev; // 前置节点,如果是list的头结点,则prev指向NULL
3 struct listNode *next;// 后置节点,如果是list尾部结点,则next指向NULL
4 void *value; // 记录该节点的值,能够存放任何信息(也叫万能节点)
5 } listNode;
从listNode 结构中看到一个节点由头指针 prev 、尾指针 next 以及节点的值 value 组成,这种有前置节点和后置节点很明显就是一个双向链表。

链表结构
为了方便操作,Redis 在 listNode 链表节点结构体基础上又封装了 list 这个数据结构,而且封装之后,还提供了头节点、尾节点以及一些自定义的函数。链表结构如下:

1 typedef struct list {
2 listNode *head; // 链表 头结点 指针
3 listNode *tail; // 链表 尾结点 指针
4 unsigned long len; // 链表长度计数器 即 节点的个数
5
6 // 三个函数指针
7 void *(*dup)(void *ptr); // 复制函数 复制链表节点保存的值
8 void (*free)(void *ptr); // 释放函数 释放链表节点保存的值
9 int (*match)(void *ptr, void *key); // 匹配函数 查找节点时使用 比较链表节点所保存的节点值和另一个输入的值是否相等
10 } list;
list 结构为链表提供了链表头指针 head、链表尾节点 tail、链表节点数量 len、以及可以自定义实现的 dup、free、match 函数。
- head:链表 头结点 指针,指向了双向链表的最开始的一个节点;
- tail:链表 尾结点 指针,指向了双向链表的最后一个节点;
- len:代表了双向链表节点的数量;
- dup:复制函数,用于复制双向链表节点所保存的值;
- free:释放函数,用于释放双向链表节点所保存的值;
- match:匹配函数,用于对比双向链表节点所保存的值和另外一个的输入值是否相等。

相关命令
右进左出(队列)
队列在结构上是先进先出(FIFO)的数据结构(比如排队购票的顺序),常见场景如消息排队、异步处理等,用于确保元素的访问顺序。
lpush -> 从左边边添加元素
127.0.0.1:6379> lpush tjt_list 1 2 3
rpush -> 从右边添加元素
127.0.0.1:6379> rpush tjt_list 1 2 3
llen -> 获取列表的长度
127.0.0.1:6379> llen tjt_list
lpop -> 从左边弹出元素
127.0.0.1:6379> lpop tjt_list

右进右出(栈)
栈在结构上是先进后出(FILO)的数据结构(比如弹夹压入子弹,子弹被射击出去的顺序就是栈),这种数据结构一般用来处理一些逆序输出的业务场景。
lpush -> 从左边边添加元素
127.0.0.1:6379> lpush tjt_list 1 2 3
rpush -> 从右边添加元素
127.0.0.1:6379> rpush tjt_list 1 2 3
rpop -> 从右边弹出元素
127.0.0.1:6379> rpop tjt_list

慢操作
由于列表(list)的链表数据结构,它的遍历是慢操作,所以涉及到遍历的性能将会随着遍历区间range 的增大而增大。在Redis 链表中,list 的索引运行为负数,-1代表倒数第一个,-2代表倒数第二个,其它同理。
lindex -> 遍历获取列表指定索引处的值(下方所有为 0)
127.0.0.1:6379> lindex tjt_list 0
"you"
lrange -> 获取从索引start 到stop 处的全部值
127.0.0.1:6379> lrange tjt_list 0 -1
1) "you"
2) "will"
3) "never"
4) "know"
ltrim -> 截取并保存索引start 到stop 处的全部值,其它将会被删除
127.0.0.1:6379> ltrim tjt_list 1 -1
OK
127.0.0.1:6379> lrange tjt_list 0 -1
1) "will"
2) "never"
3) "know"

非普通LinkedList
前面提到了Redis 数据类型List 对应的的底层数据结构有 双向链表 和 压缩列表,因为 Redis底层存储list(列表)不是一个简单的LinkedList,而是quicklist 快速列表。
为什么用quicklist 替代LinkedList
普通的LinkedList node节点元素,都会持有一个prev-> 执行前一个node 节点和next-> 指向后一个node 节点的指针(引用),这种结构虽然支持前后顺序遍历,但是也带来了不小的内存开销,如果node 节点仅仅是一个int 类型的值,那么引用的内存比例将会更大。所以Redis 底层对于list(列表)的存储,当元素个数少的时候,它会使用一块连续的内存空间来存储,这样可以减少每个元素增加prev 和next 指针带来的内存消耗,减少内存碎片化问题。
quicklist
quicklist 是多个ziplist (压缩列表)组成的双向列表。

ziplist
ziplist是一块连续的内存地址,他们之间无需持有prev和next指针,能通过地址顺序寻址访问。

3、链表小结
链表优势
- listNode 链表节点的结构里带有 prev 和 next 指针,获取某个节点的前置节点或后置节点的时间复杂度只需O(1),而且这两个指针都可以指向 NULL,所以链表是无环链表,对双向链表的访问以 NULL 结束;
- list 结构因为提供了表头指针 head 和表尾节点 tail,所以获取链表的表头、表尾节点的时间复杂度都是 O(1);
- list 结构因为提供了链表节点数量 len,通过 len 属性直接获取节点的数量,时间复杂度为 O(1) , 效率高;
- listNode 链表节使用 void* 指针保存节点值,并且可以通过 list 结构的 dup、free、match 函数指针为节点设置该节点类型特定的函数,因此链表节点可以保存各种不同类型的值。
链表缺陷
- 链表每个节点之间的内存都是不连续的,无法很好利用 CPU 缓存。数组数据结构就能很好利用 CPU 缓存,因为数组的内存是连续的,可以充分利用 CPU 缓存来加速访问。
- 保存一个链表节点的值每次都需要为一个链表节点结构头分配空间,内存开销较大。Redis 3.0 的 List 对象在数据量比较少的情况下,会采用 压缩列表 作为底层数据结构的实现,节省内存空间,降低保存链表节点的内存开销。
Redis 数据结构-双向链表的更多相关文章
- redis学习(二) redis数据结构介绍以及常用命令
redis数据结构介绍 我们已经知道redis是一个基于key-value数据存储的数据结构数据库,这里的key指的是string类型,而对应的value则可以是多样的数据结构.其中包括下面五种类型: ...
- 【Redis笔记(四)】 Redis数据结构 - list链表
原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/50573605 经过前面的介绍,我们学习了Redis中string字符串.hash ...
- 【Redis】270- 你需要知道的那些 redis 数据结构
本文出自「掘金社区」,欢迎戳「阅读原文」链接和作者进行技术交流 ?? 作者简介 世宇,一个喜欢吉他.MDD 摄影.自走棋的工程师,属于饿了么上海物流研发部.目前负责的是网格商圈.代理商基础产线,平时喜 ...
- Redis数据结构——quicklist
之前的文章我们曾总结到了Redis数据结构--链表和Redis数据结构--压缩列表这两种数据结构,他们是Redis List(列表)对象的底层实现方式.但是考虑到链表的附加空间相对太高,prev 和 ...
- 为了拿捏 Redis 数据结构,我画了 40 张图(完整版)
大家好,我是小林. Redis 为什么那么快? 除了它是内存数据库,使得所有的操作都在内存上进行之外,还有一个重要因素,它实现的数据结构,使得我们对数据进行增删查改操作时,Redis 能高效的处理. ...
- 40张图+万字,从9个数据类型帮你稳稳的拿捏Redis数据结构
摘要:本文把Redis新旧版本的数据结构说图解一遍,共有 9 种数据结构:SDS.双向链表.压缩列表.哈希表.跳表.整数集合.quicklist.listpack. 本文分享自华为云社区<为了拿 ...
- Redis 数据结构使用场景
转自http://get.ftqq.com/523.get 一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的 ...
- Redis数据结构
Redis数据结构 Redis数据结构详解(一) 前言 Redis和Memcached最大的区别,Redis 除啦支持数据持久化之外,还支持更多的数据类型而不仅仅是简单key-value结构的数据 ...
- Redis数据结构底层知识总结
Redis数据结构底层总结 本篇文章是基于作者黄建宏写的书Redis设计与实现而做的笔记 数据结构与对象 Redis中数据结构的底层实现包括以下对象: 对象 解释 简单动态字符串 字符串的底层实现 链 ...
- Redis 数据结构与内存管理策略(上)
Redis 数据结构与内存管理策略(上) 标签: Redis Redis数据结构 Redis内存管理策略 Redis数据类型 Redis类型映射 Redis 数据类型特点与使用场景 String.Li ...
随机推荐
- 11.MongoDB系列之连接副本集
1. Python连接副本集 from pymongo import MongoClient from bson.codec_options import CodecOptions from retr ...
- 怎样在vue中隐藏el-form-item中的值、设置输入框的值是只读
1.如何在前端vue中隐藏某一个元素(el-form-item怎样隐藏) 给每项表单项添加一个自己的id名,并用v-model绑定相对应的数据,利用v-if根据上一个表单项的数据值来进行显示或隐藏 & ...
- 成功解决Initialization failed for ‘https://start.spring.io‘ Please check URL, network and proxy settings
文章目录 1.问题描述 2.问题的解决方式 2.1 查看网络连接问题 2.2 设置代理 2.3 直接连接阿里云下载模板 1.问题描述 建立springboot项目的时候发现不能初始化成功,我真的栓Q ...
- 齐博x1页面不直接报错,如何排查
有的页面是不会直接报错的,比如像下面这个,这个时候需要你用谷歌或火狐浏览器打开,按F12键进入开发者模式,然后选择Network选项,刷新一下当前的网页,就会看到红色的请求.单独打开他.就可以看到错误 ...
- SLAM中的内外点
内外点之分最简单的说法就是是否符合当前位姿的判断:如果根据当前位姿,之前帧二维特征点所恢复出的地图点重投影到当前帧与实际的二维特征点匹配不上了,那么认为这个是质量差的点是outlier,抛弃掉,如果能 ...
- Pyhton基础部分:6、与用户交互、基础运算符
目录 一.python数据类型 1.布尔值bool 2.元组tuple 3.集合set 二.与用户交互 1.获取用户输入 2.输出内部信息 3.语言环境差异 三.格式化输入 1.代码实现 2.注意事项 ...
- HPL Study 1
1.安装Linux系统 在虚拟机Vmware上安装CentOS 7系统 2.安装OneApi 安装的时候将文件从桌面拖动到虚拟机安装的时候报错:archive corrupted 解决方法:大文件应采 ...
- git 进阶篇
在git使用时,有时需要在公司内部搭建自己的git服务器,用于内部的版本控制. 从远程服务器到本地 先创建服务器端的空git库,将其clone到本地,再将本地的修改push到服务器端 # step1: ...
- Java8新特性:函数式编程
1. 概述 函数式编程学习目的: 能够看懂公司里的代码 大数据量下处理集合效率更高 代码可读性高 消灭嵌套地狱 函数式编程思想: 面向对象思想需要关注用什么对象完成什么事情.而函数式编程思想就类似于我 ...
- 【安装文档】TRex流量分析仪保姆级安装指南--基于VMware虚拟机(ubantu18.04@Intel 82545EM)
前言 既然你已经知道TRex并尝试搜索它的安装教程,这意味着你有一定的基础知识(至少知道自己需要什么).因此本文对于TRex的介绍部分会偏少 本次主要为TRex安装过程的一次记录(版本为v3.0.0) ...