Redis之字典(hashtable)
Redis之字典
- 字典是什么(hashtable)
- 總體結(jié)構(gòu)
- dict
- dictht(散列表)
- dictEntry
- 如何解決哈希沖突
- 1. 鏈表法
- 2.rehash法
字典是什么(hashtable)
簡(jiǎn)單來(lái)說(shuō)就是Redis中hash數(shù)據(jù)結(jié)構(gòu)的底層實(shí)現(xiàn)
當(dāng)數(shù)據(jù)小, 并且數(shù)量不多的時(shí)候會(huì)用ziplist來(lái)實(shí)現(xiàn)hash結(jié)構(gòu)
總體結(jié)構(gòu)
這里先給出大體的結(jié)構(gòu), 便于理解
dict
字典底層又是由dict實(shí)現(xiàn)的, 下圖是dict的結(jié)構(gòu)
dictht[]數(shù)組長(zhǎng)度為2, 一般我們使用dictht[0], 另外一個(gè)dictht[1]作為rehash使用
dictht(散列表)
接下來(lái)我們看一下dictht(散列表的實(shí)現(xiàn))
typedef struct dictht {//哈希表數(shù)組dictEntry **table;//哈希表大小unsigned long size;//哈希表大小掩碼,用于計(jì)算索引值unsigned long sizemask;//該哈希已有節(jié)點(diǎn)的數(shù)量unsigned long used; }dictht;dictEntry
- dictEntry是一個(gè)散列表節(jié)點(diǎn)
散列表的節(jié)點(diǎn)是由下定義的
- key就是實(shí)際存儲(chǔ)鍵的地方
- 聯(lián)合體中就是實(shí)際存儲(chǔ)值的地方
- 散列表節(jié)點(diǎn)還有一個(gè)next域指向下一個(gè)節(jié)點(diǎn), 可以用來(lái)解決哈希沖突問(wèn)題
如何解決哈希沖突
1. 鏈表法
當(dāng)有兩個(gè)或以上的鍵被分配到散列表數(shù)組同一個(gè)索引上時(shí),就發(fā)生了鍵沖突。Redis使用鏈表法解決散列沖突。
值得一提的是比如V0先加入這個(gè)節(jié)點(diǎn)中, 又來(lái)一個(gè)V1和V0的值一個(gè)都被分配 到了一個(gè)地址, 那么就會(huì)在V0的頭部插入V1.
2.rehash法
隨著操作的進(jìn)行, dict內(nèi)保存的鍵值對(duì),會(huì)不斷的減少或者增加, 我們需要保證負(fù)載因子的正常, 那么就要重新進(jìn)行分配內(nèi)存
這個(gè)時(shí)候dicht[1]就可以起到作用了, 并且rehashids也會(huì)設(shè)置為0表示正在rehash中
rehash的過(guò)程
1.為字典的ht[1]散列表分配空間,這個(gè)空間的大小取決于要執(zhí)行的操作以及ht[0]當(dāng)前包含的鍵值對(duì)數(shù)量(即:ht[0].used的屬性值)
- 擴(kuò)展操作:ht[1]的大小為 第一個(gè)大于等于ht[0].used2的2的n次方冪。如:ht[0].used=3則ht[0] = 32 = 6, 第一個(gè)大于或者等于的2^n就是 2 ^ 3=8所以ht[1]的大小為8,ht[0].used=4則ht[1]的大小也為8。
- 收縮操作: ht[1]的大小為 第一個(gè)大于等于ht[0].used的2的n次方冪。
2.將保存在ht[0]中的鍵值對(duì)重新計(jì)算鍵的散列值和索引值,然后放到ht[1]指定的位置上. 當(dāng)然這不是一步完成的, 是一部分一部分的賦值過(guò)去
3.當(dāng)我們把ht[0]上面所有的鍵值對(duì)都給移過(guò)去到h[1]之后, 就會(huì)釋放h[0]的空間, 并且將h[1]記為ht[0], 最后再創(chuàng)建一個(gè)新的ht[1]散列表為下一次rehash做準(zhǔn)備。
這就是本次全部?jī)?nèi)容,若是看不懂建立配合著圖來(lái)理解
總結(jié)
以上是生活随笔為你收集整理的Redis之字典(hashtable)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Redis基本数据的的常见命令操作
- 下一篇: Redis之链表