acwing基础课——哈希表

由数据范围反推算法复杂度以及算法内容 - AcWing

常用代码模板2——数据结构 - AcWing

基本思想:

        哈希表:也叫做散列表。是根据关键字和值(Key-Value)直接进行访问的数据结构。也就是说,它通过关键字 key 和一个映射函数 Hash(key) 计算出对应的值 value,然后把键值对映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数(散列函数),用于存放记录的数组叫做 哈希表(散列表)。 哈希表的关键思想是使用哈希函数,将键 key 和值 value 映射到对应表的某个区块中。可以将算法思想分为两个部分:

        向哈希表中插入一个关键字:哈希函数决定该关键字的对应值应该存放到表中的哪个区块,并将对应值存放到该区块中
        在哈希表中搜索一个关键字:使用相同的哈希函数从哈希表中查找对应的区块,并在特定的区块搜索该关键字对应的值

        当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。

  • 数组
  • set (集合)
  • map(映射)

        这里y总同样用的数组模拟的,用到了拉链法和开放寻址法两种存储方式。
ps: 下面内容是摘录自代码随想录,仅供个人学习:

在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:

集合 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::set 红黑树 有序 O(log n) O(log n)
std::multiset 红黑树 有序 O(logn) O(logn)
std::unordered_set 哈希表 无序 O(1) O(1)

std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

映射 底层实现 是否有序 数值是否可以重复 能否更改数值 查询效率 增删效率
std::map 红黑树 key有序 key不可重复 key不可修改 O(logn) O(logn)
std::multimap 红黑树 key有序 key可重复 key不可修改 O(log n) O(log n)
std::unordered_map 哈希表 key无序 key不可重复 key不可修改 O(1) O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。

当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。

那么再来看一下map ,在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的。

其他语言例如:java里的HashMap ,TreeMap 都是一样的原理。可以灵活贯通。

虽然std::set、std::multiset 的底层实现是红黑树,不是哈希表,但是std::set、std::multiset 依然使用哈希函数来做映射,只不过底层的符号表使用了红黑树来存储数据,所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。 map也是一样的道理。

840. 模拟散列表 - AcWing题库

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

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

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

输入格式

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

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

输出格式

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

每个结果占一行。

数据范围

1≤N≤1e5
−1e9≤x≤1e9

输入样例:

5
I 1
I 2
I 3
Q 2
Q 5

输出样例:

Yes
No
/*
//拉链法
#include
#include

using namespace std;

//大于1e5的第一个质数 数学知识 可以减小存储的冲突情况
const int N = 100003;
int n;
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()
{
    cin >> n;
    memset(h, -1, sizeof h);
    
    while(n--)
    {
        char op;
        int x;
        cin >> op >> x;
        if(op == 'I') insert(x);
        else
        {
            if(find(x)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
    }
    
    return 0;
}
*/

//开放寻址法
#include
#include

using namespace std;

const int N = 200003;
int n;
int h[N];

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

int main()
{
    cin >> n;
    memset(h, 0x3f, sizeof h);
    
    while(n--)
    {
        char op;
        int x;
        cin >> op >> x;
        if(op == 'I') h[find(x)] = x;
        else
        {
            if(h[find(x)] == 0x3f3f3f3f) cout << "No" << endl;
            else cout << "Yes" << endl;
        }
    }
    
    return 0;
}

例题:

841. 字符串哈希 - AcWing题库

你可能感兴趣的:(acwing算法基础课二刷记录,散列表,数据结构,算法,c++)