Redis系列(六):数据结构List双向链表LPUSH、LPOP、RPUSH、RPOP、LLEN命令
1.介绍
redis中的list既实现了栈(先进后出)又实现了队列(先进先出)
1.示意图

2.各命令详解
LPUSH/RPUSH
LPUSH:
从队列的左边入队一个或多个元素
将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。
可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。元素是从最左端的到最右端的、一个接一个被插入到 list 的头部。
所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。
RPUSH:
从队列的右边入队一个元素
向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。 当 key 保存的不是一个列表,那么会返回一个错误。
可以使用一个命令把多个元素打入队列,只需要在命令后面指定多个参数。元素是从左到右一个接一个从列表尾部插入。 比如命令 RPUSH mylist a b c 会返回一个列表,其第一个元素是 a ,第二个元素是 b ,第三个元素是 c。
两个命令都返回list的长度
时间复杂度O(1) 相对于i++的操作
127.0.0.1:> lpush mylist c b a
(integer)
127.0.0.1:> rpush mylist d e f
(integer)
127.0.0.1:> lrange mylist
) "a"
) "b"
) "c"
) "d"
) "e"
) "f"
127.0.0.1:>
源码解析
{"rpush",rpushCommand,-,
"write use-memory fast @list",
,NULL,,,,,,},
{"lpush",lpushCommand,-,
"write use-memory fast @list",
,NULL,,,,,,},
LPUSH和RPUSH都是调的同一个函数通过传入LIST_HEAD和LIST_TAIL来判断怎么入队列
void lpushCommand(client *c) {
pushGenericCommand(c,LIST_HEAD);
}
void rpushCommand(client *c) {
pushGenericCommand(c,LIST_TAIL);
}
void pushGenericCommand(client *c, int where) {
int j, pushed = ;
robj *lobj = lookupKeyWrite(c->db,c->argv[]);
if (lobj && lobj->type != OBJ_LIST) {
addReply(c,shared.wrongtypeerr);
return;
}
for (j = ; j < c->argc; j++) {
if (!lobj) {
lobj = createQuicklistObject();
quicklistSetOptions(lobj->ptr, server.list_max_ziplist_size,
server.list_compress_depth);
dbAdd(c->db,c->argv[],lobj);
}
listTypePush(lobj,c->argv[j],where);
pushed++;
}
addReplyLongLong(c, (lobj ? listTypeLength(lobj) : ));
if (pushed) {
char *event = (where == LIST_HEAD) ? "lpush" : "rpush";
signalModifiedKey(c,c->db,c->argv[]);
notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[],c->db->id);
}
server.dirty += pushed;
}
LPOP/RPOP
LPOP:
移除并且返回 key 对应的 list 的第一个元素。
RPOP:
移除并返回存于 key 的 list 的最后一个元素。
两个命令都返回被移除的元素
时间复杂度O(1) 相对于i--的操作
127.0.0.1:> lpop mylist
"a"
127.0.0.1:> rpop mylist
"f"
127.0.0.1:> lrange mylist
) "b"
) "c"
) "d"
) "e"
127.0.0.1:>
源码解析
{"rpop",rpopCommand,,
"write fast @list",
,NULL,,,,,,},
{"lpop",lpopCommand,,
"write fast @list",
,NULL,,,,,,},
void lpopCommand(client *c) {
popGenericCommand(c,LIST_HEAD);
}
void rpopCommand(client *c) {
popGenericCommand(c,LIST_TAIL);
}
可见和push一样通过判断LIST_HEAD,来确定删除db中元素
void popGenericCommand(client *c, int where) {
robj *o = lookupKeyWriteOrReply(c,c->argv[],shared.null[c->resp]);
if (o == NULL || checkType(c,o,OBJ_LIST)) return;
robj *value = listTypePop(o,where);
if (value == NULL) {
addReplyNull(c);
} else {
char *event = (where == LIST_HEAD) ? "lpop" : "rpop";
addReplyBulk(c,value);
decrRefCount(value);
notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[],c->db->id);
if (listTypeLength(o) == ) {
notifyKeyspaceEvent(NOTIFY_GENERIC,"del",
c->argv[],c->db->id);
dbDelete(c->db,c->argv[]);
}
signalModifiedKey(c,c->db,c->argv[]);
server.dirty++;
}
}
LLEN
返回存储在 key 里的list的长度。 如果 key 不存在,那么就被看作是空list,并且返回长度为 0。 当存储在 key 里的值不是一个list的话,会返回error。
时间复杂度:O(1) 相当于常量操作
127.0.0.1:> llen mylist
(integer)
127.0.0.1:>
源码解析
{"llen",llenCommand,,
"read-only fast @list",
,NULL,,,,,,},
void llenCommand(client *c) {
robj *o = lookupKeyReadOrReply(c,c->argv[],shared.czero);
if (o == NULL || checkType(c,o,OBJ_LIST)) return;
addReplyLongLong(c,listTypeLength(o));
}
unsigned long listTypeLength(const robj *subject) {
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
return quicklistCount(subject->ptr);
} else {
serverPanic("Unknown list encoding");
}
}
unsigned long quicklistCount(const quicklist *ql) { return ql->count; }
Redis系列(六):数据结构List双向链表LPUSH、LPOP、RPUSH、RPOP、LLEN命令的更多相关文章
- Redis(六):list/lpush/lrange/lpop 命令源码解析
上一篇讲了hash数据类型的相关实现方法,没有茅塞顿开也至少知道redis如何搞事情的了吧. 本篇咱们继续来看redis中的数据类型的实现: list 相关操作实现. 同样,我们以使用者的角度,开始理 ...
- Redis系列六:redis相关功能
一. 慢查询原因分析 与mysql一样:当执行时间超过阀值,会将发生时间耗时的命令记录 redis命令生命周期:发送 排队 执行 返回慢查询只统计第3个执行步骤的时间 预设阀值:两种方式,默认为10毫 ...
- Redis系列二 - 数据结构
前言 redis作为我们开发的一大神器,我们接触肯定不会少,但是很多同学也许只会存储String类型的值,这是非常不合理的.在这里,将带大家认识Redis的5中数据结构. 1.问:Redis有那些数据 ...
- Redis系列(六):设置/移除键的过期时间
本篇博客是Redis系列的第6篇,主要讲解以下内容: 数据库数量 切换目标数据库 设置键的过期时间 移除键的过期时间 本系列的前5篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安 ...
- redis 系列8 数据结构之整数集合
一.概述 整数集合(intset)是集合键的底层实现之一, 当一个集合只包含整数值元素,并且这个集合元素数量不多时, Redis就会使用整数集合作为集合键的底层实现.下面创建一个只包含5个元素的集合键 ...
- Redis系列(六)-SortedSets设计技巧
阅读目录: 介绍 Score占位 更多位信息 总结 介绍 Redis Sorted Sets是类似Redis Sets数据结构,不允许重复项的String集合.不同的是Sorted Sets中的每个成 ...
- redis 系列7 数据结构之跳跃表
一.概述 跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.在大部分情况下,跳跃表的效率可以和平衡树(关系型数据库的索引就是平衡树 ...
- redis 系列6 数据结构之字典(下)
一.概述 接着上篇继续,这篇把数据结构之字典学习完, 这篇知识点包括:哈希算法,解决键冲突, rehash , 渐进式rehash,字典API. 1.1 哈希算法 当一个新的键值对 需要添加到字典里面 ...
- redis 系列5 数据结构之字典(上)
一. 概述 字典又称符号表(symbol table),关联数组(associative array), 映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构.在字典中, ...
随机推荐
- shell script的简单使用
shell script的简单介绍 shell变量 1.命名规则 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头 中间不能有空格,可以使用下划线(_) 不能使用标点符号. 不能使用bash ...
- Javascript中target事件属性,事件的目标节点的获取。
window.event.srcElement与window.event.target 都是指向触发事件的元素,它是什么就有什么样的属性 srcElement是事件初始化目标html元素对象引用,因为 ...
- (一)用less+gulp+requireJs 搭建项目(了解less)
项目完结 做个总结: 公司网站重构,整站都需要重写,终于有机会接触下 less,gulp和requireJs,因为以前的工作就是写几个活动页,并没有机会用这些工具,废话不多说,先看下完成后的项目目录: ...
- ASP.NET MVC 数据传递 视图向控制器传递
视图向控制器传递 MVC 视图向控制器传递,就是获取用户输入的数据,在去进行操作 好了,我们不多说直接进行我们的案例. 在HomeController类中添加下来方法 [HttpPost] publi ...
- Java实现 LeetCode 507 完美数
507. 完美数 对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为"完美数". 给定一个 整数 n, 如果他是完美数,返回 True,否则返回 False ...
- Java实现 蓝桥杯VIP 算法提高 邮票面值设计
算法提高 邮票面值设计 时间限制:1.0s 内存限制:256.0MB 问题描述 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤13)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮 ...
- java实现第四届蓝桥杯连续奇数和
连续奇数和 题目描述 小明看到一本书上写着:任何数字的立方都可以表示为连续奇数的和. 比如: 2^3 = 8 = 3 + 5 3^3 = 27 = 7 + 9 + 11 4^3 = 64 = 1 + ...
- (十一)DVWA全等级SQL Injection(Blind)盲注--手工测试过程解析
一.DVWA-SQL Injection(Blind)测试分析 SQL盲注 VS 普通SQL注入: 普通SQL注入 SQL盲注 1.执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,信息提 ...
- Cypress系列(16)- 查找页面元素的基本方法
如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 前端页面代码 后面写的 Cypress ...
- Python报错:SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
运行python文件的时候报错: SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2 ...