【c++提高1】数据结构之哈希表

本文深入探讨哈希表的存储方式,包括哈希冲突的处理,详细介绍了拉链法和开放寻址法两种解决冲突的方法。同时,讨论了哈希表在散射表中的应用以及字符串哈希的实现,提供了具体的代码示例和解决哈希冲突的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大纲

1.哈希表存储方式
2.哈希表应用:散射表
3.哈希表变形:字符串哈希
4.例题

1.哈希表存储方式

(1)主要思想

哈希表的主要思想是将一个大空间,映射到一个系统可以承受的小空间,一般是映射为0~N。
一般常见的是将0 ~ 1e9映射成0 ~ 1e5,1e9的空间肯定是会爆的吧。
说实话很像离散化

(2)哈希冲突

哈希表的核心是一个哈希函数f(x),对于一个数字x(0 ~ 1e9),映射为y(0~1e5)。

实现:

方法1:取模
直接将x对1e5取模即可。
常见问题:

哈希冲突

哈希冲突:将两个不同的数映射成了同一个数。
比如:10和1e6,1e6 mod 1e5 = 10, 10 mod 1e5 = 10, 哈希函数值相同

所以需要找到一种更好的函数解决哈希冲突这个问题。

(3)哈希正确实现方法1
实现方法:拉链法

用一个1e5的一维数组,来存储哈希值。

哈希冲突解决方式:当把一个x映射到某一个数的时候,将mod的结果(y)的下面拉一条链x。
这样如果有两个哈希值冲突的话,就会把这两个值都拉一条链。这个链可以使用单链表实现,每次在查找x的时候就在hash[y]下面的链找一遍看看有没有x。

取模的数最好的数是一个质数并且离2的整数幂远,这个在数学上是可以推到出来的,在这里不多说了。
题目如果有负数的话有两种应对办法:

1.开两个哈希表(负数,正数)。
2.小技巧:(x%mod+mod)%mod

拉链法实现:
步骤0:定义链表,并初始化。

const int maxn=1e5+3;   //10003是1e5上最小的质数 
int h[maxn],e[maxn],ne[maxn],idx;
void init(){
   
   
	memset(h,-1,sizeof(h));
}

步骤1:对x加入hash
得到x对应的f(x),并且通过链表拉条链x。

void add(int x){
   
   
	int k=(x%maxn+maxn)%maxn;
	e[idx]=x;          //加一条链 
	ne[idx]=h[k];
	h[k]=idx++;
}

步骤2:查询x是否在hash里
得到对应的f(x),并且遍历hash[f(x)]的链,查询是否存在x。

bool find(int x){
   
   
	int k=(x%maxn+maxn)%maxn;
	for(int i=h[k];~i;i=ne[i])
		if(e[i]==x)return 1;
	return 0;
}
(4)哈希正确实现方法2
实现方法:开放寻址法

哈希冲突解决方法:
首先数组需要开到2~3倍。
设f(x)=y,那么首先看hash[y]是否已经有hash值了,如果是,就往后移动一格,重复操作1,直到hash[z]没有hash值了,就存入x

首先初始化为一个不可能的值,接下俩就可以一个while循环判断当前hash[i]位置是否有hash值,一直往后移模拟即可。

开放寻址法代码实现:

步骤0:初始化为0x3f3f3f3f

const int maxn=2e5+3;    //同
int h[maxn];
void init(){
   
   
	memset(h,0x3f,sizeof(h));
}

步骤1:find(x)函数,如果hash[f(x)]没有值,就直接返回f(x)即可,否则返回后面第一个没有hash值的位置。
注意:在判断的时候还需要判断当前位置不为x,x有可能以前存在过,就别让它在跑下去了。

int find(int x){
   
   
	int k=(x%maxn+maxn)%maxn;
	while(h[k]!=0x3f3f3f3f&&h[k]!=x){
   
   
		k++;
		if(k==maxn) k=0;
	}
	return k;
}

没有步骤2了

2.哈希表应用散射表

hash-散射表
题意:

一个集合。
操作1:将x加入集合
操作2:问x是否存在于集合中。

两种方法直接用即可。
拉链法:

/*
拉链法
*/
#include<bits/stdc++.h>
#define FOR(x,y,z) for(int x=y,x_=z;x<=x_;x++)
#define DOR(x,y,z) for(int x=y,x_=z;x>=x_;x--)
#define ll long long
using namespace std;
void read(int& x){
   
   
	char c;x=0;
	int f=1;
	while(c=getchar(),c<'0'||c>'9')if(c=='-')f=-1;
	do x=(x<<3)+(x<<1)+(c^48);
	while(c=
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

{∞}

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值