【数据结构详解】哈希表Hash

什么是Hash

Hash就像是一个桶排,那只不过是把各个元素的数值当做下标进行存储.其最常用的用途就是用来判重.但是,如何对字符串进行判重,不可能一个一个往前超,若n上万则显然不可行.我们可以选择进行Hash,将每一个字符串或者大数字进行一定的操作即可进行.


对大整数类型进行Hash

取模法

对于每一个大整数进行取模,即除以一个大质数(例如107,10007,1000007,1-奇数个0-7),这样就作为数组的下标进行存储了.

为什么要对一个大整数取模

emmmmmm……经众多数学家证明重复的几率较小

万一实在有不可避免的误差/出题人卡你怎么办

有两种方法:
1.线性探测开拓地址法
2.拉链法


对字符串进行Hash

对字符串,我们可以选择按权展开法进行实现.
例如:对于字符abc,我们可以转换成26进制,即:1*26^0+2*26^1+3*26^2,很好理解吧
例如,对于字符串3gT,我们可以转换成某个质数进制即可.
但是,不要忘了,在按权展开的时候需要对一个大整数取模

如何避免字符串Hash的误差

同样:
1.线性探测开拓地址法
2.拉链法


线性探测开拓地址法

若hash[k]已经被填入,则尝试填写hash[k+1],hash[k+2]….等数组.最后在查找的时候也逐一查找即可.但毕竟查找不方便,个人更加偏向于拉链发


拉链法

跟据每一个数值的下标扩充一个链表,每次在链表上逐一查找即可.
为了方便实现,我们可以选用STL中的vector(即动态数组或不定长数组)来代替链表,这样也十分容易实现.


整数Hash实例:不重复数字【JLOI2011】

题目描述
给出N个数,要求把其中重复的去掉,只保留第一次出现的数。
例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4。
输入输出格式
输入格式:
输入第一行为正整数T,表示有T组数据。
接下来每组数据包括两行,第一行为正整数N,表示有N个数。第二行为要去重的N个正整数。
输出格式:
对于每组数据,输出一行,为去重后剩下的数字,数字之间用一个空格隔开。
原题体面戳这里
对于这道题,直接除以大质数1000007即可.(数据水,没有判重AC了)
代码如下:

#include<bits/stdc++.h>
using namespace std;
int Hash[1000009];
inline int h(int x){return x%1000007;}
void work()
{
    memset(Hash,0,sizeof(Hash));
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        if (Hash[h(x)]==1) continue;
    }
    printf("\n");
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--) work();
}

字符串Hash

原题题面戳这里
这道题,我们采用301当做位权;我们采用大质数1000007来取模;用拉链法来处理重复;同时用vector来代替链表;代码实现难度不大.
代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,ans=0;
int const M=1000007;//最后取模 
vector<string>Link[1000009];
inline int hash(string x)
{
    int sum=0;int w=307;//累加的值,位权 
    for (int i=0;i<x.length();i++)
        sum=(sum*w+int(x[i]))%M;
    return sum; 
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        string s;cin>>s;
        int k=hash(s),flag=1;
        for (int j=0;j<Link[k].size();j++) 
            if (s==Link[k][j]) flag=0;
        if (flag==1)
        {
            Link[k].push_back(s);
            ans++;
        }
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/81138166