当前位置: 首页 > news >正文

【算法】哈希表

作者:指针不指南吗
专栏:算法篇

🐾或许会很慢,但是不可以停下来🐾

文章目录

  • 1.定义
  • 2.优点
  • 3.数字哈希
    • 3.1拉链法
    • 3.2开放寻址法
    • 3.3 例题
  • 4.字符串哈希

1.定义

  • 哈希表(Hash table),是根据键(Key)直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这样就加快了查找速度。这个映射函数称做散列函数(哈希函数),存放记录的数组称做散列表。

  • 就是把一堆庞大数据映射到一个小的数据结构中,比如把0~10910^9109 映射到0~10510^5105 的数组中。

    h(x)一般用x mod n,n表示数组大小,一般取一个质数,这样冲突出现的概率比较小。

  • 冲突:当两个不一样的数,通过哈希函数,映射成一个数的时候,我们无法确定这两个数了,被称为冲突。

2.优点

查找速度快

  • 哈希表是种数据结构,它可以提供快速的插入操作和查找操作。

  • 不论哈希表中有多少数据,插入和删除,只需要接近常量的时间即 O( 1 ) 的时间复杂度。

    哈希表运算得非常快,在计算机程序中,如果需要在一秒种内查找上千条记录通常使用哈希表(例如拼写检查器)哈希表的速度明显比树快,树的操作通常需要O(N)的时间级。哈希表不仅速度快,编程实现也相对容易。

3.数字哈希

数字哈希是数字到数字的映射关系。

3.1拉链法

  • 操作

    • 开一个一维数组来存储哈希值;

    • 添加值(处理冲突)

      • 把每一个数组变量看成是一个槽,在槽上拉一个链,映射 h(x)出来是对应在槽,即添加在其链上。

      • 每条链上的数的个数,期望值是2个

        • 整个数组链表大致地样子

      在这里插入图片描述

      • 将一个数插在链表上面

    • 查找值

      映射h(x)一下 x ,遍历一下,它对应 槽的链上,有没有它

    • 删除值

      我们不会直接把它删掉,而是定义一个标记 bool,在对应想要删除的数值上,打一个标记。

  • 代码实现

    • 向哈希表中插入一个数
    void insert(int x) 
    {int k=(x%N+N)%N;  //哈希(映射)函数,先取模再加N,再取模,是为了保证最后的值是正数e[idex]=x;   //插在对应槽的链表里面ne[idex]=h[k];h[k]=idex++;
    }
    
    • 在哈希表中查询某个数是否存在
    bool find(int x)  
    {int k=(x%N+N)%N;  //先找出对应的槽for(int i=h[k];i!=-1;i=ne[i]){  //遍历槽的链表,查找是否有相同的值if(e[i]==x) return true;}return false;
    }
    

3.2开放寻址法

  • 操作

    • 只开一个一维数组,数组的大小按经验来说一般是 数据范围的2~3倍;
    • 先看一下,对应的槽里有没有数,有数的话,找下一槽,直到找到没有数的槽;
  • 代码实现

    int h[N];
    int null=0x3f3f3f3f;
    // 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
    int find(int x)
    {int k = (x % N + N) % N;  //函数映射到槽上while (h[k] != null && h[k] != x)  //这个槽里面有数,并且·这个数不是我,循环继续{k ++ ;  //找下一个槽if (k == N) k = 0;  //如果找到最后了,返回0,继续寻找}return t;
    }
    
    • 添加元素:

      find(x)=x x不在哈希表里面,find的返回值就是该插入的位置

    • 查找元素:

      int k = find(x) 如果x不在哈希表中,返回x应该插入的位置,则该位置为空

      h[k]==null 说明哈希表里面没有这个值

    • 删除元素:

      和拉链法一样,定义一个bool变量,用作标记

3.3 例题

维护一个集合,支持如下几种操作:

  1. I x,插入一个数 x;
  2. Q x,询问数 x 是否在集合中出现过;

现在要进行 N 次操作,对于每个询问操作输出对应的结果。

输入格式

第一行包含整数 N,表示操作数量。

接下来 N 行,每行包含一个操作指令,操作指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1 ≤ N ≤ 10510^5105
10910^9109 ≤ x ≤ 10910^9109

输入样例:

5
I 1
I 2
I 3
Q 2
Q 5

输出样例:

Yes
No
  • 方法一:拉链法

    #include<bits/stdc++.h>using namespace std;const int N=100003;  // N取100010的最大质数,100003
    int h[N],ne[N],e[N],idex;  //h表示数组中的槽,剩下的表示链表有关
    int n;void insert(int x)  //添加值的函数
    {int k=(x%N+N)%N;  //哈希(映射)函数,先取模再加N,再取模,是为了保证最后的值是正数e[idex]=x;   //插在对应槽的链表里面ne[idex]=h[k];h[k]=idex++;
    }bool find(int x)   //查找值的函数
    {int k=(x%N+N)%N;  //先找出对应的槽for(int i=h[k];i!=-1;i=ne[i]){  //遍历槽的链表,查找是否有相同的值if(e[i]==x) return true;}return false;
    }int main()
    {scanf("%d",&n );  //读入操作次数memset(h,-1,sizeof h);  //清空数组,空指针一般用 -1 表示char op[2];   //读入一个字符的时候,直接用字符数组读入,降低出错率int x;  while(n--){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=200003,null=0x3f3f3f3f;  //N数组长度一般为数据范围的2~3倍且为质数,null表示空指针
    int h[N]; //h表示槽的位置
    int n;// 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
    int find(int x)
    {int k = (x % N + N) % N;  //函数映射到槽上while (h[k] != null && h[k] != x)  //这个槽里面有数,并且·这个数不是我,循环继续{k ++ ;  //找下一个槽if (k == N) k = 0;  //如果找到最后了,返回0,继续寻找}return t;
    }int main()
    {scanf("%d",&n);memset(h,0x3f,sizeof h);while(n--){char op[2];int x;scanf("%s%d",op,&x);int k=find(x);if(*op=='I') h[k]=x;  //往哈希表里面插入元素else{if(h[k]!=null) puts("Yes");  //在哈希表里面寻找元素else puts("No");}}return 0;
    }
    

4.字符串哈希

字符串哈希是字符串到数字的映射关系。

我认为这个记住模板就行。

  • 映射

    • 我们使用的映射关系是字符串到P进制数的映射关系(P是任意的),保证映射是一一对应的,不能有冲突。
    • 使冲突最小化,我们取P=131 或者 P=13331 ,并且把字符串映射到 2642^{64}264 范围内的数字
  • 操作

    1. 先预处理出来,字符串所有前缀的哈希


      防止冲突,不能映射成0。

    2. 求一段区间的哈希值

    3. 哈希映射的时候,要对数值取N的模,unsigned long long 的范围就是2642^{64}264 ,我们可以用它来巧妙地解决取模,因为正好 超过 unsigned long long 就会溢出。

  • 代码模板

    typedef unsigned long long ULL;
    ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64// 初始化
    p[0] = 1;
    for (int i = 1; i <= n; i ++ )
    {h[i] = h[i - 1] * P + str[i];p[i] = p[i - 1] * P;
    }// 计算子串 str[l ~ r] 的哈希值
    ULL get(int l, int r)
    {return h[r] - h[l - 1] * p[r - l + 1];
    }
    
  • 例题

    给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [ l1 , r1 ] 和 [l2,r2]这两个区间所包含的字符串子串是否完全相同。

    字符串中只包含大小写英文字母和数字。

    输入格式

    第一行包含整数 n 和 m,表示字符串长度和询问次数。

    第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。

    接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。

    注意,字符串的位置从 1 开始编号。

    输出格式

    对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No

    每个结果占一行。

    数据范围

    1≤n,m≤10510^5105

    输入样例:

    8 3
    aabbaabb
    1 3 5 7
    1 3 6 8
    1 2 1 2
    

    输出样例:

    Yes
    No
    Yes
    
    #include<bits/stdc++.h>
    using namespace std;typedef unsigned long long ULL;  //ULL代替取模,映射哈希函数const int N=100010,P=131;
    ULL p[N],h[N];   //p表示前缀哈希,h表示哈希值int n,m;
    char str[N];ULL get(int l,int r)  //求某段区间的哈希值
    {return  h[r]-h[l-1]*p[r-l+1];  //右端点的前缀哈希值-左端-1的前缀和哈希值*区间进制
    }int main()
    {scanf("%d%d%s",&n,&m,str+1);  //预处理,直接从str+1 开始输入(后面涉及-1操作)p[0]=1;  //初始化,因为后面涉及-1和乘法for(int i=1;i<=n;i++){p[i]=p[i-1]*P;  //哈希映射,P进制h[i]=h[i-1]*P+str[i];  //前缀哈希值}while(m--){int l1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);if(get(l1,r1)==get(l2,r2)) puts("Yes");  //区间哈希值相等,则区间的字符相等else puts("No");}return 0;
    }
    

    之后补充 STL 中哈希表用法
    Alt

相关文章:

【算法】哈希表

作者&#xff1a;指针不指南吗 专栏&#xff1a;算法篇 &#x1f43e;或许会很慢&#xff0c;但是不可以停下来&#x1f43e; 文章目录1.定义2.优点3.数字哈希3.1拉链法3.2开放寻址法3.3 例题4.字符串哈希1.定义 哈希表&#xff08;Hash table&#xff09;&#xff0c;是根据键…...

彻底搞懂React-hook链表构建原理

写在前面的小结 每一个 hook 函数都有对应的 hook 对象保存状态信息useContext是唯一一个不需要添加到 hook 链表的 hook 函数只有 useEffect、useLayoutEffect 以及 useImperativeHandle 这三个 hook 具有副作用&#xff0c;在 render 阶段需要给函数组件 fiber 添加对应的副…...

【数据挖掘实战】——应用系统负载分析与容量预测(ARIMA模型)

项目地址&#xff1a;Datamining_project: 数据挖掘实战项目代码 目录 一、背景和挖掘目标 1、问题背景 2、传统方法的不足 2、原始数据 3、挖掘目标 二、分析方法与过程 1、初步分析 2、总体流程 第一步&#xff1a;数据抽取 第二步&#xff1a;探索分析 第三步&a…...

【华为OD机试模拟题】用 C++ 实现 - 九宫格按键输入(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明九宫格按键输入题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高…...

Linux: config: CONFIG_SYN_COOKIES

文章目录 CONFIG_SYN_COOKIESLinux kernel里的超时设置Huawei SBC详细工作机制CONFIG_SYN_COOKIES config SYN_COOKIES,布尔值;是否支持IP:TCP syncookie功能。 详解:一般来说TCP/IP网络不能够阻挡SYN flooding工具。这个工具很容易被利用,而且会导致DOS工具,妨碍其他整…...

【笔记】C# 数据类型转换

文章目录前言类型转换的概念1&#xff0c;隐式转换2&#xff0c;显式转换3&#xff0c;程序类转换结语前言 &#x1f33b; 大家好啊&#xff0c;我是writer桑&#xff0c;本章是关于 C# 数据类型转换的一个总结&#xff0c;其中包含隐式、显示转换和程序类转换&#xff0c;方便…...

JavaWeb JavaBean,MVC三层架构

9、JavaBean 实体类 JavaBean有特定的写法&#xff1a; 必须要有一个无参构造属性必须私有化必须有对应的get/set方法&#xff1b; 一般用来和数据库的字段做映射 ORM&#xff1b; ORM &#xff1a;对象关系映射 表—>类字段–>属性行记录---->对象 people表 …...

JavaEE简单实例——MyBatis一对多关联映射的嵌套结果集查询

简单介绍&#xff1a; 在之前的章节&#xff0c;我们简单介绍了MyBatis中的一对一的关联查询&#xff0c;使用了嵌套查询和嵌套结果集两种方式进行讲解&#xff0c;但是在实际的使用中&#xff0c;我们常用的是嵌套结果集的查询方式&#xff0c;所以在一对多的查询中&#xff…...

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——OutputFormat数据输出

3.6.1OutputFormat接口实现类 OutputFormat是MapReduce输出的基类&#xff0c;所有实现MapReduce输出都实现了OutputFormat接口。下面我们介绍几种常见的OutputFormat实现类。 1、文本输出TextOutputFormat 默认的输出格式是TextOutputFormat&#xff0c;它把每条记录写为文…...

Linux搜索、编辑

目录 1.搜索 1.1.基础用法 1.2.高级用法 2.编辑 2.1.vim简洁 2.2.vim快捷键 1.搜索 1.1.基础用法 find命令用于搜索&#xff0c;格式如下&#xff1a; find 指定目录 -匹配方式 所要匹配的关键字 所要匹配的关键字支持通配符,?代表一个字符*代表任意个字符。 如果想设…...

Git Commit提交规范总结

文章目录前言git commit 提交规范提交消息头(commit message header)提交消息具体内容(commit message body)提交消息尾述(commit message footer)Revert表情(Emojis)标识idea插件其他操作Commitizen生成 Change logGit获取提交消息格式化输出相关参考前言 我们都知道&#xf…...

【ESP 保姆级教程】疯狂毕设篇 —— 案例:基于ESP8266和EMQX的教室灯光控制系统

忘记过去,超越自己 ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-02-26 ❤️❤️ 本篇更新记录 2022-02-26 ❤️🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请…...

SpringBoot (一) 项目构建、配置读取、静态资源定义

哈喽&#xff0c;大家好&#xff0c;我是有勇气的牛排&#xff08;全网同名&#xff09;&#x1f42e; 有问题的小伙伴欢迎在文末评论&#xff0c;点赞、收藏是对我最大的支持&#xff01;&#xff01;&#xff01;。 前言 SpringBoot是基于Spring开发的开源项目&#xff0c…...

<JVM上篇:内存与垃圾回收篇>12 - 垃圾回收相关概念

笔记来源&#xff1a;尚硅谷 JVM 全套教程&#xff0c;百万播放&#xff0c;全网巅峰&#xff08;宋红康详解 java 虚拟机&#xff09; 文章目录12.1. System.gc()的理解12.2. 内存溢出与内存泄露内存溢出&#xff08;OOM&#xff09;内存泄漏&#xff08;Memory Leak&#xff…...

new操作符做了什么?

new是什么&#xff1f; new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 function Person (name,age) {this.name namethis.age age } Person.prototype.sayName function () {console.log(this.name) } let man new Person(xl,20) consol…...

Java_IO流,书城IO版

1.字符IO流的输入/输出 首先&#xff0c;IO流根据多方面划分。 根据方向划分 输入流/输出流根据处理单元划分 字节流/字符流根据功能划分 节点流/处理流 尝试一下使用字符输入流在读写文件&#xff1a; package IOStream;import java.io.*;public class Test {public stati…...

2023自动化测试岗位需求的 7 项必备技能 (最新版)

目录&#xff1a;导读 一、自动化测试员技能——编程语言 二、自动化测试员技能–出色的手动测试技能 三、.自动化测试员技能–自动化工具专业知识 四、自动化测试员技能–了解业务需求 五、自动化测试员技能–自动化工具故障排除 六、自动化测试员技能–具有测试管理工具…...

【华为OD机试模拟题】用 C++ 实现 - 路灯照明(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明路灯照明【华为OD机试模拟题】题目输入输出描述示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高…...

学到贫血之-贫血模型和充血模型

学习自&#xff1a;设计模式之美 1 基于贫血模型的传统开发模式 // ControllerVO(View Object) public class UserController {private UserService userService; //通过构造函数或者IOC框架注入public UserVo getUserById(Long userId) {UserBo userBo userService.getUser…...

Java常用组件面试题

文章目录HTTP通信协议Kafka消息队列Linux操作系统Mybatis框架SpringCloud框架HTTP通信协议 https通信过程 https协议是指对通过http协议传输数据的进行加密和解密。当客户端发送https请求时&#xff0c;服务端会返回数字证书给客户端&#xff0c;客户端验证通过后会生成随机数…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

轻量级Docker管理工具Docker Switchboard

简介 什么是 Docker Switchboard &#xff1f; Docker Switchboard 是一个轻量级的 Web 应用程序&#xff0c;用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器&#xff0c;使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...

PydanticAI快速入门示例

参考链接&#xff1a;https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...