哈希表模板--两种实现方式

哈希表分为开放寻址法拉链法。时间复杂度近似o(1),一般仅进行添加和查找,一般不删除(用数组标记)。

作用是使较大的定义域 映射到一个较小范围的集合

离散化是一种保持有序性的特殊哈希。

  • x mod 10^5(目标小集合长度,取质数冲突概率小)
  • 冲突处理

拉链法:用邻接表存储,把e[N]拆成很多个链表。

开放寻址法:仅一个数组,但长度比输入长度(目标小集合)大2,3倍。上厕所找坑位一样,插入时先取模得映射下标k,察看k处是否为空,为空插入,否则k++直到找到空位。查询时find 取模得下标k,查看k处是否为目标x,不为空但不是x则k++,为空则x不存在,不为空为x则true。

例题 : https://www.acwing.com/problem/content/842/

拉链法

#include <iostream>
#include <cstring>
using namespace std;
 
 
//拉链法
//开槽范围只需要比输入范围大且最好是质数
const int N=100003;
//h[N]是开的槽位,后三个就是单链表的内容
int h[N],e[N],ne[N],idx; 

void insert(int x){
    int k=(x % N + N) % N;
    e[idx]=x;
    ne[idx]=h[k]; //头插,h[k] 为head,先将新结点指向head所在结点,再将head指向新结点
    h[k]=idx++;
}

bool find(int x){
    int k=(x % N + N) % N;
    //遍历凹槽位置的单链表,找到x就返回true
    for(int i=h[k];i!=-1;i=ne[i]){
        if(e[i] == x)
            return true;
    }
    return false;
}

int main(){
    int n;
    cin>>n;
    memset(h,-1,sizeof(h));
    while(n--){
        string op;
        int x;
        cin>>op>>x;
        if(op=="I") insert(x);
        else{
            if(find(x)) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}


开放寻址法:

#include<cstring>
#include<iostream>

using namespace std;

//开放寻址法
//N取输入数据范围的2,3倍以上,最好是质数可以减少冲突
//null 是定义域之外的数来标记为空
const int N=200003,null =0x3f3f3f3f;
int h[N]; //定义凹槽

int find(int x){
    int t=(x % N + N)%N;
    while(h[t]!=null && h[t]!=x){ //寻找空位 or找x下标
        t++;
        if(t==N) t=0;
    }
    return t; //返回凹槽下标
}

int main(){
    memset(h,0x3f,sizeof h);//按字节赋值,int 4字节
    int n;
    cin>>n;
    while(n--){
        string op;
        int x;
        cin>>op>>x;
        if(op == "I") h[find(x)]=x;
        else{
            if(h[find(x)]==null) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}


posted @ 2022-01-20 16:35  秋月桐  阅读(119)  评论(0编辑  收藏  举报