【数据结构】哈希表(算法比赛向)

这篇具有很好参考价值的文章主要介绍了【数据结构】哈希表(算法比赛向)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一:介绍

一:什么是哈希表

二、哈希表的应用

二:存储结构

a.拉链法:

b.开放寻址法:

三:扩展

a.字符串哈希:

例题: 


 文章来源地址https://www.toymoban.com/news/detail-425080.html

 

一:介绍

一:什么是哈希表


1、哈希表也叫散列表,哈希表是一种数据结构,它提供了快速的插入操作和查找操作,无论哈希表总中有多少条数据,插入和查找的时间复杂度都是为O(1),因为哈希表的查找速度非常快,所以在很多程序中都有使用哈希表,例如拼音检查器。

2、哈希表也有自己的缺点,哈希表是基于数组的,我们知道数组创建后扩容成本比较高,所以当哈希表被填满时,性能下降的比较严重。

3、哈希表是由链表和数组组成的:

        链表:增删的效率极高,但是查询的效率极低。

        数组:查询效率极高,增删效率低

        所以哈希表中继承了链表和数组的优缺点,不仅查询效率高,增删效率也高

4、哈希表通过键值对的方式存储数据,【key,value】,哈希表会通过散列函数/哈希函数将key转换成对应的数组下标。【采用 先绝对值再% 的方式】

二、哈希表的应用

    通常数据都是放在数据库中的,但是有一些数据不需要存放在数据库中 ,太麻烦,那么就需要我们使用缓存层
        缓存层一般有俩种:

            缓存产品或者自己写一个缓存层(也就是哈希表)

通过一个列子自己构建出哈希表:

看一个实际需求,google公司的一个上机题:

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址..),当输入该员工的id时,要求查找到该员工的 所有信息.

要求: 不使用数据库,尽量节省内存,速度越快越好

思路:

        1、首先要求不使用数据库,那么是能用一些缓存产品用来存储数据,所以需要构建一个哈希表

        2、哈希表有数组,链表组成。在链表中保存员工数据信息,数组中保存链表
 

二:存储结构

哈希表的最主要作用是将一个比较大的范围(如10^9)映射到一个比较小的空间(0 ~ N,其中N一般为10^5 - 10^6),通过一个哈希函数h(x)完成上述操作。

这里很容易产生哈希冲突,可能会把若干不同的数映射为同一个数。处理冲突的方法有两种:开放寻址法和拉链法。

a.拉链法:

开辟一个10^5大小的空间,每个空间相当于一个槽,每次映射到某个位置就在下面连接一条链。

其实就是单链表的存储方式。

拉链法是把所有的同义词用单链表链接起来的方法。在这种方法中,哈希表的每个单元存储的不再是元素本身,而是相应同义词单链表的头指针(注意是头指针而不是头节点)。

对于单链表,我们算法比赛可以采用数组的方式进行实现。
 

(1) 拉链法

    #include <iostream>
    #include <cstring>
 
    using namespace std;
 
    const int N = 100003;
    int n;
    int h[N], e[N], ne[N], idx;

    // 向哈希表中插入一个数
    void insert(int x)
    {
        int k = (x % N + N) % N;   //哈希函数。这里防止k为负数且映射到小范围
        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(){
    scanf("%d", &n);
    // 初始化链表(链表中-1代表NULL)
    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");
        }
    }
}

 

b.开放寻址法:

找厕所坑位

 


(2) 开放寻址法
#include <iostream>
#include <cstring>
 
using namespace std;
 
// 约定一个null值作为标准,如果h数组上的某个位置等于这个标准的话,就说明这个位置是空的
// 要求这个数不在 -10^9 <= x <= 10^9 范围内即可
const int N = 200003, null = 0x3f3f3f3f;
int n;
int h[N];
 
int find(int x){
    int k = (x % N + N) % N;
    // 该位置有人且值不为x,就要向后看
    while(h[k] != null && h[k] != x){
        k++;
        if(k == N) k = 0;
    }
    return k;
}
 
int main(){
    scanf("%d", &n);
    memset(h, 0x3f, sizeof h);
    
    while(n--){
        char op[2];
        int x;
        scanf("%s %d", op, &x);
        if(*op == 'I') h[find(x)] = x;
        else{
            if(h[find(x)] == null) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}

memset函数解释

三:扩展

a.字符串哈希:

当key为字符串时,h(key)称为字符串哈希。

将字符串看成一个p进制的数,将它转化为十进制数再对Q取模,即可得到一个映射到0-Q范围内的数

  1. 不能将字符映射成0:例如将"A"映射成0,则"AA","AAA"的值均为零。所以应当从1开始

  2. 经验值:p=131 ||   13331,Q=2^64时几乎没有冲突  //利用 unsigned long long,它的大小就是2^64,这样我们就无需进行取模的操作了,因为它溢出后就相当于帮我们取模了。

 

我们可以通过求前缀哈希,通过某一个公式求出任意子串的哈希值:

string:      _______|__________|__________
           高位      L          R        低位
现在已知h[R]和h[L - 1]
我们有:
h[R]    =  p^R-1 * "_" + p^R-2 * "_" + ... + p^0 * "_"
h[L - 1] = p^L-2 * "_" + p^L-3 * "_" + ... + p^0 * "_"
容易知道只需:h[R] - h[L - 1]*p^(R - L + 1)
就能求得L-R间子串的哈希值
同时由上面的字符串哈希的定义,有:
h[i] = h[i - 1]*p + str[i];

 

例题: 

AcWing 841.字符串哈希 

给定一个长度为n的字符串,再给定m个询问,每个询问包含四个整数l1,r1,l2,r2,请你判断[l1,r1]和[l2,r2]这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。

输入格式
第一行包含整数n和m,表示字符串长度和询问次数。

第二行包含一个长度为n的字符串,字符串中只包含大小写英文字母和数字。

接下来m行,每行包含四个整数l1,r1,l2,r2,表示一次询问所涉及的两个区间。

注意,字符串的位置从1开始编号。

输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出“Yes”,否则输出“No”。

每个结果占一行。

数据范围
1≤n,m≤105
输入样例:
8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:
Yes
No
Yes

#include <iostream>
 
using namespace std;
 
typedef unsigned long long ULL;
 
const int N = 100010, P = 131;
int n, m;
char str[N];
ULL p[N], h[N];
 
ULL find(int l, int r){
    return h[r] - h[l - 1] * p[r - l + 1];
}
 
int main(){
    scanf("%d %d", &n, &m);
    // str从str[1]开始填入数据,因为h[i] = h[i - 1]*p + str[i]、h[0] = 0
    scanf("%s", str + 1);
    
    p[0] = 1;
    for(int i = 1; i <= n; i++){
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + str[i];
    }
    
    while(m--){
        int l1, r1, l2, r2;
        scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
        if(find(l1, r1) == find(l2, r2)) puts("Yes");
        else puts("No");
    }
    return 0;
}

 

 

 

 

 

 

到了这里,关于【数据结构】哈希表(算法比赛向)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构算法设计——哈希表(散列表)

            哈希表 又叫 散列表 ,他们两个是同一个东西,本文全文采用“散列表”的叫法。散列表的本质其实就是一个 数组 ,他的作用就像使用数组时一样,输入下标可以得到对应元素,散列表可以实现 输入一个的时候得到这个的地址信息 。 下面是百科给出

    2024年02月03日
    浏览(46)
  • 【数据结构与算法——TypeScript】哈希表

    哈希表介绍和特性 哈希表是一种非常重要的数据结构,但是很多学习编程的人一直搞不懂哈希表到底是如何实现的。 在这一章节中,我门就一点点来实现一个自己的哈希表。 通过实现来理解哈希表背后的原理和它的优势。 几乎所有的编程语言都有直接或者间接的应用这种数

    2024年02月13日
    浏览(30)
  • 数据结构与算法 | 哈希表(Hash Table)

    在二分搜索中提到了在有序集合中查询某个特定元素的时候,通过折半的方式进行搜索是一种很高效的算法。那能否根据特征直接定位元素,而非折半去查找?哈希表(Hash Table),也称为散列表,就是一种数据结构,用于实现键-值对的映射关系。它通过将键映射到特定的值

    2024年02月06日
    浏览(33)
  • 算法数据结构基础——哈希表(Hash Table)

    哈希表(Hash Table) :也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。 哈希表通过「键 key 」和「映射函数 Hash(key) 」计算出对应的「值 value 」,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做「哈希函数(散列函数

    2024年02月13日
    浏览(28)
  • Python篇——数据结构与算法(第六部分:哈希表)

      目录 1、直接寻址表 2、直接寻址表缺点 3、哈希 4、哈希表 5、解决哈希冲突 6、拉链法 7、常见哈希函数 8、哈希表的实现 8.1迭代器iter()和__iter__ 8.2str()和repr() 8.3代码实现哈希表 8.4哈希表的应用   直接寻址表:key为k的元素放到k的位置上 改进直接寻址表:哈希(

    2024年02月10日
    浏览(32)
  • 【数据结构与算法】04 哈希表 / 散列表 (哈希函数、哈希冲突、链地址法、开放地址法、SHA256)

    一种很好用,很高效,又一学就会的数据结构,你确定不看看? 莫慌,每个概念都很好理解。 哈希表( Hash Table ),也称为 散列表 ,是一种数据结构, 用于存储键值对(key-value pairs) 。 键值对是一种数据结构,用于将键(key)与对应的值(value)相关联。在键值对中,键

    2024年02月09日
    浏览(59)
  • 【数据结构与算法】哈希表设计(C\C++)

    针对某个集体中人名设计一个哈希表,使得平均查找长度不超过R,并完成相应的建表和查找程序。 假设人名为中国人姓名的汉语拼音形式。待填入哈希表的人名共有30个,取平均查找长度的上限为2。哈希函数用除留余数法构造。用伪随机探测再散列法处理冲突。 取读者周围

    2024年02月04日
    浏览(37)
  • 数据结构(五):哈希表及面试常考的算法

    哈希表,也叫散列表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。例如,下列键(key)为人名,value为性别。 数组 map(映射) 映射 底层实现 是否有序 数值是否可以重复 能否更改数

    2024年02月05日
    浏览(34)
  • 【Java程序员面试专栏 数据结构】四 高频面试算法题:哈希表

    一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,一个O(1)查找的利器哈希表,所以放到一篇Blog中集中练习 题目 解题思路 时间 空间 两数之和 辅助哈希 使用map存储出现过的值,key为值大小,v

    2024年02月22日
    浏览(41)
  • AcWing 算法基础课二 数据结构 链表 栈 队列 并查集 哈希表

    链表题目:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 AcWing. 826.单链表 双链表 AcWing 827.双链表 AcWing 828.模拟栈 AcWing 3302.表达式求值 AcWing 829. 模拟队列 AcWing 830.单调栈 AcWing 154.滑动窗口 AcWing 831. KMP字符串 AcWing 835. Trie字符串统计 AcWing 143. 最大异或对 AcWing 836.合并集合

    2024年02月15日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包