1、数据结构
-
zset是redis提供的一个非常特殊的数据结构,一方面它是一个set集合(没有重复元素),另一方面它是一个有序的,类似于C++的Map和Java的TreeMap。
-
内部的元素是以value : score的形式进行组织,每个value值对应一个score分数(double类型);然后根据score进行排序!value是的唯一,score是可以不唯一。
-
而zset的底层数据结构有两种:skiplist跳表、hash表,为了兼顾性能做优化。
-
skiplist跳表:首先跳表是一个有序的单向链表,其次跳表是一个多层级的链表,上面一层比下面一层少一半的节点,因此一个完整的跳表大约是有logn层。最后查询从最上层开始(链接的节点最少的),时间复杂度大约O(logn)。
-
skiplist跳表:跳表的诞生实则是为了快速实现一个各种单次操作能够达到logn级别的数据结构,能够与平衡树想媲美!而在编程语言的库中大部分并没有采用skiplist这种数据结构,只有在redis等一些非关系性数据库中有用到。
-
平衡树:目前我所了解到的平衡树AVL、Splay伸展树、Treap树堆、红黑树…但是这些平衡树似乎都有优缺点!
-
AVL平衡树:一个严格意义上的平衡树(高度差不超过1),查找性能稳定logn,但是如果整个操作伴随着大量的插入删除操作,调整平衡是非常浪费时间的,因此AVL在计算机中并没有大量使用普及。如果使用时只有少量的插入删除、大量的查找是可以使用AVL的,奈何变成难度太大!
-
Treap树堆:树堆可能不常见,但是在acm竞赛中确是一个常客,奈何它的优势Splay都具有,而且树堆的稳定性并不好,容易导致时间复杂度变成O(n)。
-
Splay伸展树:Splay相比上面两个平衡树好一点,虽然也有旋转调整,但是Splay的优势在于查找频率越高的节点越靠近根节点!均摊下来的时间复杂度O(logn),编程难度并不是很大(相对红黑树、AVL)。
-
红黑树:计算机的常客,map、set都是用红黑树实现的,相比AVL他的时间复杂度更稳定,对插入删除更加有好,编程难度太大。竞赛手写Splay的多,红黑的没见过!
-
综上:可以看到这些平衡树都有自己的优缺点,而跳表的出现就是为了弥补它们的不足,实现难度比平衡树小,而且性能也比较稳定。
2、常用命令
2.1、添加元素
这个操作只能插入值,并不能对其中某个score下的value值进行修改;如果重复操作redis会认为你在加入一条新数据,因为score可以重复!
语法:zadd key score1 value2 score2 value2 ...
zadd s 19 "zhangsan" 20 "lisi" 21 "wangwu" 22 "zhaoliu"
结果: 4
2.2、遍历集合
-
集合中元素的存储单元是从0开始的,如果stop = -1或者超过元素个数直接全部输出。
-
加上withscores,输出的结果会展示value所对应的score
语法:zrange key start stop
zrange s 0 1
结果: "zhangsan" "lisi"
zrange s 0 1 withscores
结果: "zhangsan" 19 "lisi" 20
2.3、查看集合元素个数
-
zcard命令是查看所有的元素个数
-
zcount是查看某个分数区间元素个数
语法:zcard key
zcount key min_score max_score
zcard s
结果:4
zcount s 10 21
结果: 3
2.4、查看某个元素的score
语法:zscore key value
zscore s "zhangsan"
结果:"19"
2.5、删除元素
-
可以同时删除一个或者多个元素,当删除不存在的元素时会被忽略
-
返回值是成功删除元素的个数
语法:zrem key value1 value2
zrem s "zhaoliu" "ttt"
结果:1
2.6、查看某个值的排名
-
由于上面说到存储是从0开始,排名查询也是从0开始
-
当查询不存在的时会出现"nil"
语法:zrank key value
zrank s "zhangsan"
结果: 0
zrank s "zhangsan1"
结果: nil
2.7、给某个值对应的score增加step分数
-
score分数在redis中是以一个double类型进行存储
-
返回值是操作完毕后的分数值
语法:zincrby key step value
zincrby s 5 "zhangsan"
结果: "24"
2.8、查询某个分数区间的元素值
- 区间是一个闭区间,并且返回值是一个按照score升序返回的。
语法:zrangebyscore key min_score max_score
zrangebyscore s 10 25
结果: "lisi" "wangwu" "zhangsan"
2.9、降序排列
默认情况下是升序排列,可以将某个分数区间的元素改为降序
语法:zrevrangebyscore key max_score min_score
zrevrangebyscore s 30 0
结果: "zhangsan" "wangwu" "lisi"