winform 统计大量数据重复的元素个数_Redis基本数据结构之集合

纸上得来终觉浅,绝知此事要躬行!

e8d5e9afea46d2f663f7ba5bc321bb50.png

集合,也是用来保存多个元素的一种数据结构,和之前介绍的列表有所区别:

  1. 集合元素不允许重复;列表元素可重复;
  2. 集合元素是无序的;列表元素是有序的;

内部编码

集合的内部编码分为两种:intset和hashtable。

(1)整数集合intset

从命名上,我们就可以看出来,intset是整数集合,所以,当集合内元素都是整数的时候,会使用intset作为内部编码,但也是有限制的,限制是什么呢?

# Sets have a special encoding in just one case: when a set is composed# of just strings that happen to be integers in radix 10 in the range# of 64 bit signed integers.# The following configuration setting sets the limit in the size of the# set in order to use this special memory saving encoding.set-max-intset-entries 512

简单翻译一下:集合仅在一种情况下,使用特殊的内部编码,即当集合恰好是由64位有符号整数范围内的10进制整数组成时,下边这个配置项是配置intset编码保存的元素的最大个数。翻译过来,也就一目了然了。

typedef struct intset{uint32_t encoding;  uint32_t length;  int8_t content[];} intset;

从intset的结构可以看出,底层使用的是一个整数数组实现的。并且有一个length记录长度,所以当获取intset编码的集合的长度时,时间复杂度为O(1)。也许大家注意到,content的类型是int8_t,但实际上content数组并不保存任何int8_t类型的值,真正的类型取决于第一个属性:encoding。如果encoding属性值为INTSET_ENC_INT16,那么,content就是一个int16_t类型的数组数组里的每一项都是int16_t类型的值,同理,content也可能是int32_t、int64_t类型的数组(保存的值得范围不同),这取决于集合存储多大的值。

当我们向一个使用intset编码的集合中添加一个新的整数值时,可能会触发升级操作。这里说的升级指的就是content里元素的升级,简单的说,因为content本身是个数组,只能有一个类型,如果说当前数组的所有元素都是int16_t类型的值,这时向集合中添加一个需要int32_t类型才能保存的值,就会触发升级操作,分为三个步骤进行:1、根据新元素的类型,扩展数组的空间大小,并分配空间;2、将数组内现有所有元素都转换成新元素的类型;3、将新元素添加。这种升级策略好处是满足存储要求的同时节约了内存的使用。虽然,固定使用int64_t类型的数组也能满足要求,但是,一般情况而言,一个集合中的数据应该是相似的,很少出现数据差距如此之大的情况。如果一个集合中的数据值都比较小,int16_t类型完全够用,那么使用int64_t类型就非常的浪费空间。

既然有升级,那是不是有降级操作呢?答案是没有!一旦升级之后,就无法降级了。

(2)哈希表hashtable

关于哈希表,在我介绍哈希类型的文章中介绍过,感兴趣的朋友可以点击文章底部的链接查看。

需要在这里说明的是,因为hashtable本身是键值对结构,而集合中元素只是单一元素,那么集合如何使用hashtable来实现呢?实际上,集合只使用了hashtable的键,也就是说使用hashtable编码的集合,集合元素就是hashtable的键,而其对应的值全都设置为了NULL。

常用命令

集合的命令包括两个方面,集合内命令和集合间命令。

(1)集合内命令

63bc736539dbd313d3805e5093e692ec.png

sadd:添加元素命令,可以一次添加多个元素,重复添加元素将被忽略。同时也看到,当集合元素是数值和字符串时,集合的底层编码是不同的。

f1f16c1b997fe134d34bad63a8a368d5.png

srem:删除元素命令,可以同时指定多个元素,执行返回的是成功删除的元素的个数;

scard:统计元素个数的命令,返回集合元素个数,时间复杂度为O(1),因为不管底层编码是intset还是hashtable,结构本身都有变量保存元素个数或者集合长度;

sismember:判断元素是否在集合内的命令,存在返回1不存在返回0;

srandmember:随机返回一个元素的命令,可以指定返回的个数,不指定默认为1;

spop:随机弹出指定个数的元素的命令,不指定个数默认为1个,该命令和srandmember的区别是,spop之后,元素从集合中删除;

smembers:获取集合所有元素的命令,需要注意的是,smembers和哈希的hgetall命令类似,当元素过多时,可能导致服务阻塞,产生性能问题,所以谨慎使用。

(2)集合间命令

集合间命令包含交集、并集、差集,以及将结果生成新集合。

21af61b91bcc5cbb9b37f4583fa4b127.png

sinter、sunion、sdiff分别返回多个(包含一个)集合的交集、并集、差集,在命令后边+store即可将结果保存在新的集合中。需要注意的是sdiff命令,计算差集时参数的顺序和返回内容有关。

典型应用场景

集合类型最典型的应用就是标签(tag)。大家可能对推荐比较熟悉,推荐的原理就是把推荐的内容分类,当你对分类中的某一种或者某几种感兴趣的时候,推荐系统就会把相同分类的其他内容推荐给你。打标签其实就是分类,比如你对娱乐、体育感兴趣,另一个用户对历史、新闻比较感兴趣,这些兴趣就是标签,有了这些标签,就可以知道哪些人喜好相同,从而增加用户的黏度。

集合还有一个应用场景就是随机抽奖,就是用到spop/srandmember命令,通过随机返回,生成随机数进行抽奖。

Redis基本数据结构之哈希

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值