hash算法入门

今天呢,我们简单说一下哈希suan算法,这个算法的内容可以说应该是非常的多的,今天呢我们ji就只学一些简答的,就是关于字符串处理的。

首先呢我们先简单的说一下什么是hash.

先举个例子。我们每个活在世上的人,为了能够参与各种社会活动,都需要一个用于识别自己的标志。也许你觉得名字或是身份证就足以代表你这个人,但是这种代表性非常脆弱,因为重名的人很多,身份证也可以伪造。最可靠的办法是把一个人的所有基因序列记录下来用来代表这个人,但显然,这样做并不实际。而指纹看上去是一种不错的选择,虽然一些专业组织仍然可以模拟某个人的指纹,但这种代价实在太高了。

而对于在互联网世界里传送的文件来说,如何标志一个文件的身份同样重要。比如说我们下载一个文件,文件的下载过程中会经过很多网络服务器、路由器的中转,如何保证这个文件就是我们所需要的呢?我们不可能去一一检测这个文件的每个字节,也不能简单地利用文件名、文件大小这些极容易伪装的信息,这时候,我们就需要一种指纹一样的标志来检查文件的可靠性,这种指纹就是我们现在所用的Hash算法(也叫散列算法)。

其实吧我理解的意思就是给一些东西起个名字,让我们能够知道谁是谁,而且还是不重复的,就例如我们每个人的身份证号,我们每一个人一出生就会有一个自己的身份证号,而且还是独一无二的,不会有人给你相同,所以你的身份证号就可以代表你这个人。其实我感觉hash就是干的这些事,就是给一些东西取个名字,让我们能够根据这个名字找到它。

今天我们就来学有关字符串的hash:

上面我门已经说过了hash就是给一些东西取个名字,那么字符串的hash呢?不错,就是给一些字符串娶一个名字,在这里我们取得名字都是以数字来命名的。

我们知道,a的ASCII码是97,那么在ASCII码中97就是代表着a,现在我们要干什么是呢?就是让没一个字符串都对应一个数字,而且不同的字符串对应的数字一定要是不一样的,例如我们以一个标准去赋给每一个字符串值:

a   1;

ab   15;

abc   97;

基本上就是这个样子的,现在在我们的这一套标准中1这个数字就是代表的a,如果有两个字符串所对应的数字都是97,那么我们就可以说这两个字符串相等,试想一下如果每一个字符串都对应一个不同的数字,那么当我们在对字符串处理的时候是不是就非常的的简单了呢?下面给一道例题:

假如我给你n个字符串,而且每个字符串的长度不超过100,现在我问你,在我给的这n个字符串里面有多少个不相同的字符串,如果我们没有学习hash,这题是不是不太会做,但是当我们学习了hash之后,这样的题是不是就变的非常的简单了,我们定义一个标准,让每一个字符串都对应一个数字,那么最后只要我们查一下有多少个不同的数字都行了,看吧!这道题是不是看起来非常的简单了呢?

你们现在是不是已经大致上了解了hash得一些内容,是不是已经感受到它的魅力了,是不是已经喜欢上了这个算法了呢?

但是有个问题出现了,就是我们应该怎样去做,才能让每一个字符串都对应不同的数字,没错,这的确是一个问题,接下来我们就来解决这个问题。

首先呢我们先给定一个字符串 str[100],然后我们再定义两个数字p,mod,然后我们再给一个hash函数,

hash[i]=(hash[i-1]*p+str[i])%mod.

只要我们取得p和mod合适,那么每个字符串都会对应一个唯一的值,接下来就是怎么取p和mod了,其实就是越大越好,接下来我会教大家一种取得方法,至于为什么这个问题目前我也不便解答,因为我能力有限,想知道的可以自行了解。

p的取法其实也可以很大,视情况而定,大概取有多少个字母都行了,至于mod,既然越大越好,那么我们就直接取最大的,unsigned long long,

每次当我们在定义的时候,我们根本不必去管mod,直接定义成unsigned long long,那么他就会自动取于的,好像也说不太清楚,就给一道题我们一起来看看吧、

给定一个字符串,其中含有不同的字母数量为m,现在求这个字符串中有多少个长度为n且长的互不相同的字符子串 

举个例子, n=3, m=4 ,字符串 "daababac". 长度为3的不同的子串分别是: "daa"; "aab"; "aba"; "bab"; "bac". 因此, 答案是5. 

Input

第一行是两个整数n,m,,一个空格隔开。 接下来一行是我们要解决的字符串.( 你可以认为字符串的长度不会超过一千六百万。)Orz我读错题了,并不是字符串长度不超过1600万,是合理hash之后的hash的值不超过1600万。Orz原谅我

Output

程序应该输出一个整数,对应于给定文本中所找到的大小为n的不同子字符串的数量。

输入数据

3 4
daababac

输出数据

5

Hint

输入数据量庞大,推荐使用scanf

这道题就是一道的典型的hash.

#include<stdio.h>
#include<string.h>
#include<set>
using namespace std;
# define ull unsigned long long
char ch[16000005];
int main()
{
    set<ull> se;
    int n,p;
    ull hash;//把所需要的定义成ull;这样就相当于自动取余了。
    scanf("%d %d\n",&n,&p);
    scanf("%s",ch);
    int l=strlen(ch);
    for(int i=0;i<=l-n;i++)
    {
        hash=0;
        for(int j=i;j<i+n;j++)
        {
            hash=hash*p+ch[j];//hash函数。
        }
        se.insert(hash);//自动去掉重复的数字。
    }
    printf("%d\n",se.size());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42757965/article/details/82391688