Python----数据结构(哈希表:哈希表组成,哈希冲突)

一、哈希表

哈希表(Hash table)是一种常用、重要、高效的数据结构。

哈希表通过哈希函数,可以快速地将键(Key)映射到值(Value)。从而允许在近常数时间内对键关联的值进行插入、删除和查找操作。

哈希表的主要思想是通过哈希函数将键转换为索引,将索引映射到数组中的存储位置

通俗的例子是,为了查找电话簿中某人的号码,可以创建一个按照人名首字母顺序排列的表,在首字母为L的表中查找“雷”姓的电话号码,显然比直接查找就要快得多。

二、代码展示 

2.1、键值对

class Pair:  
    """键值对的类,包含一个键和一个值"""  

    def __init__(self, key: int, val: str):  
        """初始化键值对"""  
        self.key = key  # 键,整数类型  
        self.val = val  # 值,字符串类型  

    def __repr__(self):  
        """返回键值对的字符串表示"""  
        return f"{self.key} -> {self.val}"  

2.2、初始化

    def __init__(self):  
        """构造方法,初始化哈希表"""  
        # 创建一个包含 100 个桶的数组  
        self.buckets: list[Pair | None] = [None] * 100  

2.3、哈希函数

    def hash_func(self, key: int) -> int:  
        """哈希函数,将键映射到索引"""  
        index = hash(key) % 100  # 使用内置哈希函数计算键的哈希值,并对桶的数量取模  
        return index  

2.4、添加键值对

    def put(self, key: int, val: str):  
        """添加键值对到哈希表"""  
        pair = Pair(key, val)  # 创建新的键值对  
        index: int = self.hash_func(key)  # 计算键的哈希索引  
        self.buckets[index] = pair  # 将键值对放入相应的桶中  

2.5、查询值

    def get(self, key: int) -> str:  
        """根据给定的键查询值"""  
        index: int = self.hash_func(key)  # 计算键的哈希索引  
        pair: Pair = self.buckets[index]  # 获取对应的键值对  
        if pair is None:  
            return None  # 如果未找到,返回 None  
        return pair.val  # 返回找到的值  

2.6、删除键值对

    def remove(self, key: int):  
        """根据给定的键删除键值对"""  
        index: int = self.hash_func(key)  # 计算键的哈希索引  
        self.buckets[index] = None  # 将桶置为 None,表示删除  

2.7、返回所有键值对

    def entry_set(self) -> list[Pair]:  
        """返回哈希表中所有的键值对"""  
        result: list[Pair] = []  
        for pair in self.buckets:  
            if pair is not None:  
                result.append(pair)  # 将非空桶的键值对添加到结果列表中  
        return result  

2.8、返回键

    def key_set(self) -> list[int]:  
        """返回哈希表中所有的键"""  
        result = []  
        for pair in self.buckets:  
            if pair is not None:  
                result.append(pair.key)  # 将非空桶的键添加到结果列表中  
        return result  

2.9、返回值

    def value_set(self) -> list[str]:  
        """返回哈希表中所有的值"""  
        result = []  
        for pair in self.buckets:  
            if pair is not None:  
                result.append(pair.val)  # 将非空桶的值添加到结果列表中  
        return result  

2.10、输出

    def print(self):  
        """打印哈希表中的所有键值对"""  
        for pair in self.buckets:  
            if pair is not None:  
                print(pair.key, "->", pair.val)  # 打印每个键值对  

2.11、完整代码

class Pair:  
    """键值对的类,包含一个键和一个值"""  

    def __init__(self, key: int, val: str):  
        """初始化键值对"""  
        self.key = key  # 键,整数类型  
        self.val = val  # 值,字符串类型  

    def __repr__(self):  
        """返回键值对的字符串表示"""  
        return f"{self.key} -> {self.val}"  


class ArrayHashMap:  
    """基于数组实现的哈希表"""  

    def __init__(self):  
        """构造方法,初始化哈希表"""  
        # 创建一个包含 100 个桶的数组  
        self.buckets: list[Pair | None] = [None] * 100  

    def hash_func(self, key: int) -> int:  
        """哈希函数,将键映射到索引"""  
        index = hash(key) % 100  # 使用内置哈希函数计算键的哈希值,并对桶的数量取模  
        return index  

    def put(self, key: int, val: str):  
        """添加键值对到哈希表"""  
        pair = Pair(key, val)  # 创建新的键值对  
        index: int = self.hash_func(key)  # 计算键的哈希索引  
        self.buckets[index] = pair  # 将键值对放入相应的桶中  

    def get(self, key: int) -> str:  
        """根据给定的键查询值"""  
        index: int = self.hash_func(key)  # 计算键的哈希索引  
        pair: Pair = self.buckets[index]  # 获取对应的键值对  
        if pair is None:  
            return None  # 如果未找到,返回 None  
        return pair.val  # 返回找到的值  

    def remove(self, key: int):  
        """根据给定的键删除键值对"""  
        index: int = self.hash_func(key)  # 计算键的哈希索引  
        self.buckets[index] = None  # 将桶置为 None,表示删除  

    def entry_set(self) -> list[Pair]:  
        """返回哈希表中所有的键值对"""  
        result: list[Pair] = []  
        for pair in self.buckets:  
            if pair is not None:  
                result.append(pair)  # 将非空桶的键值对添加到结果列表中  
        return result  

    def key_set(self) -> list[int]:  
        """返回哈希表中所有的键"""  
        result = []  
        for pair in self.buckets:  
            if pair is not None:  
                result.append(pair.key)  # 将非空桶的键添加到结果列表中  
        return result  

    def value_set(self) -> list[str]:  
        """返回哈希表中所有的值"""  
        result = []  
        for pair in self.buckets:  
            if pair is not None:  
                result.append(pair.val)  # 将非空桶的值添加到结果列表中  
        return result  

    def print(self):  
        """打印哈希表中的所有键值对"""  
        for pair in self.buckets:  
            if pair is not None:  
                print(pair.key, "->", pair.val)  # 打印每个键值对  


if __name__ == '__main__':  
    map = ArrayHashMap()  # 创建一个新的哈希表实例  
    map.put('m', '蟒')  # 添加键值对  
    map.put('s', '蛇')  
    map.put('c', '程')  
    map.put('x', '序')  
    map.put('y', '员')  
    
    # 查询并打印值  
    print(map.get('m'))  # 输出:蟒  
    print(map.get('s'))  # 输出:蛇  
    print(map.get('c'))  # 输出:程  
    print(map.get('x'))  # 输出:序  
    print(map.get('y'))  # 输出:员  
    
    # 打印哈希表的内容  
    map.print()  
    print(map.entry_set())  # 输出所有的键值对

三、 哈希冲突

        若key(关键字)为n,则其值存放在 f(n) = n % size 的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f函数为哈希(散列)函数,按这个思想建立的表为哈希(散列)表

        但对不同的关键字可能得到同一散列地址,即n1 ≠ n2,而f(n1)==f(n2),这种现象称为冲突

3.1、散列函数

        哈希表中元素的位置是由哈希函数确定的。将数据n作为自变量,通过一定的函数关系计算出的值,即为该元素的存储地址。

3.1.1、直接定址法

直接使用key的某些部分作为存储地址,适用于关键字的取值范围不大的情况

假设我们有一组学生ID,并决定使用学生ID本身作为哈希地址

公式:哈希地址 = 学生ID

3.1.2、数字分析法

针对key的数位进行分析,选择具有代表性的数位作为哈希地址。

适用于关键字具有一定规律的情况假设我们有一组社交安全号码,我们选择使用最后两位数字作为哈希地址

对于123-45-6789,我们取最后两位89作为哈希地址

3.1.3、平方取中法

将关键字的平方值的中间一部分作为哈希地址。

适用于关键字分布较均匀的情况假设我们有一组三位数,我们将每个数字平方,然后取中间的数字作为哈希地址

对于数字456,平方得到207936。取中间两位数字

哈希地址为79公式:哈希地址 = 取中位数字(平方(关键字))

3.1.4、折叠法

将关键字分割成固定长度的片段,然后将这些片段相加,再取余数作为哈希地址。

适用于关键字长度较长的情况。考虑一组电话号码(例如,123-456-7890)。

我们可以将数字分成两位一组,求和,然后取模得到哈希地址对于电话号码123-456-7890,哈希地址将是(12 + 34 + 56 + 78 + 90) % 表大小

公式:哈希地址 = 组的数字之和(关键字) % 表大小

3.1.5、随机数法

用一个随机数生成器产生哈希地址。适用于关键字分布随机的情况

3.1.6、除留余数数法(常用)

将关键字除以某个不大于哈希表大小的数,取余数作为哈希地址

公式:哈希地址 = 关键字 % 表大小

3.2、 哈希冲突处理的办法

1、单独链表法(常用)

每个桶(数组元素)存储一个链表或其他数据结构(如列表)。所有哈希到同一索引的元素都放在这个链表中。

2、开放定址法

当发生哈希冲突时,试探性地寻找下一个空桶以存储新的键值对。可以使用线性探测、二次探测或者双重散列来确定下一个桶的位置。

3、双散列

是开放定址法的一种变体,使用两个不同的哈希函数。当发生冲突时,第二个哈希函数决定下一步的探测位置,从而实现更均匀的分布。

4、再散列

当哈希表达到一定的负载因子时,扩展表的大小并重新计算所有元素的位置,分散冲突。一般会将哈希表的容量加倍,并使用新的哈希函数或改变现有的哈希函数。

5、建立一个公共溢出区

设计一个额外的数组(溢出区)用于存储溢出(冲突)的元素。每当一个桶中溢出时,它就会将该元素放入溢出区。

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

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

相关文章

java方法学习

java 方法 在Java中,方法是类(或对象)的行为或功能的实现。(一起实现一个功能)java的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段。 方法是解决一类问题步骤的有序结合。 方法包含于类或…

网络运维学习笔记 015网工初级(HCIA-Datacom与CCNA-EI)NAT网络地址转换

文章目录 NAT(Network Address Translation,网络地址转换)思科:1)PAT2)静态端口转换 华为:1)EasyIP2)NAT Server静态NAT:动态NAT:实验1:在R1上配置NAPT让内网…

强化学习的数学原理-六、随机近似与随机梯度下降

代码来自up主【强化学习的数学原理-作业】GridWorld示例代码(已更新至DQN、REINFORCE、A2C)_哔哩哔哩_bilibili SGD、GD、MGD举例: # 先初始化一个列表,未来要在这100个样本里面再sample出来 np.random.seed(0) X np.linspace(-…

问卷数据分析|SPSS实操之相关分析

皮尔逊还是斯皮尔曼的选取主要看数据的分布 当数据满足正态分布且具有线性关系时,用皮尔逊相关系数 当有一个不满住时,用斯皮尔曼相关系数 1. 选择分析--相关--双变量 2. 将Z1-Y2加入到变量中,选择皮尔逊 3. 此处为结果,可看我案…

jsherp importItemExcel接口存在SQL注入

一、漏洞简介 很多人说管伊佳ERP(原名:华夏ERP,英文名:jshERP)是目前人气领先的国产ERP系统虽然目前只有进销存财务生产的功能,但后面将会推出ERP的全部功能,有兴趣请帮点一下 二、漏洞影响 …

解决华硕主板的Boot界面无法设置M.2的系统启动盘问题

一、问题描述 当我们的华硕主板电脑开机后,发现电脑无法正常进入Windows系统界面,直接显示PXE网络网络信息;且知道我们进入到BIOS界面也无法找到选择系统盘,界面只显示【UEFI:PXE IP4 Intel(R) Ethernet】、【UEFI:PXE IP6 Intel(…

BuildFarm Worker 简要分析

更多BuildFarm/Bazel/Remote Execution API的文章见我的个人博客: Bazel 报错:/tmp/external/gcc_toolchain_x86_64_files/bin/x86_64-linux-gcc: No such file or directory 记录Bazel 编译 java 代码为独立运行的 jar 包的方法BuildFarm S…

docker修改镜像默认存储路径(基于页面迁移)

文章目录 1、停止服务2、拷贝镜像3、docker界面设置路径4、重新启动服务5、重启电脑 1、停止服务 桌面底部右键打开任务管理器 停止docker服务 2、拷贝镜像 从原目录拷贝到新的目录下,新的目录自己定,如果没有权限,需要先对原文件添加权限…

基于ffmpeg+openGL ES实现的视频编辑工具-opengl相关逻辑(五)

在我们的项目中,OpenGL ES 扮演着至关重要的角色,其主要功能是获取图像数据,经过一系列修饰后将处理结果展示到屏幕上,以此实现各种丰富多样的视觉效果。为了让大家更好地理解后续知识,本文将详细介绍 OpenGL 相关代码。需要注意的是,当前方案将对 OpenGL 的所有操作都集…

机器学习实战(7):聚类算法——发现数据中的隐藏模式

第7集:聚类算法——发现数据中的隐藏模式 在机器学习中,聚类(Clustering) 是一种无监督学习方法,用于发现数据中的隐藏模式或分组。与分类任务不同,聚类不需要标签,而是根据数据的相似性将其划…

七星棋牌顶级运营产品全开源修复版源码教程:6端支持,200+子游戏玩法,完整搭建指南(含代码解析)

棋牌游戏一直是移动端游戏市场中极具竞争力和受欢迎的品类,而七星棋牌源码修复版无疑是当前行业内不可多得的高质量棋牌项目之一。该项目支持 6大省区版本(湖南、湖北、山西、江苏、贵州),拥有 200多种子游戏玩法,同时…

uniapp邪门事件

很久之前在这篇《THREEJS 在 uni-app 中使用(微信小程序)》:THREEJS 在 uni-app 中使用(微信小程序)_uni-app_帶刺的小葡萄-华为开发者空间 中学到了如何在uniapp的微信小程序里接入three.js的3d模型 由于小程序自身很…

【OS安装与使用】part6-ubuntu 22.04+CUDA 12.4运行MARL算法(多智能体强化学习)

文章目录 一、待解决问题1.1 问题描述1.2 解决方法 二、方法详述2.1 必要说明2.2 应用步骤2.2.1 下载源码并安装2.2.2 安装缺失的依赖项2.2.3 训练执行MAPPO算法实例 三、疑问四、总结 一、待解决问题 1.1 问题描述 已配置好基础的运行环境,尝试运行MARL算法。 1…

人工智能(AI)的不同维度分类

人工智能(AI)的分类 对机器学习进行分类的方式多种多样,可以根据算法的特性、学习方式、任务类型等不同维度进行分类这些分类都不是互斥的: 1、按数据模态不同:图像,文本,语音,多态等 2、按目标函数不同:判别式模型…

从零开始用react + tailwindcs + express + mongodb实现一个聊天程序(一)

项目包含5个模块 1.首页 (聊天主页) 2.注册 3.登录 4.个人资料 5.设置主题 一、配置开发环境 建立项目文件夹 mkdir chat-project cd chat-project mkdir server && mkdir webcd server npm init cd web npm create vitelatest 创建前端项目时我们选择javascrip…

【论文精读】VLM-AD:通过视觉-语言模型监督实现端到端自动驾驶

论文地址: VLM-AD: End-to-End Autonomous Driving through Vision-Language Model Supervision 摘要 人类驾驶员依赖常识推理来应对复杂多变的真实世界驾驶场景。现有的端到端(E2E)自动驾驶(AD)模型通常被优化以模仿…

基于Springboot学生宿舍水电信息管理系统【附源码】

基于Springboot学生宿舍水电信息管理系统 效果如下: 系统登陆页面 系统用户首页 用电信息页面 公告信息页面 管理员主页面 用水信息管理页面 公告信息页面 用户用电统计页面 研究背景 随着高校后勤管理信息化的不断推进,学生宿舍水电管理作为高校后勤…

POI pptx转图片

前言 ppt页面预览一直是个问题&#xff0c;office本身虽然有预览功能但是收费&#xff0c;一些开源的项目的预览又不太好用&#xff0c;例如开源的&#xff1a;kkfileview pptx转图片 1. 引入pom依赖 我这个项目比较老&#xff0c;使用版本较旧 <dependency><gro…

【JAVA】封装多线程实现

系列文章目录 java知识点 文章目录 系列文章目录&#x1f449;前言&#x1f449;一、封装的目标&#x1f449;二、常见的封装方式及原理&#x1f449;壁纸分享&#x1f449;总结 &#x1f449;前言 在 Java 中&#xff0c;封装多线程的原理主要围绕着将多线程相关的操作和逻辑…

nginx 反向代理 配置请求路由

nginx | 反向代理 | 配置请求路由 nginx简介 Nginx&#xff08;发音为“Engine-X”&#xff09;是一款高性能、开源的 Web 服务器和反向代理服务器&#xff0c;同时也支持邮件代理和负载均衡等功能。它由俄罗斯程序员伊戈尔西索夫&#xff08;Igor Sysoev&#xff09;于 2004…