学习笔记10||数据结构||用数组实现哈希表
哈希表的存储结构
存储结构分为两大类: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、好处、可以利用前缀哈希计算所有字段的哈希值
- 【C++数据结构学习笔记---线性表】用数组实现线性表
- 学习数据结构笔记--顺序表的数组实现
- 数据结构学习笔记10——区分叶结点与分支结点的二叉树实现方案二
- 【C++数据结构学习笔记---栈】用数组实现栈
- (二)数据结构学习笔记 简单堆栈,STL中堆栈的实现
- 【C Prime Plus】学习笔记,Chapter 10,数组和指针之二
- 数据结构学习笔记——数组与矩阵压缩
- 数据结构学习笔记之链表分析与实现(一)
- 数据结构学习笔记--(2)数组
- python数据结构学习笔记-3-数组
- c#学习笔记之五 C与C#在几种主要数据结构在上区别 数组和枚举
- 【C Prime Plus】学习笔记,Chapter 10,数组和指针之一
- 数据结构学习笔记-平衡二叉树实现
- 数据结构与算法学习笔记——链表部分实现(数组形式)
- Java基础学习笔记 -- 10(数组排序)
- (原创)c#学习笔记10--定义类成员03--接口的实现02--用非公共的可访问性添加属性存取器
- python数据结构学习笔记-2016-10-27-02-使用单链表实现包ADT
- 数据结构与基本算法的学习笔记-数组-3
- sizzle.js学习笔记利用闭包模拟实现数据结构:字典(Map)
- 【C Prime Plus】学习笔记,Chapter 10,数组和指针之五