IntSet

news2025/3/13 20:04:30

基本概述

IntSet是Redis中set集合的一种实现方式,基于整数数组来实现,并且具备长度可变、有序等特征。

结构如下:

typedef struct intset {
    uint32_t encoding; /* 编码方式,支持存放16位、32位、64位整数(4字节32比特位)*/ 
    uint32_t length; /* 元素个数 */
    int8_t contents[]; /* 整数数组,保存集合数据*/
} intset;

其中的encoding包含三种模式,表示存储的整数大小不同:

/* Note that these encodings are ordered, so:
 * INTSET_ENC_INT16 < INTSET_ENC_INT32 < INTSET_ENC_INT64. */
#define INTSET_ENC_INT16 (sizeof(int16_t)) /* 2字节整数,范围类似java的short*/
#define INTSET_ENC_INT32 (sizeof(int32_t)) /* 4字节整数,范围类似java的int */
#define INTSET_ENC_INT64 (sizeof(int64_t)) /* 8字节整数,范围类似java的long */

为了方便查找,Redis会将intset中所有的整数按照升序依次保存在contents数组中,结构如图:(数组中元素大小要固定,方便寻址、快速定位元素

image-20230612232628095

image-20230612232913895

上述,数组中每个数字都在int16_t的范围内,因此采用的编码方式是INTSET_ENC_INT16,每部分占用的字节大小

  • encoding:4字节
  • length:4字节
  • contents:2字节 * 3 = 6字节

IntSet升级

现在,假设有一个intset,元素为{5,10,20},采用的编码是INTSET_ENC_INT16,则每个整数占2字节:

image-20230612233307741

此时,向该其中添加一个数字:50000,这个数字超出了int16_t的范围,intset会自动升级编码方式到合适的大小。

升级流程:

升级编码为INTSET_ENC_INT32, 每个整数占4字节,并按照新的编码方式及元素个数扩容数组

倒序依次将数组中的元素拷贝到扩容后的正确位置(元素下标以及元素所占字节,倒序防止覆盖原有数据

③ 将待添加的元素放入数组末尾

④ 最后,将inset的encoding属性改为INTSET_ENC_INT32,将length属性改为4

image-20230612233632386

IntSet新增流程

源码如下:

intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
    // 获取新增值的编码
    uint8_t valenc = _intsetValueEncoding(value);
    uint32_t pos;
    if (success) *success = 1;

    // 判断编码是不是超过了当前intset的编码
    if (valenc > intrev32ifbe(is->encoding)) {
        // 超出编码,需要升级
        return intsetUpgradeAndAdd(is,value);
    } else {
        // 在当前intset中查找值与value一样的元素的角标pos
        if (intsetSearch(is,value,&pos)) { // 二分查找
            //如果找到了,则无需插入,直接结束并返回失败(set)
            if (success) *success = 0;
            return is;
        }

        // 数组扩容
        is = intsetResize(is,intrev32ifbe(is->length)+1);
        // 移动数组中pos之后的元素到pos+1,给新元素腾出空间
        if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
    }

    // 插入新元素
    _intsetSet(is,pos,value);
    // 重置元素长度
    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
    return is;
}
static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
    // 获取当前intset编码
    uint8_t curenc = intrev32ifbe(is->encoding);
    // 获取新增值编码
    uint8_t newenc = _intsetValueEncoding(value);
    // 获取元素个数
    int length = intrev32ifbe(is->length);
    // 判断新元素是大于0还是小于0 ,小于0插入队首、大于0插入队尾
    int prepend = value < 0 ? 1 : 0;

    // 重置编码为新编码
    is->encoding = intrev32ifbe(newenc);
    // 重置数组大小
    is = intsetResize(is,intrev32ifbe(is->length)+1);

    // 倒序遍历,逐个搬运元素到新的位置,_intsetGetEncoded按照旧编码方式查找旧元素
    while(length--)
        _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));

    // value 值大于0,新元素放在末尾;value值小于0,最前面空出一个位置,插入队首(判断元素插入队首还是队尾)
    if (prepend)
        _intsetSet(is,0,value);
    else
        _intsetSet(is,intrev32ifbe(is->length),value);
    // 修改数组长度
    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
    return is;
}

优点

Intset可以看做是特殊的整数数组,具备一些特点:

① Redis会确保Intset中的元素唯一、有序

② 具备类型(整数编码类型)升级机制,可以节省内存空间

③ 底层采用二分查找方式来查询(少量数据比较合适,数据量大了,二分查找会影响性能)

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

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

相关文章

chatgpt赋能python:Python如何并排输入数字

Python如何并排输入数字 Python是一个功能强大的编程语言&#xff0c;可以用于各种用途&#xff0c;包括数据分析、机器学习、Web开发等。对于很多初学者来说&#xff0c;学会如何并排输入数字可能是一个基础的技巧。在本文中&#xff0c;我们将介绍如何使用Python在同一行中输…

RK3588平台开发系列讲解(USB篇)USB 常用调试方法

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、USB枚举成功标志二、USB speed查询三、USB 查询PID、VID四、USB 当前 端口组合五、USB 动态打印debug日志六、USB IPC log分析沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要 介绍 USB 常用调试…

安卓期末考试知识总结(2)

文章目录 第四章&#xff1a;程序活动单元Activity四大组件Activity生命周期Activity的启动模式standardsingleTopsingleInstancesingleTask IntentIntentFilterActivity之间的数据传递putExtra()方法传递数据Bundle类传递数据Activity之间的数据回传 练习总结 第四章&#xff…

Java虚拟机原理

Java是一种跨平台的语言&#xff0c;这意味着Java开发出来的程序经过编译后&#xff0c;可以在Linux上运行&#xff0c;也可以在Windows上运行&#xff1b;可以在PC、服务器上运行&#xff0c;也可以在手机上运行&#xff1b;可以在X86的CPU上运行&#xff0c;也可以在ARM的CPU…

chatgpt赋能python:Python引入Math库的使用方法

Python引入Math库的使用方法 Python作为一门强大的编程语言&#xff0c;有着广泛的应用场景。在计算领域中&#xff0c;Python也有很多优秀的库来进行相应的计算。其中一个广泛使用的库就是Math库。这个库包含了很多数学函数&#xff0c;如三角函数、幂函数、对数函数等等。在…

剑指offer21.调整数组顺序使奇数位于偶数前面

毫无难度。 class Solution {public int[] exchange(int[] nums) {int i 0;int size nums.length;int[] res new int[size];int jsize-1;for(int k 0; k<size;k){if(nums[k]%2 0){res[j]nums[k];j--;}else{res[i]nums[k];i;}}return res;} }

关于 Ceph 存储集群配置的一些笔记

写在前面 Ceph 考试整理笔记&#xff0c;老师总结基础上&#xff0c;略有补充博文内容涉及&#xff1a; ceph 集群的配置简单介绍永久和零时修改集群配置文件集群 Mon 的配置集群身份验证的配置集群多网络的配置 理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有…

Mysql 索引调优

前言 索引是帮助MySQL高效获取数据的数据结构 常用索引 1、普通索引 普通索引是最基本的索引&#xff0c;仅用于加速查询&#xff0c;没有任何限制&#xff1a;可以为空、可以重复 2、唯一索引 唯一索引与普通索引类似&#xff0c;但索引列的值必须唯一 3、主键索引 主…

chatgpt赋能python:Python怎么将界面和程序交互

Python怎么将界面和程序交互 随着互联网技术的不断发展和普及&#xff0c;越来越多的人开始关注于网站的设计和开发。在Web应用程序的开发过程中&#xff0c;与用户进行交互是至关重要的一个方面&#xff0c;而Python作为一种强大的开发语言&#xff0c;可以很好地帮助我们实现…

C++中防止头文件重复包含处理办法

首先给出可以拷贝的模板&#xff1a; #ifndef _ADDNUM_H_ #define _ADDNUM_H_这里加上相应的函数声明即可 #endif在小型项目中&#xff0c;如果将函数的定义写在main函数的后面&#xff0c;那么需要在main函数前面加上这个函数的声明才可以顺利运行成功。 #include <iostr…

python:基础知识—流程控制—函数与模块—数据结构—类与GUI和Turtle—异常处理与文件,概括全书(上万字最详细版)

这里是一张夜景&#xff0c;给大家放松一下。 !&#xff01;无锡南长街 文章目录 模块一&#xff1a;基础知识1、python语言2、常见数字类型3、字符串4、数字类型转换5、标识符命名6、常见关键字7、运算符与表达式&#xff08;1&#xff09;算术运算符&#xff08;2&#xff09…

web自动化框架playwright

参考&#xff1a;新兴爬虫利器 Playwright 的基本用法 | 静觅 (cuiqingcai.com) http://t.csdn.cn/S7260 官方文档&#xff1a;Trace viewer | Playwright 安装 pip3 install playwright playwright install 第一个demo from playwright.sync_api import sync_playwri…

python中的lambda表达式

目录 1.lambda函数的简介 2.为什么要用lambda函数 3.lambda函数的效率 4.lambda函数常用举例 4.1 多参数 4.2 与map函数进行使用 4.3 求两个列表元素的和 5.个人见解 1.lambda函数的简介 lambda函数是一种匿名函数&#xff0c;即没有名字的函数使用lambda保留字定…

Qt(C++)调用libass库完成ASS字幕渲染显示(高级版)

一、项目实现 1.1 实现效果 1.2 开发环境 Qt版本: 5.12.6 编译器: MinGW_32位、MSVC_32位(2017) 操作系统: win10 X64 1.3 实现功能 当前利用Qt+libass库完成了ASS字幕渲染显示,字幕渲染也就是将ASS文件里的当前时间段的字幕信息传递给libass库,渲染之后返回一张图片,在…

chatgpt赋能python:如何使用Python得到8/3的小数部分

如何使用Python得到8/3的小数部分 在数学中&#xff0c;8/3是一个分数&#xff0c;可以被表示为2.6666666666666665。然而&#xff0c;在Python中&#xff0c;我们可以使用一些技巧来得到它的小数部分。 什么是小数部分&#xff1f; 小数部分是一个数的小数点后的部分&#…

Spring Security--密码加密

项目的话&#xff0c;我们是继续写的&#xff0c;此时项目是已经实现了数据库的用户名&#xff0c;密码登录&#xff0c;且用的是自己的登录页面。 密码加密我们用到这PasswordEncoder这个接口 public interface PasswordEncoder {String encode(CharSequence rawPassword);b…

gitlab+jenkins+harbor实现CI/CD(1)——环境准备

gitlabjenkinsharbor实现CI/CD&#xff08;1&#xff09;——环境准备 前言一、git工具git安装初始化版本库登录上传 二、gitlab使用gitlab部署登录设置克隆项目 jenkins使用安装jenkins登录设置 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&am…

D349周赛:注意题目提示里,数据范围隐含的算法复杂度提示

文章目录 6470.既不是最大值也不是最小值完整版为什么两个for循环时间复杂度还是不变的 6465.执行子串操作后的字典序最小字符串思路最开始的写法题意理解的问题 修改版a必须单独拿出来的原因 6449.收集巧克力思路注意提示信息 完整版补充&#xff1a;由数据范围反推算法复杂度…

统计学中的「标准差和方差」

标准差(Standard deviation) 简单来说&#xff0c;标准差是一组数值自平均值分散程度的一种测量观念。一个较大的标准差&#xff0c;代表大部分的数值和其平均值之间差异较大&#xff0c;一个较小的标准差&#xff0c;代表这些数值较接近平均值。 例如&#xff1a; 两组数的集…

开源数字人、虚拟直播部署教程

TheRamU/Fay: 语音互动,直播自动带货 虚拟数字人 (github.com) gitee fay: 这是一个数字人项目,包含python内核及ue数字人模型,可以用于做数字助理及自动直播,又或者作为你的应用入口也很帅 (gitee.com) 2022.10.27 补充mac上的安装办法:(34条消息) Fay数字人开源项目…