数据结构:

zset是有序的,不运行重复的,带有分值score的

数据结构对比:

操作命令:

zadd myzset 10 java 20 python 20 ruby 40 mysql 50 php (添加)

zrange myzset 0 -1 withscores (通过score进行排序从小到大)

zrevrange myzset 0 -1 withscores (通过score进行排序从大到小)

zrangebyscore myzset 20 30 (通过score取出20-30的产品)

zrem myzset java python (将java和python移除)

zscard myzset (统计总数)

zincrby myzset 5 java (将java加5分)

zcount myzset 20 50 (统计20-50之间有多少个)

zrank myzset java (java在set中处于第几个位置,从0开始)

zscore myzset java (java有多少分)

存储实现原理:

在redis.conf文件中有两行这么写的

zset-max-ziplist-entries 128  # zset中压缩列表ziplist最大的元素是128个,超过128将会使用跳表skiplist+dict来存储

zset-max-ziplist-value 64 # zset中压缩列表ziplist中每个元素最大的个数是64个,超过64将会使用跳表skiplist+dict来存储

什么是跳表skiplist dict呢?我们先来看下面一张图:

这是一个有序的链表,当我们要将20这个数字插入到链表中的时候,他是从开始到结尾一个一个进行比对直到找到21之后才停止,这样他的效率就很低,时间复杂度是O(n),查找也是一样的道理。

怎么优化呢,skiplist是怎么实现的呢?再来看下面一张图:

假如我们每相邻两个节点增加一个指针(或者理解为有三个元素进入了第二层),让指针指向下下个节点。

这样所有新增加的指针连成了一个新的链表,但它包含的节点个数只有原来的一半(上图中是 7, 19, 26)。在插入一个数据的时候,
决定要放到那一层,取决于一个算法(在 redis 中 t_zset.c 有一个 zslRandomLevel 这个方法)。现在当我们想查找数据的时候,可以先沿着这个新链表进行查找。当碰到比待查数
据大的节点时,再回到原来的链表中的下一层进行查找。比如,我们想查找 23,查找的路径是沿着下图中标红的指针所指向的方向进行的:

1. 23 首先和 7 比较,再和 19 比较,比它们都大,继续向后比较。
2. 但 23 和 26 比较的时候,比 26 要小,因此回到下面的链表(原链表),与 22比较。
3. 23 比 22 要大,沿下面的指针继续向后和 26 比较。23 比 26 小,说明待查数据 23 在原链表中不存在,在这个查找过程中,由于新增加的指针,我们不再需要与链表中每个节点逐个进行比较了。需要比较的节点数大概只有原来的一半。这就是跳跃表。

可以看到他将某些元素中加了指针,这有点类似于数组中的二分法查找,但是链表中没有数组,所以用指针的方式来实现,看下面源码

源码位置:server.h
typedef struct zskiplistNode {
sds ele; /* zset 的元素 */
double score; /* 分值 */
struct zskiplistNode *backward; /* 后退指针 */
struct zskiplistLevel {
struct zskiplistNode *forward; /* 前进指针,对应 level 的下一个节点 */
unsigned long span; /* 从当前节点到下一个节点的跨度(跨越的节点数) */
}level[]; /* 层 */
}zskiplistNode; typedef struct zskiplist {
struct zskiplistNode *header, *tail; /* 指向跳跃表的头结点和尾节点 */
unsigned long length; /* 跳跃表的节点数 */ int level; /* 最大的层数 */
} zskiplist; typedef struct zset {
dict *dict;
zskiplist *zsl;
} zset;

随机获取层数的函数,源码位置t_zset.c

int zslRandomLevel(void) {
int level = 1;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

应用场景:

排行榜

id 为 6001 的新闻点击数加 1:zincrby hotNews:20190926 1 n6001
获取今天点击最多的 15 条:zrevrange hotNews:20190926 0 15 withscores

redis数据类型--zset的更多相关文章

  1. 初识redis数据类型

    初识redis数据类型 1.String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据 ...

  2. Redis数据类型介绍

    Redis 数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). String(字符串) st ...

  3. redis数据类型

    Redis 数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). String(字符串) st ...

  4. redis笔记总结之redis数据类型及常用命令

    三.常用命令 3.1 字符串类型(string) 字符串类型是Redis中最基本的数据类型,一个字符串类型的键允许存储的数据的最大容量为512MB. 3.1.1 赋值与取值: SET key valu ...

  5. redis底层设计(三)——redis数据类型

    今天我们来看一下redis的数据类型.既然redis的键值对可以保存不同类型的值,那么很自然就需要对键值对的类型进行检查以及多态处理.下面我们将对redis所使用的对象系统进行了解,并分别观察字符串. ...

  6. Redis笔记(二):Redis数据类型

    Redis 数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). String(字符串) st ...

  7. Redis 基础:Redis 数据类型

    Redis 数据类型 Redis支持五种数据类型:string(字符串).hash(哈希).list(列表).set(集合)及zset(sorted set:有序集合). String(字符串) st ...

  8. Redis数据类型及常用命名总结

    Redis数据类型: Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合).  1.String(字符串) ...

  9. Redis(三):Redis数据类型

    Redis数据类型目录导航: Redis五大数据类型 哪里去获取Redis常见数据类型操作命令 Redis键(Key) Redis字符串(String) Redis列表(List) Redis集合(S ...

随机推荐

  1. vue.config.js常用配置

    使用vue-cli3.0搭建项目比之前更简洁,没有了build和config文件夹. vue-cli3的一些服务配置都迁移到CLI Service里面了,对于一些基础配置和一些扩展配置需要在根目录新建 ...

  2. C#同级catch块和finally块中全都抛出异常,上一级捕获哪一个?

    C#同级catch块和finally块中全都抛出异常,上一级优先捕获finally块中的异常. 测试代码: using System; namespace test { class Program { ...

  3. pxe批量部署

    功能: 批量全自动安装操作系统方法: dhcp 自动分配IP tftp 微系统 用来安装系统 httpd 网络源 操作流程: #检查环境 getenforce #检查selinux systemctl ...

  4. SpringBoot系列之@Conditional注解用法简介

    SpringBoot系列之@Conditional注解用法简介 引用Spring官方文档的说法介绍一下@Conditional注解:Spring5.0.15版本@Conditional注解官方文档 @ ...

  5. Maven和Gradle中配置单元测试框架Spock

    Maven Maven本身不支持其他JVM语言(例如Groovy或Scala).要在Maven项目中使用它,需要使用第三方插件.对于Groovy而言,最好的选择似乎是GMavenPlus(重写不再维护 ...

  6. flume安装和介绍

    一.安装1.flume-ng-1.5.0-cdh5.3.6.tar.gz 下载链接:https://pan.baidu.com/s/1AWPGP2qnY6_VpYr_iSnJ3w 密码:tiog2.对 ...

  7. 忘记Linux登录密码的破解方法

    注意:1.破解方式只限于7.0以后的Linux系统. 2.要注意自己linux系统中有没有开启selinux,如果开启则在后面要建一个名为:autorelabel的隐藏文件.     1.启动Linu ...

  8. nyoj 36-最长公共子序列 (动态规划,DP, LCS)

    36-最长公共子序列 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:18 submit:38 题目描述: 咱们就不拐弯抹角了,如题,需要你做的就是写 ...

  9. windows:查看电脑开放的端口

    netstat -ano netstat -ano | findstr '445' 查看445端口是否被使用 根据端口找到占用程序的PID,再用tasklist|findstr "2720& ...

  10. python_day03

    今日所学内容 1.函数部分: #函数的三种定义方式#1.无参函数:不需要外部传入的参数#2.有参函数:需要接受外部传入的参数#3.空函数:def func(): pass#pass代表说明都不用做# ...