• 哈希表Hash:概念与基本操作


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

    对大整数类型进行Hash

    取模法

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

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

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

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

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


    对字符串进行Hash

    对字符串,我们可以选择按权展开法进行实现.
    例如:对于字符abc,我们可以转换成26进制,即:1260+2*261+326^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("
    ");
    }
    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;
    }
    
    
  • 相关阅读:
    文件内容作为服务器的响应练习
    request的请求体数据获取
    request请求头的数据
    Nodejs中流的操作
    response的数据
    http(二)
    Android SlidingMenu使用详解
    Android跨应用启动Service
    Android使用PopupMenu创建弹出式菜单
    HTML5 内联框架iFrame
  • 原文地址:https://www.cnblogs.com/pigzhouyb/p/10119826.html
Copyright © 2020-2023  润新知