1. 程式人生 > 程式設計 >python 雜湊表實現簡單python字典程式碼例項

python 雜湊表實現簡單python字典程式碼例項

這篇文章主要介紹了python 雜湊表實現簡單python字典程式碼例項,文中通過示例程式碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

class Array(object):
  def __init__(self,size = 32,init = None):
    self._size = size
    self._items = [init] * size
  def __getitem__(self,index):
    return self._items[index]
  def __setitem__(self,index,value):
    self._items[index] = value
  def __len__(self):
    return self._size
  def clear(self,value = None):
    for i in range(self,_items):
      self._items[i] = value
  def __iter__(self):
    for item in self._items:
      yield item
class Slot(object):
  """
  定義一個雜湊表陣列的槽
  注意:一個槽有三種狀態
  1. 從未被使用過,HashMap.UNUSED。 此槽沒有被使用和衝突過,查詢時只要找到UNUSED 就不用再繼續探查了
  2. 使用過但是remove了, 此時是HashMap.EMPTY,該談差點後面的元素仍可能是有key
  3. 槽正在使用Slot 節點
  """
  def __init__(self,key,value):
    self.key = key
    self.value = value
class HashTable(object):
  UNUSED = None # 表示slot 沒有被使用過
  EMPTY = Slot(None,None) # 使用過被刪除
  def __init__(self):
    self._table = Array(8,init = HashTable.UNUSED) # 初始化,陣列的每個元素都是UNUSED
    self.length = 0
  @property # 內建裝飾器,把方法變成屬性
  def _load_factor(self):
    return self.length/float(len(self._table))
  def __len__(self):
    return self.length
  def _hash(self,key):
    return abs(hash(key)) % len(self._table) # abs函式返回絕對值 hash 是內建函式 _hash 直接使用內建的雜湊函式,對陣列的長度取模
  def _find_key(self,key):
    index = self._hash(key) # 先用 _hash方法計算出槽的位置
    _len = len(self._table) # 現儲存下來長度
    while self._table[index] is not HashTable.UNUSED:  # 如果這個槽不是沒有被使用過
      if self._table[index] is HashTable.EMPTY: # 如果這個槽是,曾經有過值,不過被刪除了
        index = (index*5 +1 ) % _len    # cpython 使用的一種解決雜湊衝突的方式
        continue
      elif self._table[index].key == key: # 正在使用, 如果key值相同
        return index
      else: # 這裡就只剩最後一種可能, 正在使用,但是key沒有找到
        index = (index *5 +1) % _len
    return None
  def _slot_can_insert(self,index): # 判斷一個槽是否可以插入
    return (self._table[index] is HashTable.EMPTY or self._table[index] is HashTable.UNUSED)
  def _find_slot_for_insert(self,key):  # 尋找一個空槽,用來插入
    index = self._hash(key)
    _len = len(self._table)
    while not self._slot_can_insert(index):
      index = (index*5 + 1) % _len
    return index
  def __contains__(self,key):   # 實現一個in操作符
    index = self._find_key(key)
    return index is not None
  def add(self,value):
    if key in self:  # 上面實現的in操作符
      index = self._find_key(key)
      self._table[index].value = value
      return False  # 返回False 表示沒有執行插入操作,執行的是更新操作
    else:
      index = self._find_slot_for_insert(key)
      self._table[index] = Slot(key,value) # 這兩部可能會呼叫_slot_can_insert 函式,不管是哪種情況,EMPTY 或 是 UNUSEZD,都將這個節點宣告為Slot類
      self.length += 1
      if self._load_factor >= 0.8:
        self._rehash()   # 當空間佔用大於0.8 的時候,進行rehash 重新分配空間。
      return True
  def _rehash(self):
    old_table = self._table
    newsize = len(self._table) *2
    self._table = Array(newsize,HashTable.UNUSED)
    self.length = 0
    for slot in old_table:
      if slot is not HashTable.UNUSED and slot is not HashTable.EMPTY:  # 判斷這個slot 是有值的
        index = self._find_slot_for_insert(slot.key)  # 找到一個可以插入的槽
        self._table[index] = slot
        self.length += 1
  def get(self,default = None):
    index = self._find_key(key)
    if index is None:
      return default
    else:
      return self._table[index].value
  def remove(self,key):
    index = self._find_key(key)
    if index is None:
      raise KeyError()
    value = self._table[index].value
    self.length -= 1
    self._table[index] = HashTable.EMPTY
    return value
  def __iter__(self):   # 遍歷操作,python 字典預設遍歷的是key,這裡實現的也是遍歷key
    for slot in self._table:
      if slot not in(HashTable.EMPTY,HashTable.UNUSED):
        yield slot.key
class DictADT(HashTable):

  def __setitem__(self,value):  # 設定給定鍵的值
    self.add(key,value)
  def __getitem__(self,key):   # 返回給定鍵的值
    if key not in self:
      raise KeyError()
    else:
      return self.get(key)
  def _iter_slot(self):
    for slot in self._table:
      if slot not in (HashTable.EMPTY,HashTable.UNUSED):
        yield slot
  def items(self):
    for slot in self._iter_slot():
      yield (slot.key,slot.value)
  def keys(self):
    for slot in self._iter_slot():
      yield slot.key
  def values(self):
    for slot in self._iter_slot():
      yield slot.value
def test_dict():
  import random
  d = DictADT()
  d['a'] = 1   # 這時候呼叫 __setitem__ 方法
  assert d['a'] == 1
  d.remove('a')
  l = list(range(30))
  random.suffle(l)  # 打亂l
  for i in l:
    d.add(i,i )
  for i in range(30):
    assert d.get(i) == i
  assert sorted (list(d.keys())) == sorted(l)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。