哈希表与哈希扩容

一,哈希表

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

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

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

h(key) = key % size

1.线性哈希表

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

代码实现

class Array():
    def __init__(self,size):
        self.__size = size
        self.__item = [None]*size
        self.__length = 0

    def __setitem__(self,key,value):
        self.__item[key] = value
        self.__length += 1

    def __getitem__(self, index):
        return self.__item[index]

    def __len__(self):
        return self.__length

    def __iter__(self):
        for value in self.__item:
            yield value

class Slot():
    def __init__(self,key,value):
        self.key = key
        self.value = value

    def __str__(self):
        return 'key:{}  value:{}'.format(self.key,self.value)


class HashTable():
    def __init__(self):
        self.size = 4
        self.items = Array(self.size)



    def find_index_to_insert(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return index
        else:
            while self.items[index] is not None:
                if self.items[index].key == key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return index

    def find_key(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return None
        else:
            while self.items is not None:
                if key == self.items[index].key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return None


    def get_index(self,key):
        return hash(key) % self.size

    def put(self, key, value):
        s = Slot(key, value)
        index = self.find_index_to_insert(key)
        self.items[index] = s


    def 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 = size
        self.__item = [None]*size
        self.__length = 0

    def __setitem__(self,key,value):
        self.__item[key] = value
        self.__length += 1

    def __getitem__(self, index):
        return self.__item[index]

    def __len__(self):
        return self.__length

    def __iter__(self):
        for value in self.__item:
            yield value

class Slot():
    def __init__(self,key,value,next=None):
        self.key = key
        self.value = value
        self.next = next

    def __str__(self):
        return 'key:{}  value:{}'.format(self.key,self.value)


class HashTable():
    def __init__(self):
        self.size = 4
        self.items = Array(self.size)


    def get_index(self,key):
        return hash(key) % self.size

    def put(self, key, value):
        s = Slot(key, value)
        index = self.get_index(key)
        if self.items[index] == None:
            self.items[index] = s
        else:
            if self.items[index].key == key:
                self.items[index].value = value
            else:
                temp = self.items[index]
                temp_next = self.items[index].next
                while temp_next is not None:
                    if temp_next.key == key:
                        temp_next.value = value
                        return
                    else:
                        temp = temp_next
                        temp_next = temp.next
                temp.next = s


    def 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].next
                while temp_next is not None:
                    if temp_next.key == key:
                        return temp_next
                    else:
                        temp_next = temp_next.next
                return None

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'))




二,哈希扩容

装载因子(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 = size
        self.__item = [None]*size
        self.__length = 0

    def __setitem__(self,key,value):
        self.__item[key] = value
        self.__length += 1

    def __getitem__(self, index):
        return self.__item[index]

    def __len__(self):
        return self.__length

    def __iter__(self):
        for value in self.__item:
            yield value

class Slot():
    def __init__(self,key,value):
        self.key = key
        self.value = value

    def __str__(self):
        return 'key:{}  value:{}'.format(self.key,self.value)


class HashTable():
    def __init__(self):
        self.size = 4
        self.length = 0
        self.items = Array(self.size)



    def find_index_to_insert(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return index
        else:
            while self.items[index] is not None:
                if self.items[index].key == key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return index

    def find_key(self,key):
        index = self.get_index(key)
        if self.items[index] == None:
            return None
        else:
            while self.items is not None:
                if key == self.items[index].key:
                    return index
                else:
                    index = (5*index+1) % self.size
            return None


    def get_index(self,key):
        return hash(key) % self.size

    def put(self, key, value):
        s = Slot(key, value)
        index = self.find_index_to_insert(key)
        self.items[index] = s
        self.length += 1
        if self.load_factor():
            self.rehashing()


    def load_factor(self):
        return self.length / float(self.size) > 0.8

    def rehashing(self):
        self.length = 0
        old = self.items
        self.size = self.size << 1
        self.items = Array(self.size)
        for s in old:
            if s:
                key = s.key
                index = self.find_index_to_insert(key)
                self.items[index] = s
                self.length += 1

    def 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'))

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【虚拟现实】一、AR与VR的基本原理

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 增强现实&#xff08;AR&#xff09;和虚拟现实&#xff08;VR&#xff09;技术已经从科幻小说走入现实&#xf…

Mysql使用中的性能优化——索引数对插入操作性能的影响

表的索引可以给数据检索提升效率&#xff0c;但是也给表的增删改操作带来代价。本文我们将关注&#xff0c;索引数量对INSERT操作的影响。 结论 索引数的新增会造成INSERT操作效率下降&#xff0c;约每增一个索引会降低10%效率。 实验数据 可以看到0个索引的效率是7个索引效…

记一次极其坑爹的 process.waitFor() 卡死问题

项目中有个需求需要截取wav的音频文件 &#xff0c;网上找了找方法 用java调用ffmpeg 来截取 public static InputStream trimAudio(MultipartFile inputFile, Double startTime, Double endTime,Double volume) throws IOException {File file new File(FileUtil.getTmpDir…

深度学习笔记: 最详尽广告点击预测系统设计

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 广告点击预测 1. 问题描述 建立一个机器学习模型来预测广告是否会被点击。 为了简化&#xff0c;我们不…

Rust : windows下protobuf尝试

此前dbpystream库是用python开发 web api。今天在rust中试用一下protobuf。 一、 protobuf编译器下载 具体见相关文章。没有编译器&#xff0c;protobuf无法运行。 windows参见&#xff1a; https://blog.csdn.net/wowotuo/article/details/139458846?spm1001.2014.3001.550…

数据结构--实验

话不多说&#xff0c;直接启动&#xff01;&#x1f44c;&#x1f923; 目录 一、线性表&#x1f60e; 1、建立链表 2、插入元素 3、删除特定位置的元素 4、输出特定元素值的位置 5、输出特定位置的元素值 6、输出整个链表 实现 二、栈和队列&#x1f618; 栈 顺序栈 …

【深度学习】Transformer分类器,CICIDS2017,入侵检测

文章目录 1 前言2 什么是入侵检测系统&#xff1f;3 为什么选择Transformer&#xff1f;4 数据预处理5 模型架构5.1. 输入嵌入层&#xff08;Input Embedding Layer&#xff09;5.2. 位置编码层&#xff08;Positional Encoding Layer&#xff09;5.3. Transformer编码器层&…

使用proteus仿真51单片机的流水灯实现

proteus介绍&#xff1a; proteus是一个十分便捷的用于电路仿真的软件&#xff0c;可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域&#xff0c;使用代码实现电路功能的仿真。 汇编语言介绍&#xff1a; 百度百科介绍如下&#xff1a; 汇编语言是培养…

Vue3中的常见组件通信之`$refs`、`$parent`

Vue3中的常见组件通信之$refs、$parent 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-mod…

用AI制作历史解说视频:GPT + MidJourney + PiKa + FunSound + 剪映

1. 项目介绍 最近某站看到一个看到利用AI创作视频解说&#xff0c;成品画面很酷炫。对此以初学者视角进行复现&#xff0c;创意来源&#xff1a;用AI制作历史解说视频 2. 开始创作 我们参照原作者展示的内容&#xff0c;对古代人物屈原来生成解说视频。 2.1 故事脚本分镜 【…

IT闲谈-IMD是什么,有什么优势

目录 一、引言二、IDM是什么&#xff1f;三、IDM的优势1. 高速下载2. 稳定性强3. 强大的任务管理4. 视频下载5. 浏览器整合 四、应用场景1. 商务办公2. 教育学习3. 娱乐休闲 总结 一、引言 在数字化时代&#xff0c;下载管理器已成为我们日常工作和生活中不可或缺的工具。而在…

【Java】JDBC+Servlet+JSP实现搜索数据和页面数据呈现

目录 1 .功能介绍 2. 实现流程 3. 项目环境 4. 相关代码 4.1 Maven配置 4.2 SQL语句 4.3 Java代码 4.4 HTML代码 4.5 JSP代码 5. 结果展示 &#xff08;原创文章&#xff0c;转载请注明出处&#xff09; 博主是计算机专业大学生&#xff0c;不定期更新原创优质文章&…

Java基础教程 - 14 Maven项目

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 14 Maven项目 Java 为什么那么强大&#xff0c;很大一部分原因是在实际的开发中&#xff0c;可以将别人开发的模块引入到我们自己的项目中&#xff0c;这样别人开发好了&#xff0c;我拿来就…

Android Media Framework(三)OpenMAX API阅读与分析

这篇文章我们将聚焦Control API的功能与用法&#xff0c;为实现OMX Core、Component打下坚实的基础。 1、OMX_Core.h OMX Core在OpenMAX IL架构中的位置位于IL Client与实际的OMX组件之间&#xff0c;OMX Core提供了两组API给IL Client使用&#xff0c;一组API用于管理OMX组件…

Mysql使用中的性能优化——批量插入的规模对比

在《Mysql使用中的性能优化——单次插入和批量插入的性能差异》中&#xff0c;我们观察到单次批量插入的数量和耗时呈指数型关系。 这个说明&#xff0c;不是单次批量插入的数量越多越好。本文我们将通过实验测试出本测试案例中最佳的单次批量插入数量。 结论 本案例中约每次…

Vue3中的常见组件通信之$attrs

Vue3中的常见组件通信之$attrs 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $re…

【机器学习基础】Python编程07:五个实用练习题的解析与总结

Python是一种广泛使用的高级编程语言&#xff0c;它在机器学习领域中的重要性主要体现在以下几个方面&#xff1a; 简洁易学&#xff1a;Python语法简洁清晰&#xff0c;易于学习&#xff0c;使得初学者能够快速上手机器学习项目。 丰富的库支持&#xff1a;Python拥有大量的机…

树莓派4b安装宝塔面板

1、打开命令窗口&#xff0c;执行如下命令 #更新 sudo apt-get update sudo apt-get upgrade #切换root权限 sudo su root #安装宝塔面板 wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && bash install.sh安装过程有点久&#xff0c;会持…

如何远程连接Linux服务器?

远程连接Linux服务器是通过网络连接到位于远程位置的Linux服务器&#xff0c;以进行服务器管理和操作。远程连接使得系统管理员可以方便地远程访问服务器&#xff0c;进行配置、维护和故障排除等操作&#xff0c;而不必亲自在服务器前工作。以下是一些常用的远程连接方法&#…

智慧社区整体解决方案

1.智慧社区整体建设方案内容 2.整体功能介绍