哈希表(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 再取模一个mod
	int 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;
}

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

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

相关文章

python print用法

1.输出字符串换行 输出结果会换行&#xff0c;默认自带换行 print(111) print(0) 2.末尾插入字符串或去除换行 末尾只能插入字符串&#xff0c;不能是其他类型 print(111,end0) print(0) 3.变量&#xff0c;字符串混合输入 没有必要什么都学&#xff0c;好用的常用的学一…

基于JavaWeb SSM mybatis 私人健身房系统管理平台设计和实现以及文档报告

基于JavaWeb SSM mybatis 私人健身房系统管理平台设计和实现以及文档报告 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞…

ClamAV:Linux服务器杀毒扫描工具

Clam AntiVirus&#xff08;ClamAV&#xff09;是免费而且开放源代码的防毒软件&#xff0c;软件与病毒码的更新皆由社群免费发布。ClamAV在命令行下运行&#xff0c;它不将杀毒作为主要功能&#xff0c;默认只能查出系统内的病毒&#xff0c;但是无法清除。需要用户自行对病毒…

Linux中查看文件内容的命令

文章目录 一、七类常见的Linux的文件二、显示命令三、分页显示四、显示文件前后内容五、压缩、解压缩六、补充 一、七类常见的Linux的文件 字符文件类型-普通文件&#xff0c;包括纯文本文件、二进制文件、各种压缩文件等。在find命令中&#xff0c;type 选项中用 f来表示d目录…

git学习——tags、release、drop commit

最近一直都在持续学习git相关内容&#xff0c;越来越发现git是一个十分适合大型项目和团队协作进行开发的工具&#xff0c;掌握好了对于我们参与项目维护和开发产品帮助很大&#xff0c;所以要不断持续学习git。 tags & releases tag的创建 当我们在git版本控制中遇到了…

Docker搭建LNMP环境实战(09):安装mariadb

1、编写mariadb部署配置文件 在文件夹&#xff1a;/mnt/hgfs/dockers/test_site/compose下创建文件&#xff1a;test_site_mariadb.yml&#xff0c;内容如下&#xff1a; version: "3.5" services:test_site_mariadb:container_name: test_site_mariadbimage: mari…

【Go】四、包名、访问范围控制、标识符、运算符

文章目录 1、_2、包名3、命名大小影响可访问范围4、运算符5、获取终端输入 1、_ 下划线"_"本身在Go中是一个特殊的标识符&#xff0c;称为空标识符用于忽略某个值 1&#xff09;忽略导入的没使用的包 2&#xff09;忽略某个返回值 2、包名 main包是程序的入口包&a…

【MATLAB第103期】#源码分享 | 基于MATLAB的LIME可解释性线性分类预测模型,2020b以上版本

【MATLAB第103期】#源码分享 | 基于MATLAB的LIME可解释性线性分类预测模型&#xff0c;2020b以上版本 一、模型介绍 LIME&#xff08;Local Interpretable Model-agnostic Explanations&#xff09;是一种用于解释复杂机器学习模型预测结果的算法。它由Marco Ribeiro、Sameer…

设计模式25--策略模式

定义 案例一 案例二 优缺点

AI版青花瓷

3月22日&#xff0c;Suno正式上线V3版本&#xff0c;很多人都称之为AI音乐的"ChatGPT"时刻&#xff0c;从此人人都可以是作曲家&#xff0c;先来听下最近霸榜的只因你太美baby来感受下它的厉害之处&#xff08;我已经被洗脑了哈哈&#xff09; 1. Suno 介绍 根据Sun…

每日学习笔记:C++ STL算法分类

非更易型 更易型 移除型 变序型 排序型 已排序区间算法 数值型算法

Elasticsearch的倒排索引是什么?

文章目录 什么是ES&#xff1f;什么是倒排索引&#xff1f;为什么叫做倒排索引&#xff1f;分词器的使用 什么是ES&#xff1f; Elasticsearch是基于 Apache Lucene【lusen】的搜索引擎&#xff0c;支持Restful API风格【可以使用常见的HTTP请求来访问】&#xff0c;并且搜索速…

抖店如何上架商品?这些细节要注意!否则罚款了别怪我没提醒你!

哈喽~我是电商月月 有朋友私信我一个问题&#xff0c;说是他上架商品后&#xff0c;被判类目错放了 情节严重扣了全部的2000块保证金 申述后没通过&#xff0c;还能要回来吗&#xff1f; 其实这种情况你确实是有错放的现象&#xff0c;误判的可能性很小&#xff0c;所以申述…

metasploit使用及内网笔记

1 基本操作 Metasploit就是一个漏洞框架。它的全称叫做The Metasploit Framework&#xff0c;简称叫做MSF。Metasploit作为全球最受欢迎的工具&#xff0c;不仅仅是因为它的方便性和强大性&#xff0c;更重要的是它的框架。它允许使用者开发自己的漏洞脚本&#xff0c;从而进行…

进销存管理系统:食品批发零售迈向数字化未来-亿发

随着消费逐步复苏&#xff0c;食品批发零售行业也迎来了客流的回升&#xff0c;实体店重新焕发了生机。然而&#xff0c;随着数字化时代的来临&#xff0c;传统的食品批发零售企业面临着新的挑战和机遇。些企业正积极实施数字化转型&#xff0c;通过布局线上线下多业态的融合发…

Linux系统使用Docker部署MeterSphere并实现公网访问本地测试平台

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…

Linux:查询类型的命令type

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 type命令是Linux中一个查询类型的命令&#xff0c;它可以查询name是alias别名、keyword关键字、function函数名、builtin内建命令名&#xff08;这很有用&#xff09;或…

嵌入式秋招项目(环境监测系统节点+云服务器+QT界面设计)

文章目录 1. 项目简介2. 项目文档与资源提供3. 项目实现效果 1. 项目简介 本项目实现的是环境监测系统&#xff0c;包括节点数据采集&#xff0c;云服务器部署&#xff0c;以及QT上位机界面设计&#xff0c;具体框图可见下图 节点端&#xff1a;采用STM32控制芯片&#xff0c;…

Latex绘制多行多TSNE列子图

Latex绘制多行多列TSNE子图 问题描述解决办法 问题描述 写论文需要绘制TSNE可视化图像。 解决办法 代码如下 \usepackage{subfigure}\begin{figure*}\centering\small\subfigure[aaa]{\includegraphics[width0.18\textwidth]{Figure/MFPT_v5_train_tsne_user0_bs0.png}}\su…

Linux gcc day2

mkdir -p 递归的创建目录 rm or rmdir&#xff1a; rmdir &#xff1a;是用来删除空目录的 实际上我们更加常用的是rm命令 rm可以删除普通文件,也可以删除目录&#xff0c;目录是从某次开始就是一棵树就是递归&#xff0c;所以就要递归删除 rm -r [文件名] 递归删除目录或者目…