算法刷题笔记 模拟散列表(C++实现)

67 篇文章 3 订阅
61 篇文章 1 订阅

题目描述

  • 维护一个集合,支持如下几种操作:
    • I x,插入一个整数x
    • Q x,询问整数x是否在集合中出现过;
  • 现在要进行N次操作,对于每个询问操作输出对应的结果。

输入格式

  • 第一行包含整数N,表示操作数量。
  • 接下来N行,每行包含一个操作指令,操作指令为I xQ x中的一种。

输出格式

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

数据范围

  • 1 ≤ N ≤ 10^5

  • −10^9 ≤ x ≤ 10^9

基本思路

  • 哈希表是一种常用的数据结构,用于将一个较大的值域映射到一个较小的值域方便存储。
  • 哈希表采用的映射方式不同,由具体的哈希函数确定。最简单的哈希函数即为取模运算,这种情况下要求取模的数字要是素数,并且离2的幂次数要尽可能远,这样才能最大程度避免哈希冲突。
  • 哈希冲突是指原先值域上的不同数据都映射到哈希表中的同一个单元中。处理哈希冲突的方式一般有两种,这两种方法都非常常用,分别是拉链法和开放寻址法。相对而言,拉链法的代码更加复杂,因为需要定义额外的数组;开放寻址法的代码较为简单,但是需要更大的存储空间,因为开放寻址法的哈希表大小要是值域大小的2-3倍。
    • 拉链法:哈希表中的每一个单元都是一个链表。如果某次添加新元素时发现该元素对应的哈希表单元已经有其他元素了,则将该元素的结点作为当前哈希表中该元素的链表的尾结点插入。 在进行查询时,会先找到该链表,再逐一查找该链表中的每一个元素。
    • 开放寻址法:如果添加新元素时发现该元素对应的哈希表单元已经有其他元素了,则看该单元的后面一个单元是否有其他元素,如果没有的话则占据该单元,否则继续向前查看(查看到哈希表末尾还没有找到空单元时,则从哈希表的表头开始继续遍历)。在进行查找时,如果原本该元素应该存放的单元没有找到该元素,则逐一查看哈希表的下一个单元,直到找到该元素。

实现代码

  • 下面的代码采用开放寻址法进行实现:
#include <iostream>
using namespace std;

// 分别表示操作的总数和每一次的操作数
int n, x;
// 每一次的操作类型
char operation;

// 设置哈希表的大小(一般是哈希表值域大小后的第一个素数)
const int N = 200003;
int hash_table[N];

// 向哈希表中插入一个元素的函数
void insert2set(int x)
{
    int position = (x % N + N) % N;
    while(hash_table[position] != 2e9)
    {
        ++ position;
        if(position >= N) position = 0;
    }
    hash_table[position] = x;
}

// 查询哈希表中是否存在该元素的函数
void query(int x)
{
    int position = (x % N + N) % N;
    while(hash_table[position] != x && hash_table[position] != 2e9)
    {
        ++ position;
        if(position >= N) position = 0;
    }
    if(hash_table[position] == x) cout << "Yes" << endl;
    else if(hash_table[position] == 2e9) cout << "No" << endl;
}

int main(void)
{
    scanf("%d", &n);
    // 初始化哈希表
    for(int i = 0; i < N; ++ i) hash_table[i] = 2e9;
    // 输入操作部分
    for(int i = 0; i < n; ++ i)
    {
        cin >> operation >> x;
        if(operation == 'I') insert2set(x);
        else if(operation == 'Q') query(x);
    }
    return 0;
}
  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值