摘要:散列表結(jié)構(gòu)字典與集合散列表散列表結(jié)構(gòu)是字典和集合的一種實(shí)現(xiàn)方式。使用散列表存儲(chǔ)數(shù)據(jù)時(shí),通過(guò)一個(gè)散列函數(shù)將鍵映射為一個(gè)數(shù)字,這個(gè)數(shù)字范圍是到列表長(zhǎng)度。即使使用一個(gè)高效的散列函數(shù),仍然存在將兩個(gè)鍵映射為同一個(gè)值的可能,這種現(xiàn)象稱為碰撞。
散列表結(jié)構(gòu) 字典與集合 散列表
散列表(Hash Table)結(jié)構(gòu)是字典(Dictionary)和集合(Set)的一種實(shí)現(xiàn)方式。散列算法的作用是盡可能快地在數(shù)據(jù)結(jié)構(gòu)中找到一個(gè)值。在散列表上插入、刪除和取用數(shù)據(jù)都非???,但是對(duì)于查找操作來(lái)說(shuō)卻效率地下
散列表是基于數(shù)組進(jìn)行設(shè)計(jì)的,數(shù)組的長(zhǎng)度是預(yù)先設(shè)定,如有需要可隨時(shí)增加。所有元素根據(jù)和該元素對(duì)應(yīng)的鍵,保存在數(shù)組的特定位置。使用散列表存儲(chǔ)數(shù)據(jù)時(shí),通過(guò)一個(gè)散列函數(shù)將鍵映射為一個(gè)數(shù)字,這個(gè)數(shù)字范圍是0到列表長(zhǎng)度。散列函數(shù)的選擇依賴于鍵的數(shù)據(jù)類型,在此我們對(duì)鍵的hash值對(duì)數(shù)組長(zhǎng)度區(qū)余的方法。散列表的數(shù)組究竟應(yīng)該有多大?這是編寫(xiě)散列函數(shù)時(shí)必須要考慮的。對(duì)散列表大小的限制,通常數(shù)組的長(zhǎng)度應(yīng)該是一個(gè)質(zhì)數(shù)。
理想情況下,散列函數(shù)會(huì)將每個(gè)鍵值映射為唯一的數(shù)組索引,然而,鍵的數(shù)量是無(wú)限的,散列表的長(zhǎng)度是有限的,一個(gè)理想的目標(biāo)是讓散列函數(shù)盡量將鍵均勻地映射到散列表中。即使使用一個(gè)高效的散列函數(shù),仍然存在將兩個(gè)鍵映射為同一個(gè)值的可能,這種現(xiàn)象稱為碰撞(collision)。當(dāng)碰撞發(fā)生時(shí),我們需要方案去解決。
分離鏈接:實(shí)現(xiàn)散列表底層數(shù)組中,每個(gè)數(shù)組元素是一個(gè)新的數(shù)據(jù)結(jié)構(gòu),比如另一個(gè)數(shù)組(二維數(shù)組),這樣就能存儲(chǔ)多個(gè)鍵了。即使兩個(gè)鍵散列后的值相同,依然被保存在同樣的位置,只不過(guò)它們?cè)诘诙€(gè)數(shù)組中的位置不一樣罷了。
線性探查:當(dāng)發(fā)生碰撞時(shí),線性探測(cè)法檢測(cè)散列表的下一個(gè)位置是否為空。如果為空,就將數(shù)據(jù)存入該位置;如果不為空,則繼續(xù)檢查下一個(gè)位置,直到找到一個(gè)空的位置為止。
負(fù)載因子:如果我們持續(xù)往散列表中添加數(shù)據(jù)空間會(huì)不夠用。負(fù)載因子是已使用的空間比散列表大小的值。比如,散列表大小為13,已使用空間位8,負(fù)載因子位0.62。通常當(dāng)負(fù)載因子超過(guò)0.8時(shí),就要新開(kāi)辟空間并重新散列了。
散列表的操作:
方法 | 操作 |
---|---|
put | 向散列表添加新鍵值,或更新鍵的值 |
remove | 從散列表刪除鍵值 |
get | 返回鍵索引到的值 |
# python3 class HashTable: def __init__(self, size=11): self._keys = [None] * size self._values = [None] * size self._length = 0 # 獲取負(fù)載因子 @property def _load_factor(self): return self._length / float(len(self._keys)) # 散列函數(shù) def _hash_func(self, key): l = len(self._keys) idx = abs(hash(key)) % l # 獲取空索引 while self._keys[idx] is not None and self._keys[idx] != key: idx = (idx + l + 1) % l return idx def put(self, key, value): idx = self._hash_func(key) # 更新 if self._keys[idx] == key: self._values[idx] = value # 添加 elif self._keys[idx] is None: self._keys[idx] = key self._values[idx] = value self._length += 1 # 檢查負(fù)載因子 if self._load_factor >= 0.8: self._rehash() def get(self, key): idx = self._hash_func(key) if self._keys[idx] == key: return self._values[idx] return None def remove(self, key): idx = self._hash_func(key) if self._keys[idx] == key: self._keys[idx] = None self._values[idx] = None self._length -= 1 elif self._keys[idx] is None: self._values[idx] = None else: return -1 # 重新散列,擴(kuò)展大小 def _rehash(self): old_keys = self._keys old_value = self._values new_size = len(self._keys) * 2 self._keys = [None] * new_size self._values = [None] * new_size self._length = 0 for idx in range(len(old_keys)): if old_keys[idx] is not None: self.put(old_keys[idx], old_value[idx]) def length(self): return self._length字典
散列表的基本方法就是字典常用的方法,在此可以繼承散列表類的方法,然后完善其他的字典支持的方法。
字典的操作:
方法 | 操作 |
---|---|
keys | 返回所有鍵 |
values | 返回所有值 |
items | 返回所有鍵值對(duì) |
# python3 class Dict(HashTable): def keys(self): return [key for key in self._keys if key is not None] def values(self): return [value for value in self._values if value is not None] def items(self): return [(self._keys[idx], self._values[idx]) for idx in range(0, len(self._keys)) if self._keys[idx] is not None] def __iter__(self): return iter(self.keys()) def __len__(self): return self.length() def __getitem__(self, key): return self.get(key) def __setitem__(self, key, value): self.put(key, value) def __contains__(self, key): idx = self._hash_func(key) return self._keys[idx] is not None集合
集合是一種包含不同元素的數(shù)據(jù)結(jié)構(gòu)。集合中的元素被稱為成員。集合的兩個(gè)重要特性:首先,集合中的成員是無(wú)序的;其次:集合中不允許相同的成員存在。
集合的定義:
不包含任何成員的集合稱為空集,包含一切可能成員的集合稱為全集。
如果兩個(gè)和的成員完全相同,則稱兩個(gè)集合相等。
如果一個(gè)集合中所有的成員都屬于另一個(gè)集合,則前一集合稱為后一集合的子集。
集合的運(yùn)算:
并集:將兩個(gè)集合中的成員進(jìn)行合并,得到一個(gè)新集合。
交集:兩個(gè)集合中共同存在的成員組成一個(gè)新的集合。
補(bǔ)集:屬于一個(gè)集合而不屬于另一個(gè)集合的成員組成的集合。
其實(shí)集合也是個(gè)散列表,散列表有鍵和值,在這里我們把值設(shè)置位True即可。具體實(shí)現(xiàn)如下。
集合的操作:
方法 | 操作 |
---|---|
put | 向集合添加成員。 |
remove | 從集合移除成員。 |
union | 接收一個(gè)集合進(jìn)行并集運(yùn)算返回結(jié)果 |
intersection | 接收一個(gè)集合進(jìn)行交集運(yùn)算返回結(jié)果 |
difference | 接收一個(gè)集合進(jìn)行補(bǔ)集運(yùn)算返回結(jié)果 |
# python3 class Set(HashTable): def put(self, key): return super(Set, self).put(key, value=True) # 并集運(yùn)算 def union(self, other): if isinstance(other, Set): temp = other for key in self._keys: temp.put(key) return temp else: raise TypeError # 交集運(yùn)算 def intersection(self, other): if isinstance(other, Set): temp = Set() for key in self._keys: if key in other: temp.put(key) return temp else: raise TypeError() # 補(bǔ)集運(yùn)算 def difference(self, other): if isinstance(other, Set): temp = Set() for key in self._keys: if key not in other: temp.put(key) return temp else: raise TypeError() def __or__(self, other): return self.union(other) def __and__(self, other): return self.intersection(other) def __sub__(self, other): return self.difference(other) def __len__(self): return self._length def __iter__(self): for key in self._keys: if key is not None: yield key def __contains__(self, key): idx = self._hash_func(key) return self._keys[idx] is not None
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44817.html
摘要:若對(duì)于關(guān)鍵字集合中的任一個(gè)關(guān)鍵字,經(jīng)散列函數(shù)映象到地址集合中任何一個(gè)地址的概率是相等的,則稱此類散列函數(shù)為均勻散列函數(shù),這就是使關(guān)鍵字經(jīng)過(guò)散列函數(shù)得到一個(gè)隨機(jī)的地址,從而減少?zèng)_突。 導(dǎo)語(yǔ):本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之?dāng)?shù)據(jù)結(jié)構(gòu)篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門(mén)Python的朋友們可以來(lái)一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、掌握常見(jiàn)的字典創(chuàng)建,查詢,判別方法;2、了解字典中的defa...
摘要:小結(jié)實(shí)現(xiàn)了字典和哈希表感覺(jué)沒(méi)有想象中那么困難,當(dāng)然這還是開(kāi)始。 本系列所有文章:第一篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之棧與隊(duì)列第二篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之鏈表第三篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之集合第四篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之字典和散列表第五篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之二叉搜索樹(shù) 字典 不是新華字典哦,這里的字典也稱作_映射_,是一種數(shù)據(jù)結(jié)構(gòu),跟set集合很相似的一種數(shù)據(jù)結(jié)構(gòu),都可以用來(lái)...
摘要:基本版的散列表實(shí)現(xiàn)在散列表中我們通過(guò)散列函數(shù)來(lái)確定鍵值對(duì)的關(guān)系。的實(shí)現(xiàn)具體看的數(shù)據(jù)結(jié)構(gòu)與算法一。散列函數(shù)不超過(guò)數(shù)組的長(zhǎng)度下面兩個(gè)值相同源碼地址的數(shù)據(jù)結(jié)構(gòu)與算法二源碼 1集合 1.1集合的實(shí)現(xiàn) 集合是由一組無(wú)序且唯一(即不能重復(fù))的項(xiàng)組成的。這個(gè)數(shù)據(jù)結(jié)構(gòu)使用了與有限集合相同 的數(shù)學(xué)概念,但應(yīng)用在計(jì)算機(jī)科學(xué)的數(shù)據(jù)結(jié)構(gòu)中。 集合中常用方法列表: add(value):向集合中添加一個(gè)新的...
摘要:什么是散列表和散列函數(shù)哈希表,也叫散列表,是根據(jù)關(guān)鍵碼值而直接進(jìn)行訪問(wèn)的數(shù)據(jù)結(jié)構(gòu)。根據(jù)鍵值從散列表中移除值。請(qǐng)實(shí)現(xiàn)散列表將和存在一個(gè)對(duì)象中即可定義一個(gè)包含和屬性的類并分配到散列表。 showImg(https://segmentfault.com/img/remote/1460000019005270); 這是第五周的練習(xí)題,上周忘記發(fā)啦,這周是復(fù)習(xí) Dictionary 和 Hash...
摘要:什么是散列表和散列函數(shù)哈希表,也叫散列表,是根據(jù)關(guān)鍵碼值而直接進(jìn)行訪問(wèn)的數(shù)據(jù)結(jié)構(gòu)。將字典的所有鍵名以數(shù)組的形式返回。根據(jù)鍵值從散列表中移除值。這是第五周的練習(xí)題,上周忘記發(fā)啦,這周是復(fù)習(xí) Dictionary 和 HashTable。 下面是之前分享的鏈接: 1.每周一練 之 數(shù)據(jù)結(jié)構(gòu)與算法(Stack) 2.每周一練 之 數(shù)據(jù)結(jié)構(gòu)與算法(LinkedList) 3.每周一練 之 數(shù)據(jù)結(jié)構(gòu)...
閱讀 3600·2021-10-15 09:43
閱讀 3515·2021-09-02 15:21
閱讀 2229·2021-08-11 11:23
閱讀 3264·2019-08-30 15:54
閱讀 1959·2019-08-30 13:54
閱讀 3229·2019-08-29 18:35
閱讀 699·2019-08-29 16:58
閱讀 1783·2019-08-29 12:49