算法学习系列(十七):哈希表

目录

  • 引言
  • 一、哈希表概念
  • 二、代码实现
    • 1.开放寻址法
    • 2.拉链法

引言

这个哈希还是很重要的一个概念,我觉得本质上就是一个映射,然后只要你以后干计算机,这个概念都是非常常见并重要的一个概念,之前搞得离散化其实就是哈希表的一种,所以得好好学并且理解啊,那就开始吧。

一、哈希表概念

  • 为什么要用哈希表:主要是快,时间复杂度为O(1),这个哈希表的主要功能就是查找一个数,看这个数在不在当前的集合里,所要的操作就是插入和查找了。
  • 实现方式:一般就是创建一个数组,将这个数通过哈希函数变为一个数,这个数是作为数组的下标,然后就可以通过下标的方式来快速判断这个数了。
  • 哈希函数:一般算法题里就是 mod 所需要用到数的数量最大并且多几个数,并且这个数尽量是质数,并且尽量离2的次幂远一些。当然 mod 后的结果是会有几个数是相同的,比如说所用到的数最大是1e5,哈希函数为 mod 1e5+3,那么1和1e5+4的哈希函数结果是相同的,这也就是所谓的哈希冲突(哈希碰撞)了,所以需要中方式来解决。
  • 如何解决哈希冲突:
    开放寻址法:就是把数组大小开成所需要用到的数的数量的2~3倍,然后如果通过哈希函数后所在的下标有数,那就i++,找下一个没有用到的下标,再填进去。查找的话也是类似的,通过哈希函数找到下标,然后i++依次找。
    拉链法:就是数组大小还是用到的数的数量的最大,然后相当于每个数组的位置都是一个单链表的头结点,来一个数就插到对应哈希函数映射到的那条单链表里去,类似于如下图所示。查找的话就是通过哈希函数找到下标,再遍历单链表就可以了,这个单链表的长度可以看成是一个常数,所以也是O(1)的。
    算法学习系列(十七):哈希表_第1张图片

二、代码实现

当然这种东西还是拿题目来说会比较好。

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

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 
#include 

using namespace std;

const int N = 200003, null = 0x3f3f3f3f;  //开2倍,并且是质数  确定一个null值

int h[N];
int n;

int find(int x)  // 查找x对应的下标
{
    int k = (x % N + N) % N;  // 因为有可能是负数

    while(h[k] != null && h[k] !=x)  // 遇到空或者找到了会停下来
    {
        k++;
        if(k == N) k = 0;  // 找到了末尾,那就从0开始
    }

    return k;
}

int main()
{
    scanf("%d", &n);

    memset(h, 0x3f, sizeof h);  // 都先置为null

    while(n--)
    {
        char op[2];
        int x;

        scanf("%s%d", op, &x);

        int k = find(x);
        if(*op == 'I') h[k] = x;
        else
        {
            if(h[k] != null) puts("Yes");
            else puts("No");
        }
    }

    return 0;
}

2.拉链法

#include 
#include 
#include 

using namespace std;

const int N = 100003;

int h[N], e[N], ne[N], idx;

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 n;
    scanf("%d", &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;
}

你可能感兴趣的:(算法,算法,散列表,学习)