哈希表(散列表)
作者:互联网
散列表(哈希表)
哈希表也叫散列表,哈希表是一种数据结构,它提供了快速的插入操作和查找操作,无论哈希表总中有多少条数据,插入和查找的时间复杂度都是为O(1),因为哈希表的查找速度非常快,所以在很多程序中都有使用哈希表,例如拼音检查器。这里先说一下哈希(hash)表的定义:哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过关键码映射的位置去寻找存放值的地方。
将关键码映射为散列表中适当存储位置的函数称为散列函数(哈希函数),所得的存储位置称为散列地址(hash address)。
由于hash的特性,导致有可能存在两个不相同的元素a和b要存放到同一位置,这种现象叫做冲突,也称碰撞,a和b相对于hash函数称作同义词。
要考虑的问题
1.hash函数的设计。设计简单,均匀,随机,利用率高的hash函数
2.冲突 的处理。如何采取合理方式解决冲突。
设计散列函数
下面介绍三种常见的散列函数设计:
直接定址法
直接定址法的散列函数是关键码的线性函数,
H
(
k
e
y
)
=
a
∗
k
e
y
+
b
H(key)=a*key+b
H(key)=a∗key+b
特点:不会产生冲突,适用于事先知道关键码的分布,关键码集合不是很大且连续性好的情况。
除留余数法
选择某个适当的正整数p
,以关键码除以p
的余数作为散列地址:
H
(
k
e
y
)
=
(
k
e
y
)
m
o
d
(
p
)
H(key)=(key)mod(p)
H(key)=(key)mod(p)
这个方法关键在于选出合适的p
,否则容易出现冲突。一般情况下,选择p
为小于或等于表长的最大素数或不包含小于20 质因子 的合数。
平方取中法
对关键码平方后,取中间的若干位
适用于不知道关键码的分布,且关键码位数不是很大 的情况。
处理冲突的方法
开放寻址法
如果由关键码得到的散列地址发生了冲突,通过
H
(
k
e
y
)
=
(
H
(
k
e
y
)
+
d
i
)
m
o
d
(
m
)
H(key)=(H(key)+d_i) mod (m)
H(key)=(H(key)+di)mod(m)寻找下一个空的散列地址。
拉链法
将所有散列地址相同的记录存储在一个单链表中,散列表中存储的是所有同义词子表的头指针。
维护一个集合,支持如下几种操作:
I x,插入一个数 x;
Q x,询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果。
输入格式
第一行包含整数 N,表示操作数量。
接下来 N 行,每行包含一个操作指令,操作指令为 I x,Q x 中的一种。
输出格式
对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No。
每个结果占一行。
数据范围
1≤N≤105
−109≤x≤109
输入样例:
5
I 1
I 2
I 3
Q 2
Q 5
输出样例:
Yes
No
#include<iostream>
#include<cstring>
using namespace std;
const int N=100003;
int x,t;
int e[N],h[N],ne[N],idx;
void insert(int x)
{
int u=(x%N+N)%N;
e[idx]=x;
ne[idx]=h[u];
h[u]=idx++;
}
bool quary(int x)
{
int u=(x%N+N)%N;
for(int i=h[u];i!=-1;i=ne[i])
{
if(e[i]==x)return true;
}
return false;
}
int main()
{
char op[2];
memset(h,-1,4*N);
scanf("%d",&t);
while(t--)
{
scanf("%s%d",op,&x);
if(*op=='I')insert(x);
else printf(quary(x)?"Yes\n":"No\n");
}
}
标签:hash,哈希,关键码,int,列表,key,散列 来源: https://blog.csdn.net/qq_52841268/article/details/120095581