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

news2024/10/6 8:24:16

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

目录

一.什么是哈希表

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

三.拉链法(数组实现)

 四.拉链法模板

五.开放寻址法

六.开放寻址法模板

 七.字符串前缀哈希

九.字符串前缀哈希 模板

十.题目


一.什么是哈希表

哈希表(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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

fork复制进程

1.shell: 在计算机科学中&#xff0c;Shell俗称壳&#xff08;用来区别于核&#xff09;&#xff0c;是指“为使用者提供操作界面”的软件&#xff08;command interpreter&#xff0c;命令解析器&#xff09;。它类似于DOS下的COMMAND.COM和后来的cmd.exe。它接收用户命令&am…

C语言中入门到实战————动态内存管理

目录 前言 一、为什么要有动态内存分配 二、 malloc和free 2.1 malloc 2.2 free 三、calloc和realloc 3.1 calloc 3.2 realloc 四. 常见的动态内存的错误 4.1 对NULL指针的解引用操作 4.2 对动态开辟空间的越界访问 4.3 对非动态开辟内存使用free释放 4.4 使…

2024年【T电梯修理】考试题及T电梯修理考试内容

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【T电梯修理】考试题及T电梯修理考试内容&#xff0c;包含T电梯修理考试题答案和解析及T电梯修理考试内容练习。安全生产模拟考试一点通结合国家T电梯修理考试最新大纲及T电梯修理考试真题汇总&#xff0c;有助…

Collection与数据结构链表与LinkedList(三):链表精选OJ例题(下)

1. 分割链表 OJ链接 class Solution {public ListNode partition(ListNode head, int x) {if(head null){return null;//空链表的情况}ListNode cur head;ListNode formerhead null;ListNode formerend null;ListNode latterhead null;ListNode latterend null;//定义…

计算机网络数据链路层知识总结

物理层知识总结传送门 计算机网络物理层知识点总结-CSDN博客 功能 功能概述 一些基本概念 结点:主机、路由器链路﹔网络中两个结点之间的物理通道&#xff0c;链路的传输介质主要有双绞线、光纤和微波。分为有线链路、无线链路。数据链路︰网络中两个结点之间的逻辑通道&a…

Transformers -- 深入研究 - part 3

公众号:Halo咯咯,欢迎关注~ 前文回顾: Transformers -- 以通俗易懂的方式解释 - Part 1Transformers -- 未知英雄 - Part 2世界正在为人工智能和生成式人工智能而疯狂,特别是 2023 年的 ChatGPT 和大型语言模型。在我们讨论本系列后续部分的技术细节之前,让我们先从它的想…

移植day3

思维导图 重点README文档 1、解压tf-a源码 $> tar xfz tf-a-stm32mp-2.2.r2-r0.tar.gz 2、进入tf-a源码目录 $> cd tf-a-stm32mp-2.2.r2 3、打补丁命令&#xff0c;作用&#xff1a;补丁文件中存放默认的一些配置文件&#xff0c;对于程序员来说&#xff0c;需要将补丁…

【c++初阶】类与对象(下)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

【前端】使用Web Audio API 技术播放音乐

简言 记录下使用web audio播放音乐的方法。 Web Audio API Web Audio API 提供了在 Web 上控制音频的一个非常有效通用的系统&#xff0c;允许开发者来自选音频源&#xff0c;对音频添加特效&#xff0c;使音频可视化&#xff0c;添加空间效果&#xff08;如平移&#xff09…

CUDA从入门到放弃(十三):C++语言扩展 C++ Language Extensions

CUDA从入门到放弃&#xff08;十三&#xff09;&#xff1a;C语言扩展 C Language Extensions 1 Function Execution Space Specifiers 函数执行空间指定符 这些指定符定义函数是在主机还是设备上执行&#xff0c;以及它们是否可以跨平台调用。 1-1 __global__ __global__指…

健身房预约管理系统(源码+文档)

健身房预约管理系统&#xff08;小程序、ios、安卓都可部署&#xff09; 文件包含内容程序简要说明含有功能&#xff1a;项目截图客户端首页我的预约登录教练预约时间我的注册页个人资料课程预约课程预约 管理端订单管理团课管理教练管理分类管理用户管理 文件包含内容 1、搭建…

[数据结构]排序

本篇主要是对常见排序的分类和一些排序的详解 一、插入排序 1.直接插入排序 // 直接插入排序函数 void insertionSort(int arr[], int n) {int i, key, j;for (i 1; i < n; i) {key arr[i]; // 取出待排序的元素j i - 1;// 将大于key的元素向后移动一位while (j > 0…

6.5 Batch Normalization

在训练神经网络时&#xff0c;往往需要标准化&#xff08;normalization&#xff09;输入数据&#xff0c;使得网络的训练更加快速和有效。 然而SGD&#xff08;随机梯度下降&#xff09;等学习算法会在训练中不断改变网络的参数&#xff0c;隐藏层的激活值的分布会因此发生变…

MySQL故障排查与生产环境优化

一、MySQL单实例常见故障 1.逻辑架构图 MySQL逻辑架构图客户端和连接服务核心服务功能存储引擎层数据存储层 2.故障一 故障现象 ERROR 2002 (HY000): Cant connect to local MySQL server through socket/data/mysql/mysql.sock(2) 问题分析 数据库未启动或者数据库端口…

淘宝优惠券去哪里领取隐藏内部券?

淘宝优惠券去哪里领取隐藏内部券&#xff1f; 1、手机安装「草柴」APP&#xff0c;打开手机淘宝挑选要购买的商品&#xff0c;并点击分享复制链接&#xff1b; 2、将复制的商品链接&#xff0c;粘贴到草柴APP&#xff0c;并点击立即查询该商品的优惠券和约返利&#xff1b; 3、…

java题目15:从键盘输入n个数,求这n个数中的最大数与最小数并输出(MaxAndMin15)

每日小语 你是否有资格摆脱身上的枷锁呢&#xff1f;有许多人一旦获得解放&#xff0c;他的最后一点价值也就会跟着丧失。 ——尼采 自己敲写 它不按我想的来。。。 //从键盘输入n个数&#xff0c;求这n个数中的最大数与最小数并输出 import java.util.Scanner; public clas…

软件测评师教程之软件测试基础

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

Mysql数据库:故障分析与配置优化

目录 前言 一、Mysql逻辑架构图 二、Mysql单实例常见故障 1、无法通过套接字连接到本地MySQL服务器 2、用户rootlocalhost访问被拒绝 3、远程连接数据库时连接很慢 4、无法打开以MYI结尾的索引文件 5、超出最大连接错误数量限制 6、连接过多 7、配置文件/etc/my.cnf权…

全栈开发与测试定向培养班

Python全栈开发与测试 什么是软件测试&#xff1f; 对于测试行业来说&#xff0c;行业普遍会把职位分为测试工程师和测试开发工程师两个岗位。软件测试工程师就是常规意义上了解到的功能测试岗位&#xff0c;以功能测试为主,会有少量的自动化测试。测试能力要求&#xff1a;熟…

键盘输入与屏幕输出——单个字符的输入和输出

目录 字符常量 字符型变量 单个字符的输入输出 两种输入输出方法的比较 字符常量 字符常量是用单引号括起来的一个符号 *’3’表示一个数字字符&#xff0c;而3则表示一个整数数值 转义字符&#xff08;Escape Character&#xff09; *一些特殊字符&#xff08;无法从键盘…