【redis使用及数据结构篇】——set

redis中其他几种数据类型:
List类型使用及底层结构
String类型使用及底层结构
hash类型使用及底层结构
Zset类型使用及底层结构

一、基本用法

##添加元素 sadd  查看元素smembers  判断元素是否存在sismenber
127.0.0.1:6379> sadd myset hello hello1 hello2    #往set中添加元素
(integer) 3
127.0.0.1:6379> smembers myset        #查看myset中的所有元素
1) "hello2"
2) "hello"
3) "hello1"
127.0.0.1:6379> sismember myset hello	   #查看hello是否在myset中
(integer) 1

#获取set中元素个数      scard
127.0.0.1:6379> scard myset
(integer) 3

#移除set中指定的元素       srem
#随机移除set中的元素       spop
127.0.0.1:6379> srem myset hello2     #移除指定元素
(integer) 1
127.0.0.1:6379> smembers myset
1) "hello"
2) "hello1"
127.0.0.1:6379> smembers myset
1) "4"
2) "1"
3) "2"
4) "5"
5) "hello"
6) "hello1"
7) "6"
8) "3"
127.0.0.1:6379> spop myset       #随机移除元素
"3"
127.0.0.1:6379> spop myset
"2"

#因为set是无序不重复集合,所以可以随机从set中获取值
#随机抽出一个元素    srandmember
#随机抽出n个元素     srandmember myset n
127.0.0.1:6379> srandmember myset
"hello1"
127.0.0.1:6379> srandmember myset
"hello"
127.0.0.1:6379>

#将一个集合中的特定元素移动到另一个集合   smove
127.0.0.1:6379> smove myset myset2 4    #将myset中的4元素移动到myset2
(integer) 1
127.0.0.1:6379> smembers myset2
1) "4"
127.0.0.1:6379>

#查看两个集合中共同的元素/不同的元素/合在一起总共的元素        sinter/sdiff/sunion
127.0.0.1:6379> sadd key1 a b c
(integer) 3
127.0.0.1:6379> sadd key2 c d e
(integer) 3
127.0.0.1:6379> sinter key1 key2		#查看key1和key2中相同的元素
1) "c"
127.0.0.1:6379> sdiff key1 key2			#查看key1中与key2中不同的元素
1) "a"
2) "b"
127.0.0.1:6379> sdiff key2 key1			#查看key2中与key1中不同的元素
1) "e"
2) "d"
127.0.0.1:6379> sunion key1 key2		#查看key1和key2合在一起有多少元素
1) "b"
2) "c"
3) "d"
4) "a"
5) "e"
127.0.0.1:6379>

二、底层结构

set的底层实现主要靠的是哈希表和整数集合,这里主要讲一下整数集合。当一个 Set 对象只包含整数值元素,并且元素数量不大时,就会使用整数集这个数据结构作为底层实现。

1.结构设计

typedef struct intset {
    //编码方式
    uint32_t encoding;
    //集合包含的元素数量
    uint32_t length;
    //保存元素的数组
    int8_t contents[];
} intset;

保存元素的容器是一个 contents 数组,虽然 contents 被声明为 int8_t 类型的数组,但是实际上 contents 数组并不保存任何 int8_t 类型的元素,contents 数组的真正类型取决于 intset 结构体里的 encoding 属性的值。

如果 encoding 属性值为 INTSET_ENC_INT16,那么 contents 就是一个 int16_t 类型的数组,数组中每一个元素的类型都是 int16_t。不同类型的 contents 数组,意味着数组的大小也会不同。

2.整数集合的升级操作

整数集合会有一个升级规则,就是当我们将一个新元素加入到整数集合里面,如果新元素的类型(int32_t)比整数集合现有所有元素的类型(int16_t)都要长时,整数集合需要先进行升级,也就是按新元素的类型(int32_t)扩展 contents 数组的空间大小,然后才能将新元素加入到整数集合里,当然升级的过程中,也要维持整数集合的有序性。

整数集合升级的过程不会重新分配一个新类型的数组,而是在原本的数组上扩展空间

eg.假设有一个整数集合里有 3 个类型为 int16_t 的元素

image-20220504194809854

现在,往这个整数集合中加入一个新元素 65535,这个新元素需要用 int32_t 类型来保存,所以整数集合要进行升级操作,首先需要为 contents 数组扩容,在原本空间的大小之上再扩容多 80 位(4x32-3x16=80),这样就能保存下 4 个类型为 int32_t 的元素

image-20220504194856325

image-20220504194923632

整数升级的好处

如果要让一个数组同时保存 int16_t、int32_t、int64_t 类型的元素,最简单做法就是直接使用 int64_t 类型的数组。不过这样的话,当如果元素都是 int16_t 类型的,就会造成内存浪费的情况。而使用整数升级的话,就可以很好的节约内存资源。

(注意:只支持升级不支持降级!)

参考
[小林coding]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值