您的位置:首页 > 理论基础 > 数据结构算法

学习笔记10||数据结构||用数组实现哈希表

2020-07-18 04:19 459 查看

哈希表的存储结构

存储结构分为两大类:1、开放寻址法 2、拉链法
哈希表的作用:把一个复杂的数据结构映射到0~n。
常见情景:把0~ 10e9映射到0~10e5。
例题:模拟散列表
l x 插入一个数x
q x x是否出现过
M 0~10e5 N -10e9 ~10e9
1、x%10e5 可以将数放到10e5之内//取模最好取质数,离2的整数次幂越远越好
2、可能存在的冲突,即不同的数字映射到同一个
处理冲突:

1、拉链法:


实现:

#include< iostream>
#include < cstring>//使用到了memset函数
using namespace std;

const int N=10e5+3;//大于100000的第一个质数
//h[]就是开的槽
int h[N];
//下面拉的就是一个链表
int n[N],ne[N],idx;

//插入
void insert(int x){
int k=(x%N+N)%N;//计算映射之后的位置,k是哈希值,+N%N是为了保证是正数。
e[idx]=x,ne[idx]=h[k],h[k]=idx++;
//h[k]中存储的下一个的下标,然后把下一个的下标给ne[idx],然后,h[k]指向idx这个指针。idx++;*在此处要理解h[x]本来就是一个指针,是我们所创建的槽,例如h[11]=3,h[23]=3;*

}

bool find(int x){
int k=(x%N+N)%N;//为了避免出现负数
for(int i=h[k];i!=-1;i=ne[i]){
if(e[i]==x)  return true;
return false;
}
}

int main(){
int n;
scanf("%d",&n);
memset(h,-1,sizeof h)//先把所有的哈希表的槽清空,即所有的槽一开始都指向-1;
while(n--){
char op[2];
int x;
scanf("%s%d",op,&x);
if(op=="I") insert(x);
else if ( op=='I'){
if(find(x)) puts("yes");
else puts("no");
}
}
return 0;
}
相关知识–单链表的插入

e[]:值的大小
ne[]:下个指针的下标,节点i的下一个下标在什么地方,所以可以不按照顺序,有可能7的下个节点的下标是3,这样就实现了插入

用下标来索引节点。
idx:存储当前已经用到了哪个节点,不用担心会冲突,因为链表的创建的时候就要用idx

链表的插入code:

viod insert(int k,int x){
e[idx]=x;
ne[idx]=ne[k];
ne[k]=idx;
idx++;
//首先进行存储,然后把k的next赋值给idx
idx赋值为k的next,就加进去了,然后idx用完之后加一;
}

//在hash表中的插入,相同,此处要注意,单链表只是下面拉出来的那个串,并不是那个hash表,先进行存储,然后变换next指针,这个时候将插入的那个数放在hash表上,然而原来的那个数,变成单链表上的一个节点,就像是在头链表之后插入相同。将原来的hash表上的数放在idx之后,就是ne[idx]=h[k],然后,h[k]=idx;就完成了把idx放入hash表中,而idx的ne就是原本的hash中的数。idx用完之后+1;
存储的都是下标

void add_to_head(int x){
e[idx]=x;
//idx是当前可用的最新的指针是啥
ne[idx]=head;//head就是ne,head就是个指针
head=idx;
idx++;
}

//此处不同是因为head就是一个指针

哈希表拉链表的整体描述:
首先建立哈希表存储的槽,然后将槽所有的位置都指向-1,从第一数开始进行插入。x通过%计算出x在映射之后在hash表中的位置k,然后将e[idx]=x;ne[idx]=h[k];h[k]=idx;idx++;

2、开放寻址法
#include< iostream>
#include < cstring>//使用到了memset函数
using namespace std;

const int N=20e5+3,null=0x3f3f3f3f;//大于200000的第一个质数,null在数据范围之外,作为标志

int h[N];

int find(int x){
int k=(x%N+N)%N;//为了避免出现负数
while(h[k]!=null&&h[k]!=x){//坑位上有人,坑位上不是x
k++;
if(k==N) k=0;//从0开始
}
return k;
}

int main(){
int n;
scanf("%d",&n);
memset(h,ox3f,sizeof h)//先把所有的哈希表的槽清空,即所有的槽一开始都指向-1;
while(n--){
char op[2];
int x;
scanf("%s%d",op,&x);
int k=find(x);
if(op=="I") h[k]=x;
else {
if(h[k]!=null) puts("yes");
else puts("no");

}
}
return 0;
}
字符串哈希方式

字符串前缀哈希法
1、如何定义:看成是p进制的数字,把字符串传化成数字。最后进行取模。
不能映射成0,一般p取131,q取2的64次方经验值保证不冲突
2、好处、可以利用前缀哈希计算所有字段的哈希值

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: