介绍:

ZSet数据结构类似于Set结构,只是ZSet结构中,每个元素都会有一个分值,然后所有元素按照分值的大小进行排列,相当于是一个进行了排序的链表。

如果ZSet是一个链表,而且内部元素是有序的,在进行元素插入和删除,以及查询的时候,就必须要遍历链表才行,时间复杂度就达到了O(n),这个在以单线程处理的Redis中是不能接受的。所以ZSet采用了一种跳跃表的实现。这个实现有点类似于Kafka存储消息是使用的稀疏索引,kafka这个相对较简单,可以用来介绍类比学习。

如果熟悉Kafka,就知道Kafka在进行持久化的时候,生成了两个文件,一个是xxxxxxx.log,一个是xxxxxxx.index,这其中log文件中以链表的形式保存着消息的详细信息,而index文件中,则是保存着这些消息的索引,或者说偏移量,但又不是每一条消息的索引都在index文件中存在,而是稀疏的,比如log文件中的消息的索引从0-10000,那么index文件中存储的索引可能是100, 500, 700, 1000, 5000, 6500,每一个索引中都保存着对应的log文件中的消息的具体位置,如图:

当要访问偏移量为899的这条消息时,先去index文件中查找,找到了700和1000这个区间,根据700这个索引中的信息,找到log文件中700这条消息的具体位置,然后顺序往下查找,直到找到索引为899的这条消息为止。从这个实现中我们可以看到,Kafka并没有进行log文件的整个遍历,而是通过index中的稀疏索引,找到消息在log中的大概位置,然后顺序遍历找到消息,这样就大大提高了查找的效率,如图:

Redis的跳跃表和上面类似,只是更加复杂一些,Kafka的稀疏索引只有一层,而Redis的索引被提取为多层。如图:

所有的元素都会在L0层的链表中,根据分数进行排序,同时会有一部分节点有机会被抽取到L1层中,作为一个稀疏索引,同样L1层中的索引也有一定机会被抽取到L2层中,组成一个更稀疏的索引列表。

下面用图来演示一下在对快速链表进行插入、删除、查询时,是如何定位到L0层中的具体位置的。

首先,假定有这么一个链表,注意这里只展示分数,而不展示具体的值了:

如果要查找分数为66的元素,首先在L2层的索引找。很明显,66位于25和85中间,这时就缩小了查找区间:

然后根据获得的区间,去L1对应的区间中查找,得到一个更精确的区间:

最终,根据这个更精确的区间,去L0层顺序遍历,即可得到要查找的元素:

上述即是对Redis的跳跃表的原理的一个简述。

这种跳跃表的实现,其实和二分查找的思路有点接近,只是一方面因为二分查找只能适用于数组,而无法适用于链表,所以为了让链表有二分查找类似的效率,就以空间换时间来达到目的。

跳跃表因为是一个根据分数权重进行排序的列表,可以再很多场景中进行应用,比如排行榜,搜索排序等等。

命令操作:

添加元素,zadd zsetName score1 value1 score2 value2 score3 value3 .....

查看所有元素,zrange zsetName 0 -1

查看所有元素,按score逆序排列, zrevrange zsetName 0 -1

元素数量,zcard zsetName

获取指定value的分数, zscore zsetName value

获取指定value的排名,zrank zsetName value(从0开始)

获取指定分值区间中的元素, zrangebyscore zsetName scoreStart scoreEnd(包含上下区间)(注意inf表示无穷大,-inf表示服务券大)

获取指定分值区间中的元素,并且返回分数, zrangebyscore zsetName scoreStart scoreEnd withscores

删除元素,zrem zsetName value

代码调用:

package mainimport ("fmt""github.com/garyburd/redigo/redis"
)func main(){// 连接redisconn,err := redis.Dial("tcp", "localhost:6379")if err != nil {fmt.Errorf("connection redis failed. error info: ", err)return}// zadd_,err = conn.Do("zadd", "phones", "100", "Nokia", "80", "tianyu", "60", "xiaomifeng", "50", "shangshai")if err != nil {fmt.Errorf("sadd failed, error info: ", err)return}// zrangeresult,err := redis.Strings(conn.Do("zrange", "phones", "0", "-1"))if err != nil {fmt.Errorf("zrange failed, error info: ", err)return}fmt.Println(result)// zrevrangeresult,err = redis.Strings(conn.Do("zrevrange", "phones", "0", "-1"))if err != nil {fmt.Errorf("zrange failed, error info: ", err)return}fmt.Println(result)// zcardsize,err := conn.Do("zcard", "phones")if err != nil {fmt.Errorf("zrange failed, error info: ", err)return}fmt.Println(size)// zscorescore,err := redis.Int(conn.Do("zscore", "phones", "shangshai"))if err != nil {fmt.Errorf("zrange failed, error info: ", err)return}fmt.Println(score)// zrem_,err = conn.Do("zrem", "phones", "shangshai")if err != nil {fmt.Errorf("zrange failed, error info: ", err)return}fmt.Println("delete shangshai success.")// 关闭连接defer conn.Close()
}  

执行效果:

转载于:https://www.cnblogs.com/wuyizuokan/p/11108417.html

【Redis】redis基本数据结构之ZSet相关推荐

  1. Redis初学:9(Zset类型)

    Zset(有序集合)类型 简介 Redis里面的有序集合Zset和集合Set非常相似,都是一个没有重复元素的字符串集合. 不同之处是有序集合Zset里面的每个成员都关联了一个评分(score),这个s ...

  2. Redis专题-底层数据结构与使用场景

    Redis介绍 Redis是一种基于键值对的NoSQL数据库,是一个基于内存中的数据结构存储系统,可以用作数据库.缓存和消息中间件.它支持以string(字符串),hash(哈希),list(列表), ...

  3. redis创建像mysql表结构_如何给redis添加新数据结构

    前言 作为一款缓存型nosql数据库,redis在诞生之初就以高性能.丰富的数据结构等特性获得业界的青睐.redis默认提供了五种数据类型的支持:string.list.set.zset.hash.针 ...

  4. Redis 之(二) Redis的基本数据结构以及一些常用的操作

    本篇内容是Redis最简单最容易掌握的知识,如果你已经熟知了,就可以选择跳过啦! 要体验Redis,那么首先你得安装Redis,这边的话我就只讲一下Windows环境下的安装与操作: Window 下 ...

  5. 【学习笔记】Redis的geohash数据结构介绍

    geohash介绍 ⾃Redis 3.2开始,Redis基于geohash和有序集合提供了地理位置相关功能.Redis Geo模块包含了以下6个命令: ▶GEOADD: 将给定的位置对象(纬度.经度. ...

  6. Redis五种数据结构

    对redis来说,所有的key(键)都是字符串,所谓的5种数据结构是指针对value而言 1.Redis五种数据结构如下: 数据结构类型 说明 使用场景 常用方法 其他链接 String字符串类型 1 ...

  7. 头条面试题:请谈谈Redis 9种数据结构以及它们的内部编码实现

    转载自  头条面试题:请谈谈Redis 9种数据结构以及它们的内部编码实现 90%的人知道Redis 5种最基本的数据结构: 只有不到10%的人知道8种基本数据结构,5种基本+bitmap+GeoHa ...

  8. 向内存中连续存入数据_内存节省到极致!Redis中这个数据结构,值得每个程序员了解...

    在之前我们介绍了,Redis有五种基础数据类型,分别是String,Set,List,Hash与SortSet. 今天我们又学习了一个命令,我们可以使用DEBUG OBJECT key查询Redis中 ...

  9. redis源码分析 ppt_【Redis】redis各类型数据结构和底层实现源码分析

    一.简介和应用 Redis是一个由ANSI C语言编写,性能优秀.支持网络.可持久化的K-K内存数据库,并提供多种语言的API.它常用的类型主要是 String.List.Hash.Set.ZSet ...

  10. redis专题:redis的常用数据结构及使用场景

    文章目录 一. redis常用五大数据结构 〇:key的底层存储方式:SDS ①:string && 使用场景 ②:hash && 使用场景 ③:list && ...

最新文章

  1. OpenCV 中的 convertTo 函数
  2. 【数理知识】辛矩阵 symplectic
  3. Oracle 定义变量的方法
  4. mysql 集群备份脚本_mysqldump结合脚本的备份方案
  5. STL库中string类内存布局的探究
  6. .net 微服务实践
  7. php 数组转json乱码,php将数组转为json涌现中文乱码怎么办_后端开发
  8. MySQL Return JSON Value Attributes
  9. C#调用Matlab生成的dll方法
  10. 你有什么难忘的出差经历?
  11. Mac 上制作 SSL 证书
  12. ASP读取文件 ASP写入/保存文件
  13. 黑马程序员软件测试面试宝典
  14. 基于 Django 的图书馆借阅系统
  15. 在线考试系统,在线考试后台管理
  16. 如何给网站设置自定义图标(标签页显示,收藏夹显示)
  17. 门级仿真经验(SDF反标及其工作原理)
  18. uboot 下mmc read/write命令使用和验证方法
  19. matlab将空间描述转变为约当阵,matlab求约当标准型
  20. leafnotification_Notification Service

热门文章

  1. matlab练习程序(TV模型图像修复)
  2. Python机器学习库scikit-learn实践
  3. 7-200 天梯赛的善良 (20 分)
  4. 基于顺序存储结构的图书信息表的旧图书的出库(C++)
  5. 基于顺序存储结构的图书信息表的最爱图书的查找(C++)
  6. 求链表的倒数第m个元素
  7. java继承原理内存角度_Java编程的逻辑 (17) - 继承实现的基本原理
  8. linux中cat监控,Linux基本命令——cat、rev、head、tail
  9. linux内存锁定什么意思,Linux内存子系统——Locking Pages(内存锁定)
  10. 单向链表的简单Java实现-sunziren