Hash(  哈希表    哈希查找  )

Hash表:

定义:

1.哈希表,也称散列表,是一种高效的数据结构。它的最大优点就是把数据存储和查找所消耗的时间

大大降低,几乎可以看成是 O(1)的,而代价是消耗比较多的内存。在当前竞赛可利用内存空间越

来越多、程序运行时间控制的越来越紧的情况下,“以空间换时间”的做法还是值得的。

tips:

1.哈希冲突,不能保证每个元素的关键字与函数值是一 一对应的,这样就产生了“冲突”。

Hash查找:

定义:

1.哈希是hash的音译,也称散列.

2. 哈希查找是一种按关键字编址的快速检索方法.

优势:

1.哈希查找是通过对记录的关键字值进行某种运算,直接求出记录的地址.

2. 快——关键字到地址直接转换,无需反复比较.

3. 核心不在于如何“比较”,而在于如何“计算”.

4. 最能体现计算机科学精髓的查找方法.

基本思想:

举个例子:

 假如说我们需要将1~13存放到拥有5个区间的哈希表里,那么如果画成图就应该是这样的.(用mod对数进行取余(5)进行存放).

 

 大概就是这样一个表,我们只需将1~13依次%填到相应位置就可以了。

但到了这里,同学们就会疑惑:

  1~5正常%就行了,但是6%5=1,而前面1%5也=1,但是一个区间不是只能存放一个数值吗?

  这就是“哈希冲突”.

这里许多人可能想到我们之前讲的——链表.

tips:

  我们可以在这里创建链表,随后依次往后填写就可以了.

 

 

 填好之后就是这样的.

hash查找代码实现:

构造:

1.哈希函数的构造 ·通常情况下,我们用除余法来构造哈希函数.

2.即选择一个适当的正整数b,用其对取模的余数作为哈希值。 ·其关键是b的选取,为了尽量避免.

冲突,一般选为能够存储下并且尽量大的素数(一般情况下我们根据空间取106左右的素数).

3.一般地说,如果b的约数越多,那么冲突.

例题:

模板题:

  哈希构造的链表中查询方式比较快。已知存在一个随机的数据表(表中数字均为正整数,

没有重复),数据个数n≤50000;现在给定一些整数,查询在表中是否存在。

输入格式:

   第一行,1个正整数n表示随机数字个数.

   第二行,n个随机数字.

   第三行,要查询的数字个数m(m≤10000) 第四行,要查询的m个数,空格隔开.

输入样例1:

  10

  23 45 8 9 100 12 5 2 88 21

  3

  34 21 7

输出样例1:

  no

  yes

  no

#include<bits/stdc++.h>
using namespace std;
const int b=10000,H=10000;//哈希取模%数字. 
int t,a[10000],ne[10000],aus[10000];
int pop,st[10000];
void init(){ //初始化哈希表. 
    t=0;
    while(pop) //我们用一个栈存储下出现过的哈希值.
       a[st[pop--]]=0;
}
void insert(int key){ //将一个数字插入哈希表. 
    int h=key%b; //除余法. 
    for(int e=a[h];e;e=ne[e])
       if(aus[e]==key) return; //诺链表中已存在当前数字则不再存. 
    if(!a[h]) st[++pop]=h; //把第1次出现的哈希值入栈.
    ne[++t]=a[h],a[h]=t; //建立链表.
    aus[t]=key; //建立链接表,存储值等于key的数字. 
}
 
bool query(int key){//数组模拟链表. 
    int h=key%b;
    for(int e=a[h];e;e=ne[e]) //查询链接.
       if(aus[e]==key) return true;
    return false;  
} 
 
int main(){ 
    int a[10000];
    init();//初始化. 
    int n,m;
    cin>>n;
    for(int i=1;i<=n;++i) {
        cin>>a[i];
        insert(a[i]);
    }
    cin>>m;
    int num;
    for(int i=1;i<=m;++i){
        cin>>num;
        if(query(num)) printf("yes\n");
        else printf("no\n");
    }
}

字符串hash:

给出一个长度为n的字符串,进行m次询问,每次询问字符串的序列[a,b]和序列[c,d]是否相等 .

输入格式:

第一行1个整数n,为字符串长度.

第二行1个长度为n的字符串.

第三行1个整数m 接下来m行,每行4个以空格分隔的整数a,b,c,d.

输出格式: 对于每个询问,输出一行答案 yes或no.

数据范围:1e4< n,m ≤1e6.

输入样例:

7

asasaaa

4

1 2 3 4

1 2 2 3

1 5 3 7

1 1 7 7

输出样例:

yes

no

no

yes

#include<iostream>
#include<algorithm>
#include<cstring>  
using namespace std;
const int N=1e3+5,MD=1000000007,D=27;
string s; 
int f[N],g[N]; // f 为前缀和,g[i] 为 D 的 i 次方
void prehash(int n){
    f[0] =0; // f 前缀和预处理
    for(int i=1;i<=n;i++) f[i]=(1LL*f[i-1]*D+s[i-1])%MD;
    g[0]=1;
    for(int i=1;i<=n;i++) g[i]=1LL*g[i-1]*D%MD;
}
int hash1(int l, int r){
    int a=f[r];
    int b=1LL*f[l-1]*g[r-l+1]%MD;
    return (a - b + MD) % MD; // 前缀和相减
}
int main(){   
    int n;
    cin>>n>>s;
    prehash(n); //预处理hash表 
    int m;
    cin>>m;
    int a,b,c,d;
    for(int i=1;i<=m;++i){//进行数字判断 
        cin>>a>>b>>c>>d; 
        if(hash1(a,b)==hash1(c,d))
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;    
}

再见!!!


 

Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash Hash