哈希表与哈希扩容

一,哈希表

哈希表简单的理解:在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。 

哈希表基于数组的,正因为数组创建后难于扩展某些哈希表被基本填满时,性能下降得非常严重,所以程序虽必须要清楚表中将要存储多少数据(或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程)

如何定位数据存储的位置呢?

h(key) = key % size

1.线性哈希表

线性哈希表可以认为就是数组,不过他对数据的存储方式不如线性表一般按顺序来,他是通过某种算法来计算得到数据下标值的。可以想象如果数据比较多,那么重下标的情况会很多,所以就有了哈希冲突。

代码实现

class Array():def __init__(self,size):self.__size = sizeself.__item = [None]*sizeself.__length = 0def __setitem__(self,key,value):self.__item[key] = valueself.__length += 1def __getitem__(self, index):return self.__item[index]def __len__(self):return self.__lengthdef __iter__(self):for value in self.__item:yield valueclass Slot():def __init__(self,key,value):self.key = keyself.value = valuedef __str__(self):return 'key:{}  value:{}'.format(self.key,self.value)class HashTable():def __init__(self):self.size = 4self.items = Array(self.size)def find_index_to_insert(self,key):index = self.get_index(key)if self.items[index] == None:return indexelse:while self.items[index] is not None:if self.items[index].key == key:return indexelse:index = (5*index+1) % self.sizereturn indexdef find_key(self,key):index = self.get_index(key)if self.items[index] == None:return Noneelse:while self.items is not None:if key == self.items[index].key:return indexelse:index = (5*index+1) % self.sizereturn Nonedef get_index(self,key):return hash(key) % self.sizedef put(self, key, value):s = Slot(key, value)index = self.find_index_to_insert(key)self.items[index] = sdef get(self,key):index = self.get_index(key)return self.items[index]if __name__ == '__main__':h = HashTable()h.put('name','L')h.put('sex','M')h.put('age','18')h.put('occupation','general')print(h.get('name'))print(h.get('sex'))print(h.get('age'))print(h.get('occupation'))

2.链式哈希表

链式哈希表可以认为是数组,不过数组内的元素是链表,有种线性表嵌套链式表的既视感,者带来的好处就多了:不仅拥有了更好的空间利用率,同时解决了哈希冲突的问题:即使出现重下标的情况,我们也可以顺着往下加,之后顺着表一个一个找就可以了。

当然对链表的处理也可以改成双向链表,不过感觉没太大必要。 

代码实现

class Array():def __init__(self,size):self.__size = sizeself.__item = [None]*sizeself.__length = 0def __setitem__(self,key,value):self.__item[key] = valueself.__length += 1def __getitem__(self, index):return self.__item[index]def __len__(self):return self.__lengthdef __iter__(self):for value in self.__item:yield valueclass Slot():def __init__(self,key,value,next=None):self.key = keyself.value = valueself.next = nextdef __str__(self):return 'key:{}  value:{}'.format(self.key,self.value)class HashTable():def __init__(self):self.size = 4self.items = Array(self.size)def get_index(self,key):return hash(key) % self.sizedef put(self, key, value):s = Slot(key, value)index = self.get_index(key)if self.items[index] == None:self.items[index] = selse:if self.items[index].key == key:self.items[index].value = valueelse:temp = self.items[index]temp_next = self.items[index].nextwhile temp_next is not None:if temp_next.key == key:temp_next.value = valuereturnelse:temp = temp_nexttemp_next = temp.nexttemp.next = sdef get(self,key):index = self.get_index(key)if self.items[index]:if self.items[index].key == key:return self.items[index]else:temp_next = self.items[index].nextwhile temp_next is not None:if temp_next.key == key:return temp_nextelse:temp_next = temp_next.nextreturn Noneif __name__ == '__main__':h = HashTable()h.put('name','L')h.put('sex','M')h.put('age','18')h.put('occupation','general')print(h.get('name'))print(h.get('sex'))print(h.get('age'))print(h.get('occupation'))

二,哈希扩容

装载因子(load factor)

如果继续往我们的哈希表里塞东西会发生什么?空间不够用。这里我们定义一个负载因子的概念(load factor),其实很简单,就是已经使用的槽数比哈希表大小。 比如我们上边的例子插入了 8 个元素,哈希表总大小是 13, 它的 load factor 就是 $ 8/13 \approx 0.62 $。当我们继续往哈希表插入数据的时候,很快就不够用了。 通常当负载因子开始超过 0.8 的时候,就要新开辟空间并且重新进行散列了。

重哈希(Rehashing)

当负载因子超过 0.8 的时候,需要进行 rehashing 操作了。步骤就是重新开辟一块新的空间,开多大呢?感兴趣的话可以看下 cpython 的 dictobject.c 文件然后搜索 GROWTH_RATE 这个关键字,你会发现不同版本的 cpython 使用了不同的策略。python3.3 的策略是扩大为已经使用的槽数目的两倍。开辟了新空间以后,会把原来哈希表里 不为空槽的数据重新插入到新的哈希表里,插入方式和之前一样。这就是 rehashing 操作。

代码实现

class Array():def __init__(self,size):self.__size = sizeself.__item = [None]*sizeself.__length = 0def __setitem__(self,key,value):self.__item[key] = valueself.__length += 1def __getitem__(self, index):return self.__item[index]def __len__(self):return self.__lengthdef __iter__(self):for value in self.__item:yield valueclass Slot():def __init__(self,key,value):self.key = keyself.value = valuedef __str__(self):return 'key:{}  value:{}'.format(self.key,self.value)class HashTable():def __init__(self):self.size = 4self.length = 0self.items = Array(self.size)def find_index_to_insert(self,key):index = self.get_index(key)if self.items[index] == None:return indexelse:while self.items[index] is not None:if self.items[index].key == key:return indexelse:index = (5*index+1) % self.sizereturn indexdef find_key(self,key):index = self.get_index(key)if self.items[index] == None:return Noneelse:while self.items is not None:if key == self.items[index].key:return indexelse:index = (5*index+1) % self.sizereturn Nonedef get_index(self,key):return hash(key) % self.sizedef put(self, key, value):s = Slot(key, value)index = self.find_index_to_insert(key)self.items[index] = sself.length += 1if self.load_factor():self.rehashing()def load_factor(self):return self.length / float(self.size) > 0.8def rehashing(self):self.length = 0old = self.itemsself.size = self.size << 1self.items = Array(self.size)for s in old:if s:key = s.keyindex = self.find_index_to_insert(key)self.items[index] = sself.length += 1def get(self,key):index = self.get_index(key)return self.items[index]if __name__ == '__main__':h = HashTable()h.put('name', 'L')h.put('sex', 'M')h.put('age', '18')h.put('occupation', 'general')h.put('occupation1', 'general')h.put('occupation2', 'general')h.put('occupation3', 'general')h.put('occupation5', 'general')h.put('occupation6', 'general')print(h.get('name'))print(h.get('sex'))print(h.get('age'))print(h.get('occupation'))print(h.get('occupation1'))print(h.get('occupation2'))print(h.get('occupation3'))print(h.get('occupation5'))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/25720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JS类型转换面试题:[] == ![] 为true?

前言 OK,又是在学习的路上遇到了难点&#xff0c;今天拿来分享一哈。ok&#xff0c;话不多说&#xff0c;开始分享。 下面是一道面试题 console.log([]![])你觉得上面的值打印为多少&#xff1f;我告诉你&#xff0c;打印的结果是true。如果你是猜对的或者不会可以看看我对这…

Python从入门到精通的学习路径

Python从入门到精通的学习路径 基础语法&#xff1a; 学习Python的基本语法&#xff0c;包括变量、数据类型、运算符、流程控制&#xff08;如if、else、for、while&#xff09;等。参考书籍或在线教程&#xff0c;如《Python从入门到精通》系列教程&#xff0c;特别是“Pytho…

JVM学习笔记02

三十九、运行时数据区内部数据

Capture One 23 软件安装教程、附安装包下载

Capture One Capture One 23 是一款功能极为全面的图片处理软件&#xff0c;为用户提供了真正的逼真色彩处理和无缝衔接的编辑体验&#xff0c;以及业界最快的联机拍摄功能&#xff0c;可以满足用户在图像创作上的所有功能&#xff0c;如创作全景拼接大图、高级色彩调整、遮罩…

0605-JavaSE-单例模式-饿懒汉模式

​​​​​​​ 不能放在方法里面&#xff08;因为每个线程调用都会在方法里面实例化一个locker对象&#xff0c;但不属于同一个对象&#xff09;&#xff0c;然后要用static修饰成静态变量才会起到效果 //单例设计模式 //饿汉模式&#xff1a;在加载类的时候就已经开始创建 /…

Python项目开发实战:智能停车场车牌识别计费系统(案例教程)

开发一个智能停车场车牌识别计费系统是一个综合了多个技术领域(如图像处理、数据库管理、Web开发等)的项目。 一、项目概述 1.项目目标: 实现车牌识别功能。 设计并实现计费逻辑。 构建用户友好的前端界面。 实现后台管理系统。 2.技术栈: 后端:Python(Django/Flask等…

Opencv基本操作

Opencv基本操作 导入并使用opencv进行图像与视频的基本处理 opencv读取的格式是BGR import cv2 #opencv读取的格式是BGR import numpy import matplotlib.pyplot as plt %matplotlib inline图像读取 通过cv2.imread()来加载指定位置的图像信息。 img cv2.imread(./res/ca…

3-哈希表-51-四数相加 II-LeetCode454

3-哈希表-51-四数相加 II-LeetCode454 LeetCode: 题目序号454 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&#xff…

定时TH1、计数TL1 的计算

定时器模式 通常在模式 1 下&#xff0c;定时器 1 是 16 位定时器&#xff08;2的16次方65536&#xff09;&#xff08;8位256&#xff09;。定时器的计时周期是由 TH1 和 TL1 的组合值决定的。初始值为 65536 − ( T H 1 256 T L 1 ) 65536 - (TH1 \times 256 TL1) 65536…

Spring boot注解学习

1、SpringBootApplication spring boot 核心注解&#xff0c;加在Spring boot 主类之上&#xff0c;是Configuration、EnableAutoConfiguration、ComponentScan 注解的集合。  &#xff08;1&#xff09;Configuration&#xff1a;允许以Bean注解将对象托管给spring容器&#…

基本表的定义:创建表、修改表、删除表

一、创建数据库与打开数据库 学生选课数据库 学生&#xff08;学号&#xff0c;姓名&#xff0c;性别&#xff0c;出生时间&#xff0c;所在系&#xff09; 课程&#xff08;课程编号&#xff0c;课程名&#xff0c;先修课程号&#xff09; 选课&#xff08;学号&#xff0…

Java File IO

Java File IO ~主要介绍四个类 InputStream OutputStream FileReader FileWriter~ InputStream &#xff08;字节流读取File&#xff09; public static void main(String[] args) throws IOException {String filePath "D:\\Javaideaporject\\JavaBaseSolid8\\File\\t…

js调试过程中修改变量值

1.在想要变更的地方添加断点 2.添加监视表达式 3.执行网页代码&#xff0c;当执行到断点处则会停止 4.点击执行下一步&#xff0c;则会执行监视表达式

19、关于加强行政事业单位数据资产管理的通知

党中央有关部门,国务院各部委、各直属机构,全国人大常委会办公厅,全国政协办公厅,最高人民法院,最高人民检察院,各民主党派中央,有关人民团体,各省、自治区、直辖市、计划单列市财政厅(局),新疆生产建设兵团财政局,有关中央管理企业: 为贯彻落实《中共中央 国务…

Linux下打印封装_统计函数执行时间_线程号时间戳打印

统计函数执行时间&#xff08;多线程环境下统计结果不准&#xff09; // 无返回值 #define FUNC_EXEC_TIME_NORET(fun,promote) ({ \ unsigned long long timeDelta 0; \ struct timespec t1 {0}; \ struct timespec t2 {0}; \ clock_gettime(CLOCK_MONOTONIC, &t1); \ …

web3规则改变者:Linea的厉害之处

Linea 的厉害之处 想象一下&#xff0c;Linea 就像是一条神奇的高速公路&#xff0c;它让开车&#xff08;在这里指的是交易&#xff09;变得更快、更便宜&#xff0c;而且还很舒服。Linea 是由一个叫 Consensys 的大公司建造的&#xff0c;它用了一些超级酷的技术&#xff0c…

托盘图标结构体TBBUTTON和TRAYDATA相关说明文章记录

1、托盘图标管理器与跨进程SendMessage &#xff1a;http://www.qingfengju.com/article.asp?id294 2、TrayData 结构详解&#xff1a;http://llll123cccc.blog.163.com/blog/static/316586420105864647151/ 3、Shell Tray Info - Arrange your system tray icons&#xff1…

高考分数查询结果自动推送至微信(卷II)

祝各位端午节安康&#xff01;只要心中无结&#xff0c;每天都是节&#xff0c;开心最重要&#xff01; 在上一篇文章高考分数查询结果自动推送至微信&#xff08;卷Ⅰ&#xff09;-CSDN博客中谈了思路&#xff0c;今天具体实现。文中将敏感信息已做处理&#xff0c;读者根据自…

从零开始精通Onvif之获取设备信息

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 与设备交互的第一步 发现设备之后&#xff0c;与设备进行交互的第一步&#xff0c;是连接上设备&#xff0c;并获取设备的信息。连接设备&#…

FiRa标准之认证流程

在实现FiRa MAC时需要考虑其兼容性&#xff0c;同时对外部而言&#xff0c;如何证明一个UWB设备是否满足FiRa的规范要求&#xff0c;就需要通过一定的组织对相应的设备进行检测、认证。 为此&#xff0c;FiRa联盟已经建立了国际认证程序&#xff0c;制定了验证待检设备&#x…