模拟散列表(哈希表拉链法)

维护一个集合,支持如下几种操作:

  1. I x,插入一个整数 x;
  2. Q x,询问整数 x 是否在集合中出现过;

现在要进行 N 次操作,对于每个询问操作输出对应的结果。

输入格式

第一行包含整数 N,表示操作数量。

接下来 N 行,每行包含一个操作指令,操作指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤N≤10^5
−10^9≤x≤10^9

输入样例:
5
I 1
I 2
I 3
Q 2
Q 5
输出样例:
Yes
No

思路:要把范围这么大的X存到集合中,直接放进数组不合适,所以就要把大范围映射到小范围------>哈希表

哈希表

本题使用拉链法,也就是哈希表一个位置上有一条链表,用来存取模后映射到小范围上相等的数字(避免冲突),实现两个功能,插入和查找

其中取模要用到这个公式 ,保证结果是正数(哈希表范围从0到N)

 int k=(x%N+N)%N; 

拉链法需要注明的点:

哈希表上每个点对应一条链表,用来存取模后映射到小范围上相等的数字(避免冲突),h[]表示哈希表,h[k]表示哈希表中第k个位置上的值,h[k]存的是它这个位置上对应的链表的头结点下标

看图比较好理解:

插入部分:
void insert(int x)
{
    //h[k]是链表k的第一个元素在e数组中的索引
    
    int k=(x%N+N)%N;   //把它映射为0-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])  //从头结点开始,到-1(没有节点了),i向后遍历
    {
        if(e[i]==x)  //如果在这个哈希表上的某条链表里找到了值
            return true;
    }
    return false;
}

 

puts()函数用来向标准输出设备屏幕输出字符串并换行

示例代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int  N=1e5+10;

int h[N],e[N],ne[N],idx; //h[N]是表,e和ne表示拉链这个链表中的值和下一个点下标

/*h[]是一个整数数组,用于表示哈希表。
h[k]表示哈希表中第k个槽位的值。
当h[k]的值为-1时,表示第k个槽位为空,即对应的链表为空。
当h[k]的值不为-1时,表示第k个槽位存储了链表的头结点下标。它指向链表中第一个元素的位置。
*/

void insert(int x)
{
    //h[k]是链表k的第一个元素在e数组中的索引
    
    int k=(x%N+N)%N;   //把它映射为0-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])  //从头结点开始,到-1(没有节点了),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(find(x)) puts("Yes"); //输出字符串并换行
            else puts("No");
        }
        
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值