2022-11-17 Acwing每日一题

本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的。同时也希望文章能够让你有所收获,与君共勉!

今晚太晚了,就少些一点算了。

模拟散列表

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

I x,插入一个数 x;
Q x,询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果。

输入格式
第一行包含整数 N,表示操作数量。

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

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

每个结果占一行。

数据范围
1≤N≤105
−109≤x≤109
输入样例:

5
I 1
I 2
I 3
Q 2
Q 5

输出样例:

Yes
No

算法原理

简单的讲一下哈希表是用来干什么的吧。哈希表主要是用来记录一个数它出现的次数,能够以较快的时间在集合中找到它,那么为什么会这样呢,主要是因为哈希表建立了一种映射关系将值给映射到某一段较小的区间内,每一个值都对应的一个键,这个键就能帮助我们在这个区间里较快的找对存储的值,但是有一个问题就是这样的映射关系很容易重复,即容易产生哈希冲突,而解决哈希冲突的办法有很多,这里主要介绍开放寻址和拉链法。
需要注意开放寻址法哈希表的初始值为null = 0x3f3f3f3f,不是0哦,而拉链法的哈希表初始值-1,不要忘记memset

开放寻址法

先来看开放寻址法怎么实现。主要思路就是给定一个数x,通过加一个特别大的数再取余数转换成对应的键(x%N+N)%N,在哈希表中找没人(数字)占的地方插入就行,如果这个地方被人插入过,那么就需要寻找没有被插入过的地方,具体代码实现如下。

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

拉链法

用链表e来当作哈希表h的数据结构,经过(x%N+N)%N的映射后的值如果为t,则在哈希表下标t处存入链表头,也就是说哈希表上的每一个位置都连有一个链表,我们可以想象到当数据特别多时,如果出现哈希冲突,我们就可以往链表上添加元素。

// 向哈希表该节点插入一个数
void insert(int x){
	int k  = (x%N+N)%N;
	e[idx] = x;
	ne[idx] = h[k];
	h[k] = 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 ture;
		}
	}
	return false;
}

代码实现

开放寻址法

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200003,null = 0x3f3f3f3f;
int h[N];   // 厕所哦
int n;

int find(int x){
    int t = (x%N+N)%N;
    while(h[t]!=null && h[t]!=x){
        t++;
        if(t == N) t = 0;
    }
    return t;   // 如果存在返回x的厕所编号,不存在就返回要上厕所的编号
}

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

拉链法

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+3;
int h[N];   
int n;
int e[N],ne[N],idx = 0;

bool find(int x){
    int t = (x%N+N)%N;
    for(int i=h[t] ; i != -1 ; i = ne[i]){
        if(e[i] == x)
            return true;
    }
    return false;
}

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


int main()
{
    cin >> n;
    memset(h,-1,sizeof h);
    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;
}
posted @ 2022-11-18 00:50  ZmQmZa  阅读(21)  评论(0编辑  收藏  举报