redis 系列8 数据结构之整数集合
一.概述
整数集合(intset)是集合键的底层实现之一, 当一个集合只包含整数值元素,并且这个集合元素数量不多时, Redis就会使用整数集合作为集合键的底层实现。下面创建一个只包含5个元素的集合键,并且集合中所有元素都是整数值,那么这个集合键的底层实现就会是整数集合。 接着添加非整数值,集合键的底层实现就会是hashtable。
127.0.0.1:> sadd numbers
(integer)
127.0.0.1:> object encoding numbers
"intset"
127.0.0.1:> sadd numbers 'one'
(integer)
127.0.0.1:> object encoding numbers
"hashtable"
二. 整数集合实现
整数集合是Redis用于保存整数值的集合抽象数据结构,它可以保存类型为int16_t, int32_t, int64_t的整数值,并且保证集合中不会出现重复元素。数据集合定义如下:
// 每个intset.h/intset结构表示一个整数集合
typedef struct intset
{
//编码方式
uint32_t encoding;
//集合包含的元素数量
uint32_t length;
//保存元素的数组
int8_t contents[];
}intset;
(1) contents数组是整数集合的底层实现,整数集合的每个元素都是contents数组的一个数组项(item),各个项在数组中按值从小到大有序排列,并且数组中不包含重复项。如下面脚本:
127.0.0.1:> sadd record
(integer)
127.0.0.1:> smembers record
) ""
) ""
) ""
) ""
) ""
(2) length属性记录了整数集合包含的元素数量,也即是contents数组的长度。虽然contents属性声明为int8_t类型的数组,但实现上contents数组并不保存任何int8_t类型的值,contents数组的真正类型取决于encoding属性的值。
a. 如果encoding 属性的值为intset_enc_int16,那么contents就是一个int16_t类型的数组,数组里的每个项都是一个int16_t类型的整数值(范围在 -32768 ~ 32767)。如下图encoding属性的值有5个整数型,根据这些整数值得出encoding为int16_t类型。
b. 如果encoding属性的值为intset_enc_int32, 那么数组里每个项就是一个int32_t类型的整数值(范围在 -2147483648 ~ 2147483647)。还有encoding属性的值为intset_enc_int64类型的,数组里每个项取取值范围更大。
需要注意的是:假设contents数组保存的值为2147483647, 1,2,3 四个整数值。 但只有第一个整数值需要用int32_t类型来保存,而其它三个值可以用int16_t类型来保存。不过根据整数集合的升级规则,当一个底层的int16_t数组的整数集合添加一个int64_t类型的整数值时,整数集合中所有元素都会被转换成int64_t类型。 所以contents数组保存的整数值都是int64_t类型的。
三. 升级
当我们要将一个新元素添加到整数集合里面,并且新元素的类型比整数集合现有所有元素的类型都要长时,整数集合需要先进行升级,然后才能将新元素添加到整数集合中。假设:集合中包含三个int16_t类型的元素,值分别是1,2,3 。因为每个元素都占用16位空间,所以整数集合底层数组的大小 为3 * 16 =48位。现将int32_t的数值65535添加进去,这里程序需要对整数集合进行升级。
升级整数集合并添加新元素共分三步进行:
(1) 根据新元素的类型,扩展整数集合底层数组的空间大小 ,并为新元素分配空间。分配空间后,现在整数集合4个元素的底层数组大小为4 *32 =128位, 此时前三位还是48位空间,如下图所示:
(2) 将底层数组现有的所有元素都转换成与新元素相同的类型(需要从int16_t 转成int32_t所需的空间) ,转换后元素位置有序不变,如下图所示:
(3) 将新元素添加到底层数组里面,如下图所示:
四. 升级的好处
4.1 提升灵活性
为了避免类型错误,通常不会将两种不同类型的值放在同一个数据结构里面,通过升级处理可以随意地将int16_t, int32_t, , int64_t 类型的整数添加到集合中,而不必担心出现类型错误。
4.2 节约内存
要让一个数组可以同时保存int16_t,int32_t, , int64_t三种类型的值,最简单的做法就是直接使用int64_t类型的数组作为整数集合的底层实现,不过这样浪费内存空间。
五. 降级
整数集合不支持降级操作,一旦对数组进行了升级,编码就会一直保持升级后的状态。即使集合里只有一个需要使用int64_t类型的元素被删除了,整数集合的编码仍然会维持intset_enc_int64, 底层数组也仍然会是int64_t类型,如下图所示:
六. 整数集合API
函数 |
作用 |
intsetNew |
创建一个新的压缩列表 |
intsetAdd |
将给定元素添加到整数集合里面 |
intsetRemove |
从整数集合中移除给定元素 |
intsetFind |
检查给定值是否存在于集合 |
intsetRandom |
从整数集合中随机返回一个元素 |
intsetGet |
取出底层数组在给定索引上的元素 |
intsetLen |
返回整数集合包含的元素个数 |
intsetBloblen |
返回整数集合占用的内存字节数 |
redis 系列8 数据结构之整数集合的更多相关文章
- Redis 的底层数据结构(整数集合)
当一个集合中只包含整数,并且元素的个数不是很多的话,redis 会用整数集合作为底层存储,它的一个优点就是可以节省很多内存,虽然字典结构的效率很高,但是它的实现结构相对复杂并且会分配较多的内存空间. ...
- Redis数据结构之整数集合
整数集合是Redis用于保存整数值的集合抽象数据结构,它可以保存类型为int16_t .int32_t或者int64_t的整数值,并且保证集合中不会出现重复元素. 一.整数集合数据结构定义 参数说明: ...
- Redis数据结构之整数集合-intset
当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis会使用整数集合(intset)来存储集合元素. intset是紧凑的数组结构,同时支持16位.32位和64位整数. 结构 struc ...
- Redis 底层数据结构之整数集合
文章参考:<Redis 设计与实现>黄建宏 整数集合 整数集合时集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合数量不多时,就会使用整数集合 typedef struct i ...
- 跟着大彬读源码 - Redis 10 - 对象编码之整数集合
[TOC] 整数集合是 Redis 集合键的底层实现之一.当一个集合只包含整数值元素,并且元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现. 1 整数集合的实现 整数集合是 Redis ...
- redis 系列7 数据结构之跳跃表
一.概述 跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.在大部分情况下,跳跃表的效率可以和平衡树(关系型数据库的索引就是平衡树 ...
- redis源码学习_整数集合
redis里面的整数集合保存的都是整数,有int_16.int_32和int_64这3种类型,和C++中的set容器差不多. 同时具备如下特点: 1.set里面的数不重复,均为唯一. 2.set里面的 ...
- Redis系列二 - 数据结构
前言 redis作为我们开发的一大神器,我们接触肯定不会少,但是很多同学也许只会存储String类型的值,这是非常不合理的.在这里,将带大家认识Redis的5中数据结构. 1.问:Redis有那些数据 ...
- redis 系列5 数据结构之字典(上)
一. 概述 字典又称符号表(symbol table),关联数组(associative array), 映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构.在字典中, ...
随机推荐
- 回文数(vector的使用)
问题描述一个正整数,如果交换高低位以后和原数相等,那么称这个数为回文数.比如 121,2332 都是回文数,134567 不是回文数. 任意一个正整数,如果其不是回文数,将该数交换高低位以后和原数相加 ...
- python3中列表、元组、字典的增删改查说明详解
python基础中的列表.元组.字典属于python中内置的序列数据结构.其中序列可以进行的操作包括索引.截取(切片).加.乘.成员检查等. 1.列表 列表(list)是最常用的python数据类型之 ...
- 用Sklearn画一颗决策树
小伙伴们大家好~o( ̄▽ ̄)ブ,首先声明一下,我的开发环境是Jupyter lab,所用的库和版本大家参考: Python 3.7.1(你的版本至少要3.4以上 Scikit-learn 0.20.0 ...
- C#的排序Sort和OrderBy扩展方法
可以实现一个IComparable接口的CompareTo方法,或者是给予List的Sort扩展方法,传入委托实现,举个例子: list.Sort((a, b) => { var o = a.s ...
- 【Vue-Cli3.0】【1】创建一个Vue-Cli3.0的项目
最近在做爬虫,然后要爬好多数据,代码写完了,就让它在爬了.不想闲着就复习一下Vue吧! 开始开始! ***正式讲解之前 先下载一个node.js吧! 一.首先检查一下 版本 PS D:\徐孟林\D D ...
- [AGC017D]Game on Tree
[AGC017D]Game on Tree 题目大意: 一棵\(n(n\le10^5)\)个结点的树.A和B轮流进行游戏,A先手.每次删掉一棵子树,根结点不能删.最先不能操作的人输,问最后谁赢. 思路 ...
- Windows10用fiddler抓包Android应用(解决手机设置代理后无法上网,设置只抓app包)
1.环境准备 1.电脑上安装fiddler 2.手机和电脑在同一个局域网内 2.设置 1.fiddler>Tools>Fiddler Options>Connections 勾选Al ...
- Kafka监控工具kafka-monitor v0.1简要介绍
Kafka Monitor为Kafka的可视化管理与监控工具,为Kafka的稳定运维提供高效.可靠.稳定的保障,这里主要简单介绍Kafka Monitor的相关功能与页面的介绍: Kafka Moni ...
- web 12
调用一个地图(百度地图)API(定位) 到网站: 1.调用API的js : <script type="text/javascript" src="https:// ...
- 使用secureCRT和Telnet将文件压缩导出到Ubuntu中,到Ubuntu中加压缩发现:tar解压包的时候出现错误gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error is not recoverable: exiting now
细节描述: 问题如题所示:查找博客园和CSDN上查找问题,得到问题解决方法大致如下: 1 修改解压缩命令: 由 tar zxvf software_package.tar.gz变为tar xvf so ...