Hash表_拉链法_开放寻址法_模拟散列表

Hash表

一般只有添加、查找

(注意:离散化为特殊的哈希方式,因为离散化需要提前保序)

作用

将一堆数据 通过hash函数映射为 0 ~ N的数

hash函数:x mod N(N一般取质数)

当不同的数映射成一个数时,产生冲突,处理冲突有两种方法。

① 拉链法

(存放下标的数组h初始化为-1)
请添加图片描述

插入

void insert(int x)
{
    int k = (x % N + N) % N;
    e[idx] = x;
    ne[idx] = h[k];
    h[k] = idx ++;
}

注意 :求其余数时,值可正可负(-10 % 3 == -1),需要保证为正数

%N + N ) % N,不可 + N ) % N ,x在-1e+09 ~ 1e+09,N为 10^5,这样无法保证k为正数

查找

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;
} 

② 开放寻址法

当映射时,若该位已有数,则继续向后查找,直至找到空位,存下。

(数组存放的是数值,初始化为无穷大即可,规定一个值 null)
请添加图片描述

//若x存在返回其位置,若x不存在返回其应该在的位置。
int find(int x)
{
    int k = (x % N + N) % N;
    while(h[k] != null && h[k] != x)
    {
        k++;
        if(k = N) k = 0;    //k到最后一个,则从头循环
    }
    return k;
}
  • h[k] == x 时:说明已存在x,返回其位置即可。

  • h[k] == null 时:说明不存在x,返回其应该在的位置。注意后续需要将x填入。

例 - 模拟散列表

请添加图片描述

> 拉链法

#include <iostream>
#include <cstring>
using namespace std;

const int N = 200003;
int h[N];

void insert(int x)
{
    int k = (x % N + N) % N;
    e[idx] = x;
    ne[idx] = h[k];
    h[k] = idx;
    idx ++;
}

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()
{
    memset(h,-1,sizeof h );
    int n,x;
    scanf("%d",&n);
    char op[2];
    while(n--)
    {
        scanf("%s",op);
        if(op[0] == 'I')
        {
            scanf("%d",&x);
            insert(x);
        }
        else
        {
            scanf("%d",&x);
            if(!find(x)) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}

> 开放寻址法

#include <iostream>
#include <cstring>
using namespace std;

const int N = 200003;
const int null = 0x3f3f3f3f;
int h[N];


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


int main()
{
    memset(h,0x3f,sizeof h );
    int n,x;
    scanf("%d",&n);
    char op[2];
    while(n--)
    {
        scanf("%s",op);
        if(op[0] == 'I')
        {
            scanf("%d",&x);
            h[find(x)] = x;
        }
        else
        {
            scanf("%d",&x);
            if(h[find(x)] == null) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}

注意:

以上两种方法h[k]代表的含义不同

拉链法:映射到k的数的下标 idx

开放寻址法:映射到k的数(k可能为负数,数组初始化时)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值