算法:模拟散列表(哈希拉链法,开放选址法)

拉链法:

用数组h[N]来表示拉链法上对应的链,如果遇到冲突则在对应冲突的位置开一个链,创建链的方式和之前单链表的方式相同。如果要插入一个值:

  1. 计算当前值在哈希之后的映射位置int k = (x % N + N) % N;之所以要取两次模,是为了处理负数的模
  2. 将x存储在e[idx]中
  3. 该链表的下一个位置就是当前冲突位置的链表的头,故ne[idx] = h[k];
  4. 当前冲突位置链表的头变为了当前的idxh[k] = idx++;

开放选址法

只需要一个一维数组用来存储。
在插入时遇到冲突,按数组顺序向后查找,直到找到空位置将其插入。
在查找时,从哈希映射的位置开始查找,如果找到这个值,则返回其下标,如果直到当前位置为空时,还没有找到,则说明该值不存在。
取余的数应该是一个质数,并且应该大于题目要求的两倍。

问题描述

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

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

输入格式

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

接下来N行,每行包含一个操作指令,操作指令为”I x”,”Q 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

代码1

// 拉链法
#include
#include
using namespace std;

const int N = 100003;
int h[N], e[N], ne[N], idx = 0;

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 true;
        }
    }
    return false;
}

int main(){
    int m;
    memset(h, -1, sizeof h);
    cin >> m;
    while(m --){
        string s;
        int x;
        cin >> s >> x;
        if(s == "I"){
            insert(x);
        }else{
            if(find(x)){
                cout << "Yes" << endl;
            }else{
                cout << "No" << endl;
            }
        }
    }
    return 0;
}

代码2

#include
#include
using namespace std;

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

int find(int x){
    int k = (x % N + N) % N;
    for(int i = k; ; ++i){
        if(h[i] == null){
            return i;
        }
        if(h[i] == x){
            return i;
        }
    }
    
    return k;
}

int main(){
    int m;
    memset(h, null, sizeof h);
    cin >> m;
    while(m --){
        string s;
        int x;
        cin >> s >> x;
        if(s == "I"){
            int k = find(x);
            h[k] = x;
        }else{
            if(h[find(x)] != null){
                cout << "Yes" << endl;
            }else{
                cout << "No" << endl;
            }
        }
    }
    return 0;
}

原题链接

你可能感兴趣的:(算法,数据结构,c++,散列表,拉链法,开放选址法)