哈希表(Hash Table) -- 用数组模拟--字符串前缀哈希

本文用于个人算法竞赛学习,仅供参考

目录

一.什么是哈希表

 二.哈希函数中的取模映射

三.拉链法(数组实现)

 四.拉链法模板

五.开放寻址法

六.开放寻址法模板

 七.字符串前缀哈希

九.字符串前缀哈希 模板

十.题目


一.什么是哈希表

哈希表(Hash Table)是一种数据结构,用于存储键值对。它通过将键映射到表中的一个位置来实现快速的查找操作。在哈希表中,每个键都会经过一个哈希函数的计算,得到对应的哈希值,然后将键值对存储在哈希值对应的位置上。

哈希表的主要特点包括:
1. 快速的查找操作:通过哈希函数计算出键对应的位置,可以在常数时间内找到对应的值。
2. 空间效率高:可以根据实际情况动态调整哈希表的大小,使得空间利用率高。
3. 冲突处理:由于哈希函数的映射不是一 一对应的,可能会出现不同键映射到同一个位置的情况,这时需要通过解决冲突的方法来存储这些键值对。

在哈希表中,哈希函数起着至关重要的作用,它决定了键和哈希值之间的映射关系。一个好的哈希函数应该尽可能地减少冲突,使得键能够均匀地分布在哈希表中。

常见的哈希表实现方式包括开放寻址法拉链法。开放寻址法是指当发生冲突时,依次探测下一个空槽位来存储冲突的键值对;拉链法是指在哈希表的每个位置上存储一个链表,将冲突的键值对存储在链表中。

在实际应用中,哈希表被广泛应用于各种场景,如数据库索引、缓存系统、编程语言中的字典等。

 二.哈希函数中的取模映射

假定所需数据区间a(0,10^5),值域x(-10^9, 10^9)

有哈希函数 h(x) ∈(0,10^5),其中h(x) = x  mod  10^5

当有多个元素同时映射到同一个值时产生哈希冲突,使用 开放寻址法 和 拉链法来解决

对于取模的数值大小按题目设定,一般设定成一个质数,且离2的整次幂尽可能远,这样发生冲突的概率较小。

三.拉链法(数组实现)

用一个数组来实现拉链法,数组下标是映射后的值,数组存储链表头

 四.拉链法模板

//伪代码
// 
//h[]是用来存放链表头的,e[]存放节点数据,ne[]存放节点的next指针
//index相当于节点的地址
const int N = 100010;
int h[N], e[N], ne[N], index, mod;
//bool数组来判断是否存在,true表示存在,false表示已经删除
bool exist[N];void init()
{//将h[]指向-1表示指向空链表memset(h, -1, sizeof(h));
}//求取模mod的值(求第一个大于N的质数)
int getMod(int N)
{for (int i = N; i; i++){bool isMod = true;for (int j = 2; j * j <= i; j++){if (i % j == 0){isMod = false;break;}}if (isMod){return i;}}
}//向哈希表中插入一个数
void insert(int x)
{mod = getMod(N);//因为值域存在负数(c++负数取模是负数),所需数据区间>0,所以加上mod 再取模一个modint k = (x % mod + mod) % mod;exist[index] = true;e[index] = x;ne[index] = h[k];h[k] = index++;
}//查找一个数
bool find(int x)
{mod = getMod(N);int k = (x % mod + mod) % mod;for (int i = h[k]; i != -1; i = ne[i]){if (e[i] == x && exist[i])return true;}return false;
}//删除操作不会直接删除,会再开一个bool数组来判断,true表示存在,false表示已经删除
void del(int x)
{mod = getMod(N);int k = (x % mod + mod) % mod;for (int i = h[k]; i != -1; i = ne[i]){if (e[i] == x)exist[i] = false;}
}

五.开放寻址法

在开放寻址法中,当发生哈希冲突时,会尝试在哈希表中的其他位置寻找空闲的位置来存储数据,而不是使用链表等数据结构来处理冲突。可以使用线性探测:当发生冲突时,依次检查下一个位置,直到找到一个空闲位置为止。

在开放寻址法中,为了保证数据能够被正确插入并正确查找,哈希表的大小一般会设置为所需数据个数的2~3倍,这样可以减少冲突的概率,提高查找和插入的效率。

六.开放寻址法模板

//开放寻址法
//数组开辟一般为所需数据个数的2~3倍--可以使冲突概率降低const int N = 300010;
int h[N];
//标记空格
int null = 0x3f3f3f3f;//7717637477//初始化
void init()
{memset(h, 0x3f, sizeof(h));//memset是每个字节赋值
}//如果x在哈希表中,返回x的下标,如果不存在就返回应该插入的位置
int find(int x)
{int t = (x % N + N) % N;while (h[t] != null && h[t] != x){t++;if (t == N)t = 0;//循环回去找}//此时t要么找到了返回对应下标,要么没找到返回应该插入的下标return t;
}//插入一个数
void insert(int a)
{int t = (a % N + N) % N;t = find(t);h[t] = a;
}

 七.字符串前缀哈希

字符串前缀哈希是一种用于快速计算字符串前缀哈希值的方法,通常用于字符串匹配算法中。其基本思想是将字符串看作是一个以某个进制表示的数,通过计算前缀的哈希值快速比较字符串的相等性(快速判断两个字符串是否相等)

一种常见的计算字符串前缀哈希值的方法是使用多项式哈希,即将字符串中的每个字符看作是一个进制数,并通过多项式运算来计算哈希值。假设字符串 s 的长度为 n ,字符集大小为 P ,则可以使用如下公式计算字符串前缀哈希值:
H[i] = (H[i-1] * P + s[i]) % Q

其中, H[i] 表示字符串 s 的前缀 s[0:i] 的哈希值, P 是一个较大的质数, Q 是一个较大的模数,  s[i] 表示字符串 s 的第 i 个字符。

为了避免哈希冲突,对于P一般取值为131或者13331,Q一般取2^64,一般情况下99.99%不会有冲突。

八.通过字符串前缀哈希 求区间哈希值

 举个例子:

九.字符串前缀哈希 模板

//思想:将字符串看成P进制,P的经验值是131或者13331,Q取2^64, 这样发生冲突的概率较小
//取模Q的数用 2^64 ,这样直接用unsigned long long的存储,因为unsigned long long最大可以存放2^64,超出部分就相当于取模2^64了typedef unsigned long long ULL;
const int N = 100010;
//H[] 存储字符串哈希值,P[] 存储对应对应数量级,p^k % 2^64
ULL H[N], P[N];
int p = 131;
//原字符串
char str[N];
//H[],P[],str[]有效值从下标1开始//初始化
void init()
{H[0] = 0;P[0] = 1;
}//求字符串前缀哈希--str表示字符串
void Hash()
{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)];
}

十.题目

P3370 【模板】字符串哈希 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <unordered_set>
#include <cstdio>using namespace std;const int N = 10010;
const int M = 1510;
const int P = 131;
typedef unsigned long long ULL;int sizes;//维护一个字符串的长度
vector<ULL> H;int main()
{int n;scanf("%d", &n);while (n--){char str[M];//下标从1开始scanf("%s", str+1);sizes = strlen(str + 1);//求哈希值ULL h = 0;for (int i = 1; i <= sizes; i++){h = h * P + str[i];}H.push_back(h);}unordered_set<ULL> Set(H.begin(), H.end());printf("%llu\n", Set.size());return 0;
}

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

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

相关文章

flink: 将接收到的tcp文本流写入HBase

一、依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…

C# 排序的多种实现方式(经典)

一、 对数组进行排序 最常见的排序是对一个数组排序&#xff0c;比如&#xff1a; int[] aArray new int[8] { 18, 17, 21, 23, 11, 31, 27, 38 }; 1、利用冒泡排序进行排序&#xff1a; &#xff08;即每个值都和它后面的数值比较&#xff0c;每次拿出最小值&#xff09; s…

java数据结构与算法刷题-----LeetCode695. 岛屿的最大面积

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 深度优先遍历2. 广度优先 1. 深度优先遍历 这不是找最短路径&…

[ruby on rails] ruby使用vscode做开发

ruby LSP实现 ruby插件推荐用这个来实现&#xff0c;但是现在这个在加载文件索引时候&#xff0c;特别慢&#xff0c;时好时坏&#xff0c;所以现在推荐用Solargraph实现 ruby LSP要求ruby版本3以上&#xff0c;如果在旧版本中使用&#xff0c;需要指定bundleGemfile路径 旧版…

电脑win10系统更新后开机很慢,更新win10后电脑开机怎么变慢了

很多用户反映&#xff0c;更新win10后电脑开机怎么变慢了呢?现在动不动就要30几秒&#xff0c;以前都是秒开机的&#xff0c;要怎么设置才能提高开机速度?小伙伴们别着急&#xff0c;主要原因可能是关机设置中没有勾选启用快速启动&#xff0c;或者是开机启动设置的问题&…

Excel 隔几行批量插入空白行

例如如下表格&#xff0c;每隔6行插入一行数据&#xff1a; 1&#xff09;第7个单元格输入1 2&#xff09;选中6个单元格&#xff0c;然后双击填充数据&#xff1a; 3&#xff09;F5 找到常量 Ctrlshift 复制插入的数据&#xff0c;然后选中数据 按F5&#xff0c;定位到空值

两数之和-考察哈希表的运用

题目 给定一个整数数组 n u m s nums nums和一个整数目标值 t a r g e t target target&#xff0c;请你在该数组中找出和为目标值 t a r g e t target target的那 两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同…

网络基础——ISIS

名词 ISIS&#xff1a;中间系统到中间系统&#xff0c;优先级是15集成化ISIS&#xff1a;这是在优化后&#xff0c;可以使用在OSI模型上的NET地址&#xff1a;由区域ID、系统ID和SEL组成&#xff0c;一台设备上最多配置3个NET地址&#xff0c;条件是区域号要不一致&#xff0c;…

使用VM搭建Linux服务器局域网

最近在了解一些LAN相关的内容&#xff0c;抱着学习的心态就使用了VM安装Linux虚拟机进行组建LAN&#xff08;局域网&#xff09;的测试。 一、虚拟机网络规划 下面是我安装的虚拟机网络配置 虚拟机编号 IP地址 子网掩码 网络连接 1 192.168.164.100 255.255.255.0 NAT…

golang语言系列:Git

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 golang语言系列 文章&#xff0c;主要对编程通用技能Git进行学习 1.为什么使用版本控制系统 版本控制系统可以解决的问题 代码备份很重要版本控制很重要协同工作很重要责任追溯很重要 常见的版本控制系统 GitS…

ES学习日记(七)-------Kibana安装和简易使用

前言 首先明确一点&#xff0c;Kibana是一个软件&#xff0c;不是插件。 Kibana 是一款开源的数据分析和可视化平台&#xff0c;它是 Elastic stack 成员之一&#xff0c;设计用于和Elasticsearch 协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索&#xff0c;…

css酷炫边框

边框一 .leftClass {background: #000;/* -webkit-animation: twinkling 1s infinite ease-in-out; 1秒钟的开始结束都慢的无限次动画 */ } .leftClass::before {content: "";width: 104%;height: 102%;border-radius: 8px;background-image: linear-gradient(var(…

服务器设置了端口映射之后外网还是访问不了服务器

目录 排查思路参考&#xff1a; 1、确认服务是否在运行 2、确认端口映射设置是否正确 3、使用防火墙测试到服务器的连通性 4、检查服务内部的配置 5、解决办法 6、学习小分享 我们在一个完整的网络数据存储服务系统设备中都会存有业务服务器、防火墙、交换机、路由器&a…

穿山甲广告平台SDK接入效果怎么样?

广告收入是大多数开发者的应用变现收入来源&#xff0c;如何进行流流量变现是从应用设计之初就需要开发者思考的问题。 穿山甲广告平台作为国内第三方广告变现平台&#xff0c;是不少开发者选择的对接平台。 穿山甲广告平台的广告类型较多&#xff0c;有信息流&#xff0c;ba…

【单片机 5.3开关检测】

文章目录 前言一、5.3开关检测1.1没按键按下的1.2有按键按下的 二、改进1.改进 三、独立键盘3.1为什么要取反3.2 实用的按键 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 课程需要&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xf…

VScode 集成终端设置默认打开当前文件夹 mac系统

一.快捷键设置 搜索 openInIntegratedTerminal 如图&#xff1a; 二.设置cmd 默认打开位置 点击设置 搜索 ntegrated:cwd 如下图&#xff1a; 三.查看ip 快捷指令&#xff1a; ipconfig getifaddr en0

前端性能优化-Table渲染速度优化

教务系统-排课页面性能优化总结 一、前言 在公司教务系统中,排课页面慢的令人发指,在某些情况由于数据量大导致页面主进程卡死,遂组织进行一次排查优化,现记录一下 二、效果对比 以下数据均为UAT环境 Performence对比 更改前: 主进程渲染时间为 8s 教务系统-排课页面性…

HTTP和HTTPS谁传输数据更安全?

1.HTTP HTTP在传输数据时&#xff0c;通常都是明文传输&#xff0c;也就是传输的数据没有进行加密。在这种情况下&#xff0c;如果传输的是一些敏感数据&#xff0c;比如某银行卡密码&#xff0c;就很容易被别人截获到&#xff0c;这就对我们的个人利益产生了威胁。 HTTP传输数…

go优雅读取zip压缩包-进阶2

【前言】 看到这里就晓得了&#xff0c;之前那一一篇文章go优雅读取zip压缩包&#xff0c;依旧还是有些问题&#xff0c;接下来&#xff0c;我就开始描述下本文章讲述的内容&#xff1a; 面对需要多次读取多个zip压缩包里的指定文件内容&#xff0c;如何提升读取的速度&#x…

C++初阶:5.STL简介(了解)

STL简介&#xff08;了解&#xff09; 一.什么是STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 二. STL的版本 原始版本 Alexander Stepan…