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)的抽象数据结构.在字典中, ...
随机推荐
- Java实现k个数乘(cheng)(自然数的k乘积问题)
k个数乘(cheng) 题目描述 桐桐想把一个自然数N分解成K个大于l的自然数相乘的形式,要求这K个数按从小到大排列,而且除了第K个数之外,前面(K-l)个数是N分解出来的最小自然数.例如:N=24, ...
- Java实现 蓝桥杯VIP 算法训练 友好数
有两个整数,如果每个整数的约数和(除了它本身以外)等于对方,我们就称这对数是友好的.例如: 9的约数和有:1+3=4 4的约数和有:1+2=3 所以9和4不是友好的. 220的约数和有:1 2 4 5 ...
- Java实现 LeetCode 374 猜数字大小 II
375. 猜数字大小 II 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字. 每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了. 然而,当你猜 ...
- Java实现 LeetCode 59 螺旋矩阵 II
59. 螺旋矩阵 II 给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵. 示例: 输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ...
- Python爬虫 requests库基础
requests库简介 requests是使用Apache2 licensed 许可证的HTTP库. 用python编写. 比urllib2模块更简洁. Request支持HTTP连接保持和连接池,支 ...
- Python中的三种等待时间
一.强制等待 不论页面是否加载完成,都要等待指定时间才能执行下一步, 单位秒,time.sleep(5) import time time.sleep(10) # 强制等待10秒时间 二.隐式等待( ...
- 查看Android系统中硬件信息的文件
文件目录: 使用Linux命令,进入到/proc目录 进入/proc目录,可以查看内存信息(memoinfo)或CPU信息(cpuinfo),使用cat命令
- LiveCharts 提示框(DataTooltip)百分比一直为0.00%解决办法
LiveCharts 提示框(DataTooltip)百分比一直为0.00%解决办法 问题描述:在使用LiveCharts 开源图标库的时候,使用CartesianChart类图表,当Series为L ...
- window.open打开新的独立页面
如下所示的代码: window.open('xxxxx.html', '_blank', 'height=100, width=400, top=0, left=0, toolbar=no, menu ...
- FFT,NTT入门
目录 -1.前置知识 复数 单位根 单位根反演 0.卷积 1.FFT -1.前置知识 复数 复数单位\(i\):定义为\(i^2=-1\).\(i\)可以直接参与运算. 复数:形如\(z=a+ ...