list底层是双向链表

特点:

1.有序:表示插入和取出是有顺序的,对列表本身的元素是不进行排序的;
2.可以重复
3.可以当作 栈,队列,数组,(阻塞队列)订阅和发布

1.单向链表

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表


解释: 单向链表只有一个next指针指向后面的结点, 只能单向遍历, 相对于双向链表来说占用的内存小

2.双向链表的基本结构

有一个head结点和tail结点,方便再插入和删除的时候快速定位开始和结束结点的位置,然后通过pre和next指针寻找目标结点,然后进行插入和删除;还有一个size属性,用来记录链表中的元素个数;

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_02

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_03


解释: next指针指向后一个结点, pre指针指向前一个结点; 对比于单向链表占用内存小;支持双向遍历,mysql的innodb搜索引擎的索引是b+tree; tree的叶子节点就是双向链表

3.双向链表的基本操作

头部插入( LPUSH key element [element …] )

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表_04

尾部插入(RPUSH key element [element …])

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_05

中间位置插入

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_06

删除头部( LPOP key [count])

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表_07

删除尾部(RPOP key [count])

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_08

中间位置删除

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_list_09


扩展:

1.数组简单易用,在实现上使用的是连续的内存空间,可以借助CPU的缓存机制,预读数组中的数据,所以访问效率更高。

2.链表在内存中并不是连续存储,所以对CPU缓存不友好,没办法有效预读。

3.数组的缺点是大小固定,一经声明就要占用整块连续内存空间。如果声明的数组过大,系统可能没有足够的连续内存空间分配给它, 导致“内存不足(out ofmemory)”。如果声明的数组过小,则可能出现不够用的情况。注意下标越界的问题。

4.动态扩容:数组需再申请一个更大的内存空间,把原数组拷贝进去,非常费时。链表本身没有大小的限制,天然地支持动态扩容,使用的时候也需要考虑占用内存的问题。

redis中的list的相关操作命令

左方向操作命令

LPUSH key element [element …]

解释: 将一个或多个值 value 插入到列表 key 的表头

LPOP key [count]

解释: 从头部开始, 移除并取出前几个值

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_list_10

LPUSHX key element [element …]

解释:当且仅当 key 存在并且是一个列表时将值 value 插入到列表 key 的头部,与lpush不同,LPUSH是如果key不存在就创建一个key和列表,再把值插入到列表的头部

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_11

右方向操作命令

RPUSH key element [element …]

解释: 将一个或多个值 value 插入到列表 key 的尾部

RPOP key [count]

解释: 尾部开始, 移除并取出前几个值

RPUSHX key element [element …]

解释:当且仅当 key 存在并且是一个列表时将值 value 插入到列表 key 的尾部,与RPUSH不同,RPUSH是如果key不存在就创建一个key和列表,再把值插入到列表的尾部

list的其他一些操作命令

这些操作命令的首字母L不是表示左边,而是表示list

LINDEX key index

解释: 返回列表 key 中,下标为 index 的元素,并没有删除该元素。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_12

LINSERT key BEFORE|AFTER pivot element

解释: 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。当key 或者 pivot或者列表不存在时不进行任何操作

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_13

LLEN key

解释:获取链表的长度,也就是数据结构底层的size

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_14

LMOVE source destination LEFT|RIGHT LEFT|RIGHT

解释:元素的移动, source: 要移动的列表; destination :目标列表, 第一个LEFT|RIGHT:从source列表弹出元素的方向,第二个LEFT|RIGHT:向destination 列表插入元素的方向

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_客户端_15

LPOS key element [RANK rank] [COUNT num-matches] [MAXLEN len]

解释:

1 返回列表 key 中匹配给定 element 成员的索引。 默认的,当没有其它参数选项时,LPOS 从列表头部开始扫描,直到列表尾部,查找第一个与匹配"element"的成员。如果找到匹配的成员,返回这个成员的索引(从零开计数),如果找不到匹配的成员返回 NULL。

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_客户端_16


2 RANK 选项表示返回第几个匹配的元素,即如果有列表中有多个元素匹配,那么 rank 为 1 时返回第一个匹配的元素, rank 为 2 时返回第二个匹配的元素,以此类推。例如,在上面的例子中,成员 “c” 出现了多次,如果想返回第二个匹配的 “c” 的索引,可以也这样写:

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_17


第二个 “c” 的位置索引是 6。3负值 RANK 参数表示换一个搜索方向,从列表尾部想列表头部搜索。所以,查找列中中尾部开始第3个匹配的元素命令:

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_18


需要注意的是返回的索引还是从列表头开始,从零开始计数。无论 RANK 值正负,索引的值是固定的。4 有时我们不是想返回第 N 个匹配的成员,而是想返回前 N 个匹配的成员; 所以查找前2个匹配的元素命令:

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_list_19


COUNT 为 0 时表示返回所有匹配成员的索引数组

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_20

LRANGE key start stop

解释:

返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。

下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_21

LREM key count element

解释:

count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。

count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。

count = 0 : 移除表中所有与 value 相等的值。

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表_22

LSET key index element

将列表 key 下标为 index 的元素的值设置为 value 。当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_23

LTRIM key start stop

对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。包含start和stop

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_24

RPOPLPUSH source destination

命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
1.将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
2.将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。

举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c , destination 列表有元素 x, y, z ,执行 RPOPLPUSH source destination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。

如果 source 不存在,值 nil 被返回,并且不执行其他动作。

如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_25


redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_26


第一次把c放到头部,第二次把b放到头部

阻塞命令

BLMOVE source destination LEFT|RIGHT LEFT|RIGHT timeout

解释:

1.BLMOVE 是 LMOVE 的阻塞版本。
2.当 source 列表非空时,BLMOVE 的执行效果跟 LMOVE 一样。 当用在事务块 MULTI/EXEC 内, BLMOVE 的执行效果跟 LMOVE 一样。
3. 当 列表为空时,Redis 会阻塞客户端连接,直到另一个客户端向 source 列表插入新值或timeout 超时时间到达。 timeout 等于 0 时表示永不超时。

开启两个连接,一个连接执行BLMOVE ,一个连接向source列表添加元素

第一步:左边客户端执行LMOVE命令,可以看到该客户端一直处于阻塞状态;

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表_27


第二步:我们在右边的客户端向source列表添加元素

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_28


当左边的客户端发现source列表不为空了,就执行了该命令

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表_29

BLPOP key [key …] timeout

解释:
timeout 等于 0 时表示永不超时。
Redis BLPOP 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。它是 LPOP 的阻塞版本。
当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。

开启两个客户端,左边客户端执行BLPOP ,右边客户端向source列表添加元素

第一步:左边客户端执行BLPOP命令,可以看到该客户端一直处于阻塞状态;

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_客户端_30


第二步: 我们在右边的客户端向source列表添加元素

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_客户端_31


第三步:当左边的客户端发现source列表不为空了,就执行了该命令

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_链表_32

BRPOP key [key …] timeout

BRPOP 是阻塞列表的移除原语。从给的列表参数中按顺序检查第一个不空的列表,然后从该列表的尾部移除元素。 BRPOP 是 RPOP 的阻塞版本,因为当没有元素从给定的列表中移除的时候,BRPOP 阻塞连接。此处不做演示参照BLPOP命令

支持数据结构

栈(先进后出)同向命令

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_客户端_33

队列(先进先出)反向命令

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_数组_34

数组

redis 的 isMember 方法值只能是字符串吗 redis的value可以为空吗_redis_35