1、数据结构
-
通过上面的一些操作可以看到redis中的List这种数据结构还是很特殊的,某些操作有链表的特性能够做到快速删除,某些属性又向是有数组的属性能够快速获取!
-
这是一种特殊的数据结构双端队列deque,它是数组 + 链表的结合体。以前做竞赛的时候玩单调队列就是用的这个玩意。所以我做完操作的时候基本上能猜到是它。
-
如果只是双向链表,两个指针域空间浪费肯定非常大的。而且两个指针域只用来存一个数据非常不划算!
-
那么怎么改造呢?那就是将数据域扩大,指针域依然保留,只需要将数据域扩大到一定容量,比如之前只能存一个数据,现在我可以存100个。那么数据域空间 / 整体空间的利用率就提高了!这就是deque的核心。
-
有兴趣可以看C++的STL模板库,里面介绍了deque的实现。
#include <deque>
2、基本使用
2.1、头插法建立List链表
头插法:每次都将新增元素从头部插入,越先插入的元素越靠后。
单次时间复杂度:O(1)
整体时间复杂度:O(n)
语法:lpush key value1 value2...
lpush k1 v1 v2 v3 v4
结果:"v4" "v3" "v2" "v1"
2.2、尾插法建立List链表
尾插法0:每次都将新增元素从尾部插入,越先插入的元素越靠前。
单次时间复杂度:O(1)
整体时间复杂度:O(n)
语法:rpush key value1 value2...
rpush k2 v1 v2 v3 v4
结果:"v1" "v2" "v3" "v4"
2.3、遍历List链表
遍历是从左往右进行遍历
整体时间复杂度:O(stop-start)
注意:start是起始下标位置,stop是结束位置。最终查询的区间是[start,stop]。stop = -1说明全部遍历。
语法:lrange key start stop
lrange k1 0 -1
1) "v4"
2) "v3"
3) "v2"
4) "v1"
2.4、从头部删除几个值
单次时间复杂度:O(1)
整体时间复杂度:O(count)。
语法:lpop key count
lpop k1 1
1) "v4"
2.5、从尾部删除几个值
单次时间复杂度:O(1)
整体时间复杂度:O(count)。
语法:rpop k2 2
rpop k2 2
1) "v4"
2) "v3"
2.6、删除插入联合操作
redis还支持同时操作两个key键,可以将一个key从删除一个值并且插入到另外一个key中。
整体时间复杂度:O(1)
rpoplpush:从key2中右边删除一个元素,然后将这个值头插法插入到key2中。
语法: rpoplpush start end
k1: "v3" "v2" "v1"
k2: "v1" "v2"
rpoplpush k2 k1
k1: "v2" "v3" "v2" "v1"
k2: "v1"
2.7、获取指定下标的值
整体时间复杂度:O(1)
语法:lindex key idx
k1: "v2" "v3" "v2" "v1"
lindex key 1
结果: "v3"
2.8、删除n个指定元素
从头部开始遍历查找,删掉n个值为value的元素。
整体时间复杂度:O(n)
语法:lrem k1 n value
k1: "v2" "v3" "v2" "v1"
lrem k1 2 "v2"
结果:"v3" "v1"
2.9、指定位置插入值
可以在list列表中找到一个value值,在这个值的前面/后面插入newvalue新值。
整体时间复杂度:O(n),因为查找是需要便利的,插入是O(1).
语法: linsert key before/after value newvalue
k1: "v1" "v2" "v3" "v4"
linsert k1 before "v3" 999
结果:k1: "v1" "v2" "999" "v3" "v4"
linsert k1 after "999" "888"
结果:k1: "v1" "v2" "999" "888" "v3" "v4"
2.10、更改指定下标位置的值
整体时间复杂度:O(1)
注:redis中的list集合数据结构比较特殊,准确的说应该算list + array = deque。
语法: lset key index value
k1: "v1" "v2" "999" "888" "v3" "v4"
lrange k1 0 -1
结果:k1: "v1" "v2" "777" "888" "v3" "v4"
2.11、获取列表长度
这个应该是最简单的,时间复杂度O(1)
语法:llen key
k1: "v1" "v2" "777" "888" "v3" "v4"
llen key
结果:6