【第十六课】哈希表(acwing-840模拟散列表 / 拉链法 / 开放寻址法 / c++代码 )

目录

前言

哈希表思想

拉链法

开放寻址法

acwing-840模拟散列表

拉链法代码如下

开放寻址法代码


前言

我对哈希表的印象就是:感觉可以类比数组,像数组的下标和该下标所对的元素之间的关系一样,就是比如ha[0]=1,那么我下标为0所对应的元素就是1,就是这样一种映射关系。只是哈希表所解决的是更复杂一些点、具有某种复杂的函数关系的映射。

另外感觉直接连想起来了关于离散化的知识,其实当时写那道题的时候就感觉也是类似哈希表的这种映射,只是当时还没学到hh。

离散化:acwing-802区间和

这里也提出了离散化是一种特殊的哈希表,它特殊的地方就在于它所处理的是数据范围较大的连续的坐标,在保持原有坐标的大小关系的基础上,将其压缩为范围小的、连续且非负的范围上,同时保持原始坐标的相对大小关系。

而哈希表是并没有什么按照坐标递增一个个映射,而是根据一定的哈希函数关系得到的散乱的映射,不具有递增的特性。

哈希表思想

一般来说我们所用到的求哈希值的办法就是直接对我们数组的最大的数据范围取模

(有个小tip就是我们最好对大于数据范围的最大的质数进行取模,比如这道题里最大数据范围是1e5,那我知道大于1e5的最大指数是1e5+3,因此我的常数N就设为1e5+3。这样可以最大限度的减少冲突的发生。)

附上求大于数据范围的最大质数的代码

//求大于1e5的最大质数
#include<iostream>
using namespace std;
int main()
{
    for(int i=100000;;i++)
    {
        int flag=1;
        for(int j=2;j*j<=i;j++)
        {
            if(i%j==0){
                flag=0;
                break;
            }
        }
        if(flag){
            cout<<i;
            break;
        }
    }
    return 0;
}

在这种取值方式下,有可能出现不同的数取模之后有相同的哈希值,称哈希冲突。为了应对哈希冲突有两种办法:拉链法和开放寻址法

一般用哈希表处理的是插入和查询操作,不太常用删除,如果非要实现删除的话,我们一般是在数据上做标记,要删的数据更改一下标记这样的形式来实现删除,实际上是没有删除的。

拉链法

拉链法就如下图

(简直受不了太丑了🤣)

就是把同一个哈希值的数据连成一个单链表。看到这里我就想起邻接表的结构也是这样,这两个是类似的。

ha数组存储的是哈希值为k的所有数据所组成的链表的头指针。 理解了这些剩下的就是数组模拟单链表的内容了。

数组模拟单链表

这是之前写过的内容,可以去回顾一下。

关于一些比较容易迷惑的点(我之前有点迷hh),再说一下。

//头插法
    e[idx]=x;
    ne[idx]=ha[k];
    ha[k]=idx++;

这是头插法插入数据的代码,最后的“ha[k]=idx++;” 这是记录下现在头结点的地址,这是在数组模拟单链表里的特有的部分,因为使用结构体链表的时候会自动分配空间地址,但是在数组模拟单链表的时候,只能靠下标的自增来实现地址的分配 

就是明白了这个突然感觉顿悟了数组模拟单链表。之前就是有点迷迷糊糊的感觉hh。

//单链表的遍历
for(int i=ha[k];i!=-1;i=ne[i])
    {
        if(e[i]==x)return 1;
    }

明白了之后单链表的遍历也很容易理解这个for循环的三个条件了。 

同时我们发现,其实我们表面上只建立了一个链表e和ne,但是他们其实是一个大的节点池,所谓的"多个单链表"都是存储在这个节点池里。也就是说,在e和ne数组中,是有很多个散乱分布的节点,而且他们并不是按照数组下标的顺序进行依次连接,而是有可能第一个节点的ne指针其实指向的是数组中第四个节点,而第三个节点的ne指针可能指向的是第二个节点。从而达到了好像有很多个单链表的效果,因此我们说这些链表是通过e和ne数组共享同一个节点池。这点可以明白哈。

查找一个元素是否出现过的时候,我们只需要遍历其所属链表,直到到达链表末尾,我们规定其为-1,即ha数组所有位置的初始值,如果我们一直到了-1还没有找到这个元素,就说明数组中不存在这个元素。查找失败。这里-1可以安全地用作链表的结束标志这里我们的判断标准是链表的末尾

开放寻址法

开放寻址法处理冲突的方式是,如果这个数据所得的哈希值的位置已经被用过了,那就从这个位置开始往后找,直到找到空位直接把数据放进去。要实现这样的操作就要把数组开到我们规定数据范围的两到三倍,用来尽可能避免冲突,这样的好处是可以只建立一个ha数组。

使用这种方法在查找一个元素是否出现过的时候,由于我们每个元素都是直接占用了一个数组的下标位置,所以我们找的时候只能在数组中一个一个遍历,我们比较的时候是直接拿我们数组位上所存储的数据进行对比的,因此我们如何标记没有找到该元素呢我们设一个在题目规定的数据范围之外的数,例如下面840这道题,我们规定数组初始值都为null=0x3f3f3f3f,这个数是大于10^9的,因此绝对不会与我们使用到的数据发生冲突导致歧义这里我们判断的标准是实打实的每一个数据的真实值。只有我们向后索引不属于有效数据范围的null的时候,才能安全的判断不存在该元素。

总结一下这个问题

在使用开放寻址法时,通常需要定义一个数据范围之外的数作为标记,表示哈希表中的空位置。这个标记通常被称为“哨兵值”。这个哨兵值应该是一个我们知道不会出现在输入数据中的值。这样,当我们在哈希表中看到这个哨兵值时,就可以确定这个位置是空的,没有存储任何元素。这主要是为了处理查找操作

acwing-840模拟散列表

有了上面的学习,理解了之后就直接看代码把,一些需要注意和解释的都写在注释里了。

拉链法代码如下

#include<iostream>
#include<cstring>//初始化数组memset的头文件
using namespace std;
const int N=1e5+3;//大于1e5的第一个质数
int ha[N],n;//ha数组存储的是:哈希值为 k 的所有数的 链表的头节点
int ne[N],e[N],idx;//e数组存储数据 ne数组存储下一个节点的地址 idx表示分配地址的下标

void Insert(int x)
{
    int k=(x%N+N)%N;//计算出哈希值
    //头插法
    e[idx]=x;
    ne[idx]=ha[k];
    ha[k]=idx++;
}
bool find(int x)
{
    int k=(x%N+N)%N;
    for(int i=ha[k];i!=-1;i=ne[i])//单链表的遍历
    {
        if(e[i]==x)return 1;
    }
    return 0;
}
int main()
{
    scanf("%d",&n);

    memset(ha,-1,sizeof ha);//初始化数组值为-1

    while(n--)
    {
        char op[2];
        int x;
        scanf("%s%d",op,&x);

        if(op[0]=='I')Insert(x);
        else{
            if(find(x))puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

开放寻址法代码

#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+3,null=0x3f3f3f3f;
int ha[N],n;
int find(int x)
{
    int k=(x%N+N)%N;
    while(ha[k]!=null && ha[k]!=x)//如果当前哈希值的位置有数据并且这个数不是我们正在处理的这个数,就要向后找能放它的位置
    {
        k++;
        if(k==N)k=0;
    }
    return k;
}
int main()
{
    scanf("%d",&n);

    memset(ha,0x3f,sizeof ha);

    while(n--)
    {
        char op[2];
        int x;
        scanf("%s%d",op,&x);

        int k=find(x);
        if(op[0]=='I')ha[k]=x;
        else{
            if(ha[k]!=null)puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

memset函数简单了解一下,暂时够用就行。

两种方式都是用到了memset函数来进行数组的初始化

memset(ha,-1,sizeof ha);//初始化数组值为

他是一个一般是快速的初始化数组的一个函数,使用该函数时要引头文件  #include<cstring> 

每次以一个字节为单位进行赋值,因此才出现在开放寻址法里null应该是0x3f3f3f3f,但是在memset函数里只写了0x3f的原因。


有了上面对于这两种方法的解释,代码应该不难理解。主要理解一下在查找操作上判断标准的不同。区分清楚就可以了。 

有问题欢迎指出!一起加油!!

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

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

相关文章

mask transformer相关论文阅读

前面讲了mask-transformer对医学图像分割任务是非常适用的。本文就是总结一些近期看过的mask-transformer方面的论文。 因为不知道mask transformer是什么就看了一些论文。后来得出结论&#xff0c;应该就是生成mask的transformer就是mask transformer。 DETR 很多这些论文都…

机器学习 | 掌握Matplotlib的可视化图表操作

Matplotlib是python的一个数据可视化库&#xff0c;用于创建静态、动态和交互式图表。它可以制作多种类型的图表&#xff0c;如折线图、散点图、柱状图、饼图、直方图、3D 图形等。以渐进、交互式方式实现数据可视化。当然博主也不能面面俱到的讲解到所有内容&#xff0c;详情请…

新特性Record最全用法总结---动力节点总结

目录 0、有用的新特性 一、Record 1.1、Record的介绍&#xff1a; 1.2、Record的声明&#xff1a; 1.3、Record的创建&#xff1a; 1.4、Record使用举例&#xff1a; 1.5、Record-实例方法、静态方法 1.6、Record-三类构造方法 1.6.1、紧凑型构造、定制构造方法&#…

MySQL的启动与连接

一、启动MySQL服务 方式一&#xff1a;进入计算机管理界面&#xff0c;点击【服务】&#xff0c;找到【MYSQL80】&#xff0c;右键开启即可 方式二&#xff1a;以管理员身份打开powershell, 输入命令net start MYSQL80. 二、连接MySQL服务 进入MySQL的安装目录中的bin目录&a…

【jetson笔记】torchaudio报错

原因是因为pip安装的包与jetson不兼容导致 自己安装或者cmake编译也会报错 需要拉取官方配置好的docker镜像 拉取docker镜像 具体容器可以看官网&#xff0c;按照自己需求拉取即可 https://catalog.ngc.nvidia.com/orgs/nvidia/containers/l4t-ml 如果其他包不需要只需要torc…

Supplier 惰性调用和 Future#get 同步等待调用结合

&#x1f4d6;一、背景介绍 关于任务异步执行&#xff0c;两个点不可避免&#xff1a;异步结果和异步回调。 而在我的工程中有这样一段代码&#xff1a;使用 CompletableFuture 进行封装&#xff0c;可以异步执行&#xff0c;异步回调&#xff0c;通过 get() 等待异步任务的结…

ArcEngine添加点要素、线要素、面要素及学习总结

基于C#的ArcEngine二次开发教程&#xff08;13&#xff09;&#xff1a;点、线、面要素的绘制_arcengine onmousedown-CSDN博客 https://www.cnblogs.com/cannel/p/11074343.html ArcEngine绘制点、线、多边形、矩形、圆形、椭圆的代码_arcengine 开发 生成矩形-CSDN博客 https…

《数学之友》期刊投稿方式投稿邮箱

《数学之友》是国家新闻出版总署批准的正规期刊&#xff0c;设置的栏目主要有&#xff1a;数学教育、教材研究、教学研究、数学建模、思想方法、数学学习、解题探索、CAI专题、复习考试、错例剖析等。从解题技巧方法、数学问题的溯源探微释疑到新课程背景下的教改教法教案&…

Qt事件处理,提升组件类

1.相关说明 1.提升组件QLabel的类&#xff0c;以实现双击功能 2.监控键盘事件&#xff0c;实现上下左右移动 3.鼠标点击获取坐标 2.相关界面 3.相关代码和操作 自定义类TMyLabel&#xff0c;父类为QLabel tmylabel.h #ifndef TMYLABEL_H #define TMYLABEL_H #include <QL…

thinkphp+vue+mysql旅游推荐攻略分享网站p0667

基于php语言设计并实现了旅游分享网站。该系统基于B/S即所谓浏览器/服务器模式&#xff0c;应用thinkphp框架&#xff0c;选择MySQL作为后台数据库。系统主要包括用户、景点信息、攻略分类、旅游攻略、门票购买、留言反馈、论坛管理、系统管理等功能模块。运行环境:phpstudy/wa…

CSC7225

CSC7225 为高性能电流模式 PWM 开关电源控制器&#xff0c;满足绿色环保标准&#xff1b;广泛适用于经济型开关电源&#xff0c;如 DVD、机顶盒、传真机、打印机、LCD 显示器等。CSC7225 采用 DIP-8 封装。 CSC7225主要特点  CSC7225内置 700V 高压功率开关管&#xff0c;外…

解读人工智能:AI时代的奇迹与担忧

随着科技的迅猛发展&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;逐渐进入人们的视野。那么&#xff0c;什么是人工智能呢&#xff1f;简单来说&#xff0c;它是一种模拟人类智能的技术&#xff0c;通过计算机系统实现人类所具备的思…

GBASE南大通用数据库GBase 8s常见问题解析 -- 查找锁会话并解锁

本文摘自GBASE南大通用社区&#xff0c;by&#xff1a;wty&#xff0c;原文请点击&#xff1a;GBase 8s常见问题 -- 查找锁会话并解锁|GBASE社区|天津南大通用数据技术股份有限公司|GBASE-致力于成为用户最信赖的数据库产品供应商 问题现象 执行SQL时报错 244: Could not do…

6.PR-AUC机器学习模型性能的常用的评估指标

PR-AUC PR-AUC&#xff0c;即精确率-召回率曲线下的面积&#xff0c;是一种用于评估分类模型性能的指标。与ROC-AUC&#xff08;接收者操作特征曲线下的面积&#xff09;不同&#xff0c;PR-AUC关注的是精确率和召回率之间的关系&#xff0c;特别适用于不平衡数据集。 精确率…

【大数据】YARN调度器及调度策略

YARN调度器 YARN负责作业资源调度&#xff0c;在集群中找到满足业务的资源&#xff0c;帮助作业启动任务&#xff0c;管理作业的生命周期。 ​ YARN技术架构 ​ 目前&#xff0c;Hadoop作业调度器主要有三种&#xff1a;先进先出调度器&#xff08;First In First Out&…

雪花算法生成ID【细糠】

目录 &#x1f9c2;1.ID生成规则 &#x1f953;2.UUID &#x1f32d;3.数据库自增主键 &#x1f37f;4.雪花算法 1.ID生成规则 1. 全局唯一2.趋势递增3.单调递增4.信息安全5.含时间戳 2.UUID UUID(Universally Unique Identifier)的标准型式包含32个16进制数字,以连字…

Windows和Linux访问不了GitHub的解决方法

一、Windows访问不了GitHub 问题描述 使用Windows访问GitHub时&#xff0c;出现如下情况&#xff0c;显示无法访问。 解决方案&#xff1a; 打开域名查询网站&#xff1a;https://tool.chinaz.com/dns 输入GitHub的域名&#xff0c;点击立即检测。 出现如下页面&#xff0c…

【51单片机】点亮第一个LED灯

目录 点亮第一个LED灯单片机 GPIO 介绍GPIO 概念GPIO 结构 LED简介软件设计点亮D1指示灯LED流水灯 橙色 点亮第一个LED灯 单片机 GPIO 介绍 GPIO 概念 GPIO&#xff08;general purpose intput output&#xff09; 是通用输入输出端口的简称&#xff0c; 可以通过软件来控制…

泥石流监测识别摄像机

泥石流监测识别摄像机是一种基于图像识别技术的监测设备&#xff0c;主要用于实时监测和识别泥石流的发生和演变过程&#xff0c;以预警和减灾为目的。这种摄像机通常采用高清晰度摄像头和图像处理系统&#xff0c;能够实时拍摄泥石流事件&#xff0c;并对图像进行处理和分析&a…

Spring Boot 整合 Camunda 实现工作流

工作流是我们开发企业应用几乎必备的一项功能&#xff0c;工作流引擎发展至今已经有非常多的产品。最近正好在接触Camunda&#xff0c;所以来做个简单的入门整合介绍。如果您也刚好在调研或者刚开始计划接入&#xff0c;希望本文对您有所帮助。如果您是一名Java开发或Spring框架…