哈希表的原理及實現代碼

哈希表能夠表述爲,是一種能夠根據關鍵字快速查詢數據的數據結構python

一. 哈希表有哪些優勢?

不論哈希表中數據有多少,增長,刪除,改寫數據的複雜度平均都是O(1),效率很是高數組

二. 實現哈希表

1. 哈希表原理數據結構

若是說每個數據它都對應着一個固定的位置,那咱們查找特定一個數據時,就能夠直接查看這個數據對應的位置是否存在數據。一個形象的例子就是學生在教室中的位置,開學的時候,老師會給學生每個人分配一個位置,並且不容許學生隨便亂坐位置,之後老師要查看今天李剛同窗有沒有上課,直接看李剛同窗的位置是否是有人就能夠判斷,不必點了全班同窗的名才能夠知道李剛同窗來了沒有。函數

2. 實現簡單的哈希表spa

根據上面的原理,首先,咱們要分配一片空間用來存儲咱們數據,好比是一個空的數組code

而後,有數據存進來的時候,按照特定規則得出這個數據在數組中的位置,將數據存進這個位置blog

咱們就以存進一個整型數據爲例,特定規則就是取餘get

根據計算出來的值,將這些數據放入對應的位置,咱們的數組變爲hash

咱們已經把數據插入到了哈希表中,如今,咱們要查找一個數據,只要按照取餘規則計算出這個數據在數組中對應的位置,而後查看數組的這個位置,就能夠取出這個數據了,好比咱們要從哈希表中取出52,根據取餘規則,52的計算出來的位置是8,數組中8這個位置是空的,52不在哈希表中,找不到52的數據;從哈希表中取出77,77計算出來的位置是0,數組中0這個位置有值,並且值就是77,從哈希表中取出77的值。it

至此,咱們知道實現了一個很簡單的哈希表的原理,其實還存在不少問題,這個咱們接下來討論,這兒先把咱們前面的一些概念用專業的術語替換一下,前面咱們所說的特定規則,咱們稱之爲哈希函數,用特定股則計算出來的值稱之爲哈希值。

3. 還存在哪些問題?

  1. 有可能兩個數據經過哈希函數計算出來的哈希值有可能相等,好比77,88計算出來的位置值都是0

  2. 若是哈希表滿了,該怎麼擴容

第一個問題就是如何解決這種衝突

有開放定址法,鏈定址法,咱們說一下開放定址法,就是將這個衝突的數據再從新計算一個空的位置,將其存進去,好比咱們要存放88,哈希值是0,數組這個位置已經有值了,那咱們再獲取一個哈希值,好比在原哈希值的基礎上加1,獲得1,1的位置是空,我將88放進去。有人會問,1這個位置被佔了,那下一個數據是1這個位置怎麼辦,這時候,咱們仍是一樣的作法,給這個數據再計算一個哈希值。

插入88後的數組變爲

 

衝突解決了,但咱們讀取數據的時候,好像又出現問題了,88的哈希值是0,發現數組0位置不是空的,那咱們肯定88在哈希表中?確定不行,0這個位置存儲的是77,不是88。咱們的解決方法是判斷0這個位置的值是否是88,不是的話,再計算88的哈希值是1,判斷是1這個位置是否爲空,爲空,則88不在哈希表中;不爲空,判斷值是否爲88,如果88,肯定在哈希表中;若是值不是88,咱們則繼續計算哈希值是2,依次下去,直到找到88或者值爲空的位置。

第二個問題,哈希表擴容

一個簡單的解決辦法是,當插入數據時,發現全部的位置都滿了,咱們就再分配一個大於原先空間的一片空間,把原來空間中的值從新哈希到新的空間中。

4. 哈希表的python實現

python中的字典就是哈希表,下面代碼實現了一個簡單的字典

class Dict:
    def __init__(self, size=10):
        self.size = size
        self.key = [None] * self.size
        self.data = [None] * self.size

    def __setitem__(self, key, value):
        assert isinstance(key, int)
        index = self.hash(key)
        if not self.key[index]:
            self.key[index] = key
            self.data[index] = value
        elif self.key[index] == key:
            self.data[index] = value
        else:
            start = index
            while self.key[index] and self.key[index] != key:
                index = self.re_hash(index)
                if index == start:
                    raise Exception('dict is full')

            if self.key[index]:
                self.data[index] = value
            else:
                self.key[index] = key
                self.data[index] = value

    def __getitem__(self, item):
        assert isinstance(item, int)
        index = self.hash(item)
        if not self.key[index]:
            raise KeyError(item)
        else:
            if self.key[index] == item:
                return self.data[index]
            else:
                start = index
                while self.key[index] and self.key[index] != item:
                    index = self.re_hash(index)
                    if start == index:
                        raise KeyError(item)

                if self.key[index] == item:
                    return self.data[index]
                else:
                    raise KeyError(item)

    def __contains__(self, item):
        assert isinstance(item, int)
        index = self.hash(item)
        if not self.key[index]:
            return False
        else:
            if self.key[index] == item:
                return True
            else:
                start = index
                while self.key[index] and self.key[index] != item:
                    index = self.re_hash(index)
                    if start == index:
                        break

                if self.key[index] == item:
                    return True
                else:
                    return False

    def hash(self, key):
        index = key % self.size
        return int(index)

    def re_hash(self, index):
        return index+1


a = Dict()
a[1]='3'
a[2]='4'
print(a[5])

 

三. 總結:

哈希表對於數據的插入,刪除,更新操做複雜的平均是O(1),效率很是高,若是不關心數據的存儲順序,咱們能夠選取這種數據結構。

相關文章
相關標籤/搜索