Redis核心数据结构之整数集合

整数集合

概述

整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个结合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现。

例子

举个例子,如果创建一个只包含五个元素的集合键,并且集合中的元素都是整数值,那么这个集合键的底层实现就会是整数集合

127.0.0.1:6379> SADD numbers 1 3 5 7 9
(integer) 5
127.0.0.1:6379> OBJECT ENCODING numbers
"intset"
127.0.0.1:6379>

整数集合的实现

整数集合(intset)是Redis用于保存整数值的集合抽象数据结构,它可以保存类型为int16_t、int32_t或者int64_t的整数值,并且保证集合中不会出现重复元素。每个intset.h/intset结构表示一个整数集合:
contents数组是整数集合的底层实现:整数集合的每个元素都是contents数组的一个数组项(item),各个项在数组中按值得大小从小到大有序地排列,并且数组中不包含任何重复项
length属性记录了整数集合包含地元素数量,也即是contents数组地长度.虽然intset结构将contents属性声明为int8_t类型地数组,但实际上contents数组并不保存任何int8_t类型的值,contents数组的真正类型取决于encoding属性的值:

  • 1.如果encoding属性的值为INTSET_ENC_INT16,那么contents就是一个int16_t类型的数组,数组里的每个项都是一个int16_t类型的整数值(最小值为-32768,最大值为32767,正负2的16-1次方)
  • 2.如果encoding属性的值为INTSET_ENC_INT32,那么contents就是一个int32_t类型的数组,数组里的每个项都是一个int32_t类型的整数值(最大值、最小值为正负2的32-1次方)
  • 3.如果encoding属性为INTSET_ENC_INT64,那么contents就是一个int64_t类型的数组,数组里的每个项都是一个int64_t类型的整数值(最大值最小值为,2的64-1次方-1,2的64-1次方)

例子

  • 举个例子,
    1.encoding属性的值为INTSET_ENC_INT16,表示整数集合的底层实现为int16_t类型的数组,
    而集合保存的都是int16_t类型的整数值
    2.length属性的值为5,表示整数集合包含五个元素
    3.contents数组按从小到大的顺序保存着集合中的五个元素
    4.因为每个集合元素都是int16_t类型的整数值,所以contents数组的大小等于sizeof(int16_t) * 5 = 16 * 5 = 80位
    在这里插入图片描述
  • 另一个整数集合示例:
    1.encoding属性的值位INTSET_ENC_INT64,表示整数集合的底层实现为int64_t类型的数组,而数组中保存的都是int64_t类型的整数值
    2.length属性的值为4,表示整数集合包含四个元素
    3.contents数组按从小到大的顺序保存着集合中的四个元素
    4.因为每个集合元素都是int64_t类型的整数值,所以contents数组的大小为
    sizeof(int64_t) * 4 = 64 * 4 = 256位

虽然contents数组保存的四个整数值中,只有-2675256175807981027是真正需要用int64_t类型来保存的,而其他的1、3、5三个值都可以用int16_t类型来保存,不过根据整数集合的升级规则,当向一个底层位int16_t数组的整数集合添加一个int64_t类型的整数值时,整数集合已有
的所有元素都会被转换成int64_t类型,所以contents数组保存的四个整数值都是int64_t类型的,不仅仅是-2675256175807981027
在这里插入图片描述

升级

每当我们要将一个新元素添加到整数集合里面,并且新元素的类型比整数集合现有所有元素的类型都要长时,整数集合需要先进行升级(upgrade),然后才能将新元素添加到整数集合里面。升级整数集合并添加新元素共分为三步进行:

  • 1.根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间
  • 2.将底层数组现有的所有元素都转换成与新元素相同的类型,并将类型转换后的元素防止到正确的位上,而且在放置元素的过程中,需要继续维持底层数组的有序性质不变
  • 3.将新元素添加到底层数组里面
例子

举个例子。假设现在有一个INTSET_ENC_INT16编码的整数集合,集合中包含三个int16_t类型的元素。如图所示。因为每个元素都占用16位空间,所以整数集合底层数组的大小为16*3=48位,
在这里插入图片描述
在这里插入图片描述
现在,假设要将类型为int32_t的整数值65535添加到整数集合里面,因为65535的类型int32_t比整数集合当前所有的元素的类型都要长,所以在将65535添加到整数集合之前,程序需要先对整数集合
进行升级。升级首先要做的是,根据新类型的长度,以及集合元素的数量(包括要添加的新元素在内),对底层数组进行空间重分配。
整数集合目前有三个元素,再加上新元素65535,整数集合需要分配四个元素的空间,因为每个int32_t整数值需要占用32位空间,所以在空间重分配之后,底层数组的大小将是32 * 4 = 128位,

  • 虽然程序对底层数组进行了空间重分配,但数组原有的三个元素1、2、3仍然是int16_t类型,这些元素还保存在数组的前48位里面,所以程序接下来要做的就是将这三个元素转换为int32_t类型,并将转换后的元素放置到正确的位上面,而且在防止元素的过程中,需要维持底层数组的有序性质不变
    在这里插入图片描述
  • 首先,因为3在1、2、3、65535四个元素中排名第三,所以它将被转移到contents数组的索引2位置上,也即是数组64位至96位的空间内,如图
    在这里插入图片描述
  • 接着,因为2在1、2、3、65535四个元素中排名第二,所以它将被移动到contents数组中索引1位置上,也即是32位至63位的空间内,如图
    在这里插入图片描述
  • 之后,因为元素1在1、2、3、65535四个元素中排名第一,所以它将被移动到contents数组的索引0位置上,即数组的0位至31位的空间内,如图
    在这里插入图片描述
  • 然后,因为元素65535在1、2、3、65535四个元素中排名第四,所以它将被移动到contents数组的索引3位置上,也即是数组的96位至127位的空间内在这里插入图片描述
  • 最后,程序将整数集合encoding属性的值从INTSET_ENC_INT16改为INTSET_ENC_INT32,并将length属性的值从3改为4,设置完成之后的整数集合如图。因为每次向整数集合添加元素都可能会引起升级,而每次神各级都需要对底层数组中已有的所有元素进行类型转换,所以向整数集合添加新元素的时间复杂度为O(N)。其他类型的升级操作,比如INTSET_ENC_INT16编码升级为INTSET_ENC_INT64编码,
    或者从INTSET_ENC_INT32编码升级为INTSET_ENC_64编码在这里插入图片描述
升级之后新元素的摆放位置

因为引发升级的新元素的长度总是比整数集合现有所有元素的长度都大,所以这个新元素的值要么就大于所有现有元素,要么就小于所有现有元素。

  • 1.在新元素小于所有现有元素的情况下,新元素会被放置在底层 数组的最开头(索引0)
  • 2.在新元素大于所有现有元素的情况下,新元素会被放置在底层数组的最末尾(索引length-1)
升级的好处
提升整数集合的灵活性

因为C语言是静态类型语言,为了避免类型错误,通常不会讲两种不同类型的值放在同一个数据结构里面。例如,一般只使用int16_t类型的数组来保存int16_t类型的值,只使用int32_t类型的数组来保存int32_t类型的值。
但是,因为整数集合可以通过自动升级底层数组来适应新元素,所以可以随意地将int16_t、int32_t或者int64_t类型的整数添加到集合中,而不必担心出现类型错误

尽可能地节约内存

要让一个数组可以同时保存int16_t、int32_t、int64_t三种类型的值,最简单的做法就是直接使用int64_t类型的数组作为整数集合的底层实现。不过这样一来,即使添加到整数集合里面的都是int16_t或者int32_t类型的值,数组都需要使用int64_t类型的空间去保存它们,从而出现浪费内存的情况。而整数集合现在的做法既可以让集合能同时保存三种不同类型的值,又可以确保升级操作只会在有需要的时候进行,这可以尽量节省内存

例如,如果我们一直只向整数集合添加int16_t类型的值,那么整数集合的底层实现就会一直是int16_t类型的数组,只有在我们要将int32_t类型或者int64_t类型的值添加到集合时,程序才会对数组进行升级

降级

整数集合不支持降级操作,一旦对数组进行了升级,编码就会一直保持升级后的状态
举个例子,即使将集合里唯一一个真正需要使用int64_t类型来保存的元素
4294967295删除了,整数集合的编码仍然会维持INTSET_ENC_INT64
底层数组也仍然会是int64_t类型
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/735831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 8.0 架构 之 慢查询日志(Slow query log)(2)流程图:查询记录到慢查询日志中的条件

文章目录 MySQL 8.0 架构 之 慢查询日志(Slow query log)(2)流程图:查询记录到慢查询日志中的条件确定查询是否会记录在慢查询日志中的流程图参考 【声明】文章仅供学习交流,观点代表个人,与任何…

JavaScript数组方法常用方法大全

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1. push()2. pop()3. unshift()4. shift()5. isArray()6. map()7. filter()8. every()9. some()10. splice()11. slice()12. indexOf()13. includes()14. concat()1…

【大厂AI课学习笔记NO.76】人工智能人才金字塔

人工智能领域,分为源头创新人才、产业研发人才、应用开发人才和实用技能人才。 人工智能领域的人才结构呈现多样化特点,主要可以分为源头创新人才、产业研发人才、应用开发人才和实用技能人才四大类。这四大类人才在人工智能领域的发展中各自扮演着不可或…

Python刘诗诗

写在前面 刘诗诗在电视剧《一念关山》中饰演了女主角任如意,这是一个极具魅力的女性角色,她既是一位有着高超武艺和智慧的女侠士,也曾经是安国朱衣卫前左使,身怀绝技且性格坚韧不屈。剧中,任如意因不满于朱衣卫的暴行…

P1948 [USACO08JAN] Telephone Lines S

Here 典中之典!! 解题思路 可选k条边代价为0如何决策? 将到当前位置选择了几条代价为0的边放入状态,即若当前状态选的边数小于,则可以进行决策,是否选择当前边,若选,则&#xff0c…

基于智慧灯杆的智慧城市解决方案(2)

功能规划 智慧照明功能 智慧路灯的基本功能仍然是道路照明, 因此对照明功能的智慧化提升是最基本的一项要求。 对道路照明管理进行智慧化提升, 实施智慧照明, 必然将成为智慧城市中道路照明发展的主要方向之一。 智慧照明是集计算机网络技术、 通信技术、 控制技术、 数据…

uniapp:小程序数字键盘功能样式实现

代码如下&#xff1a; <template><view><view><view class"money-input"><view class"input-container" click"toggleBox"><view class"input-wrapper"><view class"input-iconone"…

C++ 队列

目录 队列的应用场景 1、429. N 叉树的层序遍历 2、 103. 二叉树的锯齿形层序遍历 3、662. 二叉树最大宽度 4、515. 在每个树行中找最大值 队列的应用场景 广度优先搜索&#xff08;BFS&#xff09;&#xff1a;队列是广度优先搜索算法的核心数据结构。在BFS中&#xff…

C语言:深入补码计算原理

C语言&#xff1a;深入补码计算原理 有符号整数存储原码、反码、补码转换规则数据与内存的关系 补码原理 有符号整数存储 原码、反码、补码 有符号整数的2进制表示方法有三种&#xff0c;即原码、反码和补码 三种表示方法均有符号位和数值位两部分&#xff0c;符号位用0表示“…

Linux:kubernetes(k8s)lable和selecto标签和选择器的使用(11)

通过标签是可以让我们的容器和容器之间相互认识&#xff0c;简单来说一边打了标签&#xff0c;一边使用选择器去选择就可以快速的让他们之间耦合 定义标签有两种办法&#xff0c;一个是文件中&#xff0c;一个是命令行里 我们在前几章编进文件的时候里面都有lable比如 这个就是…

rk3399使用阿里推理引擎MNN使用cpu和gpu进行benchmark,OpenCL效果不佳?

视频讲解 rk3399使用阿里推理引擎MNN使用cpu和gpu进行benchmark&#xff0c;OpenCL效果不佳&#xff1f; 背景 MNN是阿里开源的推理引擎&#xff0c;今天测试一下在rk3399平台上的benchmark怎么样&#xff1f; alibaba/MNN: MNN is a blazing fast, lightweight deep learning…

keycloak18.0.0==前后端分离项目中使用,前端react后端springboot

配置keycloak 启动keycloak18 新建一个realm,名字叫test1 新建两个client&#xff0c;一个用于前端&#xff0c;一个用于后端 第一个 react http://localhost:8081/auth/realms/test1/react/ 第二个 backend-service 在两个client下分别创建role testRole backend-servic…

可免费使用的AI平台汇总 + 常用赋能科研的AI工具推荐

赋能科研&#xff0c;AI工具助你飞跃学术巅峰&#xff01;(推荐收藏) 文章目录 赋能科研&#xff0c;AI工具助你飞跃学术巅峰&#xff01;(推荐收藏)一、可免费使用的AI平台汇总1. ChatGPT2. New Bing3. Slack4. POE5. Vercel6. 其他平台7. 特定功能平台8. 学术资源平台9. 中文…

编曲学习:钢琴编写 人性化、逻辑预制 工程音频导出

第8课 钢琴编写 人性化、逻辑预制 工程音频导出小鹅通-专注内容付费的技术服务商https://app8epdhy0u9502.pc.xiaoe-tech.com/live_pc/l_65e30339e4b064a8cfe56001?course_id=course_2XLKtQnQx9GrQHac7OPmHD9tqbv 音乐创作中,有思路时可以不套学习到的公式,没有思路时可以套…

离线数仓(六)【ODS 层开发】

前言 1、ODS 层开发 ODS层的设计要点如下&#xff1a; &#xff08;1&#xff09;ODS层的表结构设计依托于从业务系统同步过来的数据结构&#xff08;JSON/CSV/TSV&#xff09;。 &#xff08;2&#xff09;ODS层要保存全部历史数据&#xff0c;故其压缩格式应选择高压缩比的…

C++程序设计-第六/七/八章 运算符重载/包含与继承/虚函数和多态性【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下C程序设计中的重点概念&#xff0c;以供大家期末复习和考研复习的时候使用。 C程序设计系列文章传送门&#xff1a; 第一章 面向对象基础 第四/五章 函数和类和对象 第六/七/八章 运算符重载/包含与继承/虚函…

Java多线程实战-实现多线程文件下载,支持断点续传、日志记录等功能

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 前言 1 基础知识回顾 1.1 线程的创建和启动 1.2 线程池的使用 2.运行环境说…

Shell常用脚本:文件或目录一键同步到多台服务器

注意&#xff1a; 将本地文件&#xff0c;同步到【/opt/module/script/xsyncByFileIp.txt】里面的目标机器 xsyncByFile.sh #!/bin/bash# 入参参数个数 argsCount$#if(($argsCount0)); thenecho "同步失败&#xff1a;请输入待同步的文件或者目录" exit; fiecho &q…

BetterDisplay for mac V2.2.5 强大的mac显示器管理开源工具

BetterDisplay是Mac OS 一个很棒的工具&#xff01; 它允许您将显示器转换为完全可扩展的屏幕 管理显示器配置覆盖 允许亮度和颜色控制 提供 XDR/HDR 亮度升级&#xff08;Apple Silicon 和 Intel Mac 上兼容的 XDR 或 HDR 显示器的额外亮度超过 100% - 多种方法可用&#x…

CSS 居中对齐 (水平居中 )

水平居中 1.文本居中对齐 内联元素&#xff08;给容器添加样式&#xff09; 限制条件&#xff1a;仅用于内联元素 display:inline 和 display: inline-block; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><…