欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python?哈希表的實(shí)現(xiàn)——字典詳解

 更新時(shí)間:2023年11月25日 09:18:49   作者:edisonfish  
這篇文章主要介紹了Python?哈希表的實(shí)現(xiàn)——字典,那么今天我們就來看看哈希表的原理以及如何實(shí)現(xiàn)一個(gè)簡易版的?Python?哈希表,需要的朋友可以參考下

接觸過 Python 的小伙伴應(yīng)該對【字典】這一數(shù)據(jù)類型都了解吧

雖然 Python 沒有顯式名稱為“哈希表”的內(nèi)置數(shù)據(jù)結(jié)構(gòu),但是字典是哈希表實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)

在 Python 中,字典的鍵(key)被哈希,哈希值決定了鍵對應(yīng)的值(value)在字典底層數(shù)據(jù)存儲中的位置

那么今天我們就來看看哈希表的原理以及如何實(shí)現(xiàn)一個(gè)簡易版的 Python 哈希表

ps:文中提到的 Python 指的是 CPyhton 實(shí)現(xiàn)

何為哈希表?

哈希表(hash table)通常是基于“鍵-值對”存儲數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)

哈希表的鍵(key)通過哈希函數(shù)轉(zhuǎn)換為哈希值(hash value),這個(gè)哈希值決定了數(shù)據(jù)在數(shù)組中的位置。這種設(shè)計(jì)使得數(shù)據(jù)檢索變得非???/p>

舉個(gè)例子,下面有一組鍵值對數(shù)據(jù),其中歌手姓名是 key,歌名是 value

+------------------------------+
|   Key        |   Value       |
+------------------------------+
| Kanye        | Come to life  |
| XXXtentacion | Moonlight     |
| J.cole       | All My Life   |
| Lil wanye    | Mona Lisa     |
| Juice WRLD   | Come & Go     |
+------------------------------+

如果我們想要將這些鍵值對存儲在哈希表中,首先需要將鍵的值轉(zhuǎn)換成哈希表的數(shù)組的索引,這時(shí)候就需要用到哈希函數(shù)了

哈希函數(shù)是哈希表實(shí)現(xiàn)的主要關(guān)鍵,它能夠處理鍵然后返回存放數(shù)據(jù)的哈希表中對應(yīng)的索引

一個(gè)好的哈希函數(shù)能夠在數(shù)組中均勻地分布鍵,盡量避免哈希沖突(兩個(gè)鍵返回了相同的索引)

哈希函數(shù)是如何處理鍵的,這里我們創(chuàng)建一個(gè)簡易的哈希函數(shù)來模擬一下(實(shí)際上哈希函數(shù)要比這復(fù)雜得多)

def simple_hash(key, size):
    return ord(key[0]) % size

這個(gè)簡易版哈希函數(shù)將歌手名(即 key)首字母的 ASCII 值與哈希表大小取余,得出來的值就是歌名(value)在哈希表中的索引

那這個(gè)簡易版哈希函數(shù)有什么問題呢?聰明的你一眼就看出來了:容易出現(xiàn)碰撞。因?yàn)椴煌逆I的首字母有可能是一樣的,就意味著返回的索引也是一樣的

例如我們假設(shè)哈希表的大小為 10 ,我們以上面的歌手名作為鍵然后執(zhí)行 simple_hash(key, 10) 得到索引

可以看到,由于Juice WRLDJ.cole 的首字母都一樣,哈希函數(shù)返回了相同的索引,這里就發(fā)生了哈希碰撞

雖然幾乎不可能完全避免任何大量數(shù)據(jù)的碰撞,但一個(gè)好的哈希函數(shù)加上一個(gè)適當(dāng)大小的哈希表將減少碰撞的機(jī)會

當(dāng)出現(xiàn)哈希碰撞時(shí),可以使用不同的方法(例如開放尋址法)來解決碰撞

應(yīng)該設(shè)計(jì)健壯的哈希函數(shù)來盡量避免哈希碰撞

我們再來看其他的鍵,Kanye 通過 simple_hash() 函數(shù)返回 index 5,這意味著我們可以在索引 5 (哈希表的第六個(gè)元素)上找到 其鍵 Kanye 和值Come to life

哈希表優(yōu)點(diǎn)

在哈希表中,是根據(jù)哈希值(即索引)來尋找數(shù)據(jù),所以可以快速定位到數(shù)據(jù)在哈希表中的位置,使得檢索、插入和刪除操作具有常數(shù)時(shí)間復(fù)雜度 O(1) 的性能

與其他數(shù)據(jù)結(jié)構(gòu)相比,哈希表因其效率而脫穎而出

不但如此,哈希表可以存儲不同類型的鍵值對,還可以動態(tài)調(diào)整自身大小

Python 中的哈希表實(shí)現(xiàn)

在 Python 中有一個(gè)內(nèi)置的數(shù)據(jù)結(jié)構(gòu),它實(shí)現(xiàn)了哈希表的功能,稱為字典

Python 字典(dictionary,dict)是一種無序的、可變的集合(collections),它的元素以 “鍵值對(key-value)”的形式存儲

字典中的 key 是唯一且不可變的,這意味著它們一旦設(shè)置就無法更改

my_dict = {"Kanye": "Come to life", "XXXtentacion": "Moonlight", "J.cole": "All My Life"}

在底層,Python 的字典以哈希表的形式運(yùn)行,當(dāng)我們創(chuàng)建字典并添加鍵值對時(shí),Python 會將哈希函數(shù)作用于鍵,從而生成哈希值,接著哈希值決定對應(yīng)的值將存儲在內(nèi)存的哪個(gè)位置中

所以當(dāng)你想要檢索值時(shí),Python 就會對鍵進(jìn)行哈希,從而快速引導(dǎo) Python 找到值的存儲位置,而無需考慮字典的大小

my_dict = {}
my_dict["Kanye"] = "Come to life" # 哈希函數(shù)決定了 Come to life" 在內(nèi)存中的位置
print(my_dict["Alice"]) # "Come to life" 

可以看到,我們通過方括號[key]來訪問鍵對應(yīng)的值,如果鍵不存在,則會報(bào)錯(cuò)

print(my_dict["Kanye"])  # "Come to life" 
# Raises KeyError: "Drake"
print(my_dict["Drake"])

為了避免該報(bào)錯(cuò),我們可以使用字典內(nèi)置的 get() 方法,如果鍵不存在則返回默認(rèn)值

print(my_dict.get('Drake', "Unknown")) # Unknown

在 python 中實(shí)現(xiàn)哈希表

首先我們定義一個(gè) HashTable 類,表示一個(gè)哈希表數(shù)據(jù)結(jié)構(gòu)

class HashTable:
    def __init__(self, size):
        self.size = size
        self.table = [None]*size
    def _hash(self, key):
        return ord(key[0]) % self.size

在構(gòu)造函數(shù) __init__() 中:

  • size 表示哈希表的大小
  • table是一個(gè)長度為 size 的數(shù)組,被用作哈希表的存儲結(jié)構(gòu)。初始化時(shí),數(shù)組的所有元素都被設(shè)為 None,表示哈希表初始時(shí)不含任何數(shù)據(jù)

在內(nèi)部函數(shù) _hash() 中,用于計(jì)算給定 key 的哈希值。它采用給定鍵 key 的第一個(gè)字符的 ASCII 值,并使用取余運(yùn)算 % 將其映射到哈希表的索引范圍內(nèi),以便確定鍵在哈希表中的存儲位置。

然后我們接著在 HashTable 類中添加對鍵值對的增刪查方法

class HashTable:
    def __init__(self, size):
        self.size = size
        self.table = [None]*size
    def _hash(self, key):
        return ord(key[0]) % self.size
    def set(self, key, value):
        hash_index = self._hash(key)
        self.table[hash_index] = (key, value)
    def get(self, key):
        hash_index = self._hash(key)
        if self.table[hash_index] is not None:
            return self.table[hash_index][1]
        raise KeyError(f'Key {key} not found')
    def remove(self, key):
        hash_index = self._hash(key)
        if self.table[hash_index] is not None:
            self.table[hash_index] = None
        else:
            raise KeyError(f'Key {key} not found')

其中,set() 方法將鍵值對添加到表中,而 get() 該方法則通過其鍵檢索值。該 remove() 方法從哈希表中刪除鍵值對

現(xiàn)在,我們可以創(chuàng)建一個(gè)哈希表并使用它來存儲和檢索數(shù)據(jù):

# 創(chuàng)建哈希表
hash_table = HashTable(10)
# 添加鍵值對
hash_table.set('Kanye', 'Come to life')
hash_table.set('XXXtentacion', 'Moonlight')
# 獲取值
print(hash_table.get('XXXtentacion'))  # Outputs: 'Moonlight'
# 刪除鍵值對
hash_table.remove('XXXtentacion')
# 報(bào)錯(cuò): KeyError: 'Key XXXtentacion not found'
print(hash_table.get('XXXtentacion'))

前面我們提到過,哈希碰撞是使用哈希表時(shí)不可避免的一部分,既然 Python 字典是哈希表的實(shí)現(xiàn),所以也需要相應(yīng)的方法來處理哈希碰撞

在 Python 的哈希表實(shí)現(xiàn)中,為了避免哈希沖突,通常會使用開放尋址法的變體之一,稱為“線性探測”(Linear Probing)

當(dāng)在字典中發(fā)生哈希沖突時(shí),Python 會使用線性探測,即從哈希沖突的位置開始,依次往后查找下一個(gè)可用的插槽(空槽),直到找到一個(gè)空的插槽來存儲要插入的鍵值對。

這種方法簡單直接,可以減少哈希沖突的次數(shù)。但是,它可能會導(dǎo)致“聚集”(Clustering)問題,即一旦哈希表中形成了一片連續(xù)的已被占用的位置,新元素可能會被迫放入這片區(qū)域,導(dǎo)致哈希表性能下降

為了緩解聚集問題,假若當(dāng)哈希表中存放的鍵值對超過哈希表長度的三分之二時(shí)(即裝載率超過66%時(shí)),哈希表會自動擴(kuò)容

最后總結(jié)一下:

  • 在哈希表中,是根據(jù)哈希值(即索引)來尋找數(shù)據(jù),所以可以快速定位到數(shù)據(jù)在哈希表中的位置
  • Python 的字典以哈希表的形式運(yùn)行,當(dāng)我們創(chuàng)建字典并添加鍵值對時(shí),Python 會將哈希函數(shù)作用于鍵,從而生成哈希值,接著哈希值決定對應(yīng)的值將存儲在內(nèi)存的哪個(gè)位置中
  • Python 通常會使用線性探測法來解決哈希沖突問題

到此這篇關(guān)于Python 哈希表的實(shí)現(xiàn)——字典的文章就介紹到這了,更多相關(guān)Python 哈希表字典內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解PyQt5?事件處理機(jī)制

    詳解PyQt5?事件處理機(jī)制

    PyQt為事件處理提供了兩種機(jī)制高級的信號與槽機(jī)制,以及低級的事件處理機(jī)制,這篇文章主要介紹了PyQt5?事件處理機(jī)制,需要的朋友可以參考下
    2022-11-11
  • python+opencv識別圖片中的圓形

    python+opencv識別圖片中的圓形

    這篇文章主要為大家詳細(xì)介紹了python+opencv識別圖片中的圓形 ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • PyTorch策略梯度算法詳情

    PyTorch策略梯度算法詳情

    這篇文章主要介紹了PyTorch策略梯度算法詳情,文章我們主要使用策略梯度算法解決CartPole問題,詳細(xì)的相關(guān)介紹,需要的朋友可以參考一下
    2022-07-07
  • Python version 2.7 required, which was not found in the registry

    Python version 2.7 required, which was not found in the regi

    這篇文章主要介紹了安裝PIL庫時(shí)提示錯(cuò)誤Python version 2.7 required, which was not found in the registry問題的解決方法,需要的朋友可以參考下
    2014-08-08
  • pycharm調(diào)試功能如何實(shí)現(xiàn)跳到循環(huán)的某一步

    pycharm調(diào)試功能如何實(shí)現(xiàn)跳到循環(huán)的某一步

    這篇文章主要介紹了pycharm調(diào)試功能如何實(shí)現(xiàn)跳到循環(huán)的某一步問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Python之os模塊案例詳解

    Python之os模塊案例詳解

    這篇文章主要介紹了Python之os模塊案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • python制作簡單計(jì)算器功能

    python制作簡單計(jì)算器功能

    這篇文章主要為大家詳細(xì)介紹了python制作簡單計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • python實(shí)現(xiàn)電子產(chǎn)品商店

    python實(shí)現(xiàn)電子產(chǎn)品商店

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)電子產(chǎn)品商店,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • 完美解決python3.7 pip升級 拒絕訪問問題

    完美解決python3.7 pip升級 拒絕訪問問題

    這篇文章主要介紹了python3.7 pip升級 拒絕訪問 解決方案,文中給大家提到了python中for循環(huán)問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-07-07
  • 淺談tensorflow與pytorch的相互轉(zhuǎn)換

    淺談tensorflow與pytorch的相互轉(zhuǎn)換

    本文主要介紹了簡單介紹一下tensorflow與pytorch的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評論