python 哈希表实现简单python字典代码实例


Posted in Python onSeptember 27, 2019

这篇文章主要介绍了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, key, 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, key, 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, key, 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)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python实现HTTP协议下的文件下载方法总结
Apr 20 Python
python 链接和操作 memcache方法
Mar 04 Python
Django自定义认证方式用法示例
Jun 23 Python
python使用super()出现错误解决办法
Aug 14 Python
Python实现基于TCP UDP协议的IPv4 IPv6模式客户端和服务端功能示例
Mar 22 Python
Python3.6实现连接mysql或mariadb的方法分析
May 18 Python
Django框架中间件(Middleware)用法实例分析
May 24 Python
Pandas库之DataFrame使用的学习笔记
Jun 21 Python
对numpy下的轴交换transpose和swapaxes的示例解读
Jun 26 Python
利用python实现PSO算法优化二元函数
Nov 13 Python
python中xlutils库用法浅析
Dec 29 Python
python和C/C++混合编程之使用ctypes调用 C/C++的dll
Apr 29 Python
python实现发送form-data数据的方法详解
Sep 27 #Python
PyCharm更改字体和界面样式的方法步骤
Sep 27 #Python
Pycharm 字体大小调整设置的方法实现
Sep 27 #Python
python3 写一个WAV音频文件播放器的代码
Sep 27 #Python
简单瞅瞅Python vars()内置函数的实现
Sep 27 #Python
Python 获取项目根路径的代码
Sep 27 #Python
Python Pandas对缺失值的处理方法
Sep 27 #Python
You might like
PHP中__FILE__、dirname与basename用法实例分析
2014/12/01 PHP
浅谈php处理后端&接口访问超时的解决方法
2016/10/29 PHP
ajax+php实现无刷新验证手机号的实例
2017/12/22 PHP
PHP7新增函数
2021/03/09 PHP
JS控件autocomplete 0.11演示及下载 1月5日已更新
2007/01/09 Javascript
JavaScript 中的日期和时间及表示标准介绍
2013/08/21 Javascript
JQuery性能优化的几点建议
2014/05/14 Javascript
jQuery绑定事件不执行但alert后可以正常执行
2014/06/03 Javascript
jQuery简单操作cookie的插件实例
2016/01/13 Javascript
jquery实现简单Tab切换菜单效果
2020/07/17 Javascript
NodeJS如何实现同步的方法示例
2018/08/24 NodeJs
vue3.0 CLI - 2.6 - 组件的复用入门教程
2018/09/14 Javascript
详解如何解决vue开发请求数据跨域的问题(基于浏览器的配置解决)
2018/11/12 Javascript
LayUI动态设置checkbox不显示的解决方法
2019/09/02 Javascript
[47:06]DOTA2上海特级锦标赛主赛事日 - 4 败者组第五轮 MVP.Phx VS EG第一局
2016/03/05 DOTA
[01:00:30]完美世界DOTA2联赛循环赛 Inki vs Matador BO2第二场 10.31
2020/11/02 DOTA
python通过ElementTree操作XML获取结点读取属性美化XML
2013/12/02 Python
Python的另外几种语言实现
2015/01/29 Python
Python实现Linux命令xxd -i功能
2016/03/06 Python
Python中字符串的格式化方法小结
2016/05/03 Python
Python处理CSV与List的转换方法
2018/04/19 Python
对YOLOv3模型调用时候的python接口详解
2019/08/26 Python
使用python客户端访问impala的操作方式
2020/03/28 Python
Python使用urlretrieve实现直接远程下载图片的示例代码
2020/08/17 Python
详解CSS3中nth-child与nth-of-type的区别
2017/01/05 HTML / CSS
英国泰坦旅游网站:全球陪同游览,邮轮和铁路旅行
2016/11/29 全球购物
波兰香水和化妆品购物网站:Notino.pl
2017/11/07 全球购物
SNIDEL官网:日本VIVI杂志人气少女第一品牌
2020/03/12 全球购物
求最大连续递增数字串(如"ads3sl456789DF3456ld345AA"中的"456789")
2015/09/11 面试题
怎样写好创业计划书的内容
2014/02/06 职场文书
公司成本主管岗位责任制
2014/02/21 职场文书
学生期末评语大全
2014/04/30 职场文书
乡镇民主生活会发言材料
2014/10/20 职场文书
人事专员岗位职责
2015/02/03 职场文书
Vue+Flask实现图片传输功能
2022/04/01 Vue.js
MySQL数据库优化之通过索引解决SQL性能问题
2022/04/10 MySQL