Redisbook学习笔记(3)数据类型之集合
REDIS_SET 集合 是SADD 、SRANDMEMBER 等命令的操作對(duì)象 它使用
REDIS_ENCODING_INTSET 和REDIS_ENCODING_HT 兩種方式編碼
編碼的選擇
第一個(gè)添加到集合的元素決定了創(chuàng)建集合時(shí)所使用的編碼
如果第一個(gè)元素可以表示為long long 類型值也即是它是一個(gè)整數(shù)那么集合的初
始編碼為REDIS_ENCODING_INTSET 。
否則集合的初始編碼為REDIS_ENCODING_HT 。
編碼的切換
如果一個(gè)集合使用REDIS_ENCODING_INTSET 編碼那么當(dāng)以下任何一個(gè)條件被滿足時(shí)這個(gè)
集合會(huì)被轉(zhuǎn)換成REDIS_ENCODING_HT 編碼
intset 保存的整數(shù)值個(gè)數(shù)超過(guò)server.set_max_intset_entries 默認(rèn)值為512 。
試圖往集合里添加一個(gè)新元素并且這個(gè)元素不能被表示為long long 類型也即是
它不是一個(gè)整數(shù)。
字典編碼的集合
當(dāng)使用REDIS_ENCODING_HT 編碼時(shí)集合將元素保存到字典的鍵里面而字典的值則統(tǒng)一設(shè)
為NULL 。
作為例子以下圖片展示了一個(gè)以REDIS_ENCODING_HT 編碼表示的集合集合的成員為elem1
、elem2 和elem3
集合命令的實(shí)現(xiàn)
Redis 集合類型命令的實(shí)現(xiàn)主要是對(duì)intset 和dict 兩個(gè)數(shù)據(jù)結(jié)構(gòu)的操作函數(shù)的包裝以及
一些在兩種編碼之間進(jìn)行轉(zhuǎn)換的函數(shù)大部分都沒有什么需要解釋的地方唯一比較有趣的是
SINTER 、SUNION 等命令之下的算法實(shí)現(xiàn)以下三個(gè)小節(jié)就分別討論它們所使用的算法。
求交集算法
SINTER 和SINTERSTORE 兩個(gè)命令所使用的求并交集算法可以用Python 表示如下
# coding: utf-8 def sinter(*multi_set): # 根據(jù)集合的基數(shù)進(jìn)行排序 sorted_multi_set = sorted(multi_set, lambda x, y: len(x) - len(y)) # 使用基數(shù)最小的集合作為基礎(chǔ)結(jié)果集有助于降低常數(shù)項(xiàng) result = sorted_multi_set[0].copy() # 剔除所有在sorted_multi_set[0] 中存在 # 但在其他某個(gè)集合中不存在的元素 for elem in sorted_multi_set[0]: for s in sorted_multi_set[1:]: if (not elem in s): result.remove(elem) break return result算法的復(fù)雜度為O(N2) 執(zhí)行步數(shù)為S T 其中S 為輸入集合中基數(shù)最小的集合而T 則
為輸入集合的數(shù)量。
求并集算法
SUNION 和SUNIONSTORE 兩個(gè)命令所使用的求并集算法可以用Python 表示如下
# coding: utf-8 def sunion(*multi_set): result = set() for s in multi_set: for elem in s: # 重復(fù)的元素會(huì)被自動(dòng)忽略 result.add(elem) return result算法的復(fù)雜度為O(N) 。
求差集算法
Redis 為SDIFF 和SDIFFSTORE 兩個(gè)命令準(zhǔn)備了兩種求集合差的算法。
以Python 代碼表示的算法一定義如下
# coding: utf-8 def sdiff_1(*multi_set): result = multi_set[0].copy() sorted_multi_set = sorted(multi_set[1:], lambda x, y: len(x) - len(y)) # 當(dāng)elem 存在于除multi_set[0] 之外的集合時(shí) # 將elem 從result 中刪除 for elem in multi_set[0]: for s in sorted_multi_set: if elem in s: result.remove(elem) break return result這個(gè)算法的復(fù)雜度為O(N2) 執(zhí)行步數(shù)為S T 其中S 為輸入集合中基數(shù)最小的集合而
T 則為除第一個(gè)集合之外其他集合的數(shù)量。
以Python 代碼表示的算法二定于如下
# coding: utf-8 def sdiff_2(*multi_set): # 用第一個(gè)集合作為結(jié)果集的起始值 result = multi_set[0].copy() for s in multi_set[1:]: for elem in s: # 從結(jié)果集中刪去其他集合中包含的元素 if elem in result: result.remove(elem) return result這個(gè)算法的復(fù)雜度同樣為O(N2) 執(zhí)行步數(shù)為S 其中S 為所有集合的基數(shù)總和。
Redis 使用一個(gè)程序決定該使用那個(gè)求差集算法程序用Python 表示如下
# coding: utf-8 from sdiff_1 import sdiff_1 from sdiff_2 import sdiff_2 def sdiff(*multi_set): # 算法一的常數(shù)項(xiàng)較低給它一點(diǎn)額外的優(yōu)先級(jí) algo_one_advantage = 2 algo_one_weight = len(multi_set[0]) * len(multi_set[1:]) / algo_one_advantage algo_two_weight = sum(map(len, multi_set)) if algo_one_weight <= algo_two_weight: return sdiff_1(*multi_set) else: return sdiff_2(*multi_set)轉(zhuǎn)載于:https://blog.51cto.com/janephp/1363456
總結(jié)
以上是生活随笔為你收集整理的Redisbook学习笔记(3)数据类型之集合的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 批处理文件检测windows系统是32位
- 下一篇: 4、连接Mysql数据库