雜湊,一種簡單的演算法,通過對字元型別的ASCLL碼值進行運算並取模得到雜湊值,然後對於每一個雜湊值開一個空間,將他們串到一起,也就是說分到一類。

這種演算法常被用來加密,比如使用者的密碼。一些著名的例子如名字競技場的MD5。

當用戶設定初始密碼後,計算機經過驗算,將其轉化為一個值,並儲存下來,日後使用者想要登陸的時候就對使用者輸入的密碼進行運算,進行匹配,如果值相同則通過。

一個求雜湊值簡單的實現:

int hash1(char s[]){
    unsigned long long k;//用於儲存雜湊值
    int len=strlen(s);//字串的長度
    for(int i=1;i<=len;++i){
        k+=s[i]*s[i];//不用擔心溢位,unsigned型別必為整數,當他超過最大值時就會自動模最大值
    }
    return k%mod;//返回
}

在這裡,我們看到雜湊的一個簡單的實現方法。其中,mod是一個變數,可以根據自己的意願進行更改,當然,數字越大匹配的精確度就越高。

這時就有朋友想問了:如果剛好取模後撞上了怎麼辦?不用擔心,我們可以多寫幾個函式,以避免撞車。

當然無論怎麼寫總是會有一些字串的雜湊值相同,這是無可避免的,只能儘量縮小。

方才我們列舉的那個例子是有缺陷的,無法判斷順序不同的字串。

這時我們就要運用一種名曰加權的方法。對,就是那個轉化進位制時用到的加權:對於每一個位置上的數進行加權,以區分位置的區別。

比如下面的又一個例子:

int hash2(char s[],int tmp){
	unsigned long long k;
	int len=strlen(s);
	for(int i=1;i<=len;++i){
		k=h*tmp+s[i];//加權
	}
	return k%mod;
}

其中的tmp便是位權,這個值可以隨意更改。

這樣我們就可以區分順序不同的字串了。

那麼,在求得雜湊值後,我們該如何儲存這些雜湊值呢?

這時候,我們就會用到雜湊表了。而雜湊表的一種實現方式——

噹噹噹,單鏈表閃亮登場!

我們將每一個雜湊值進行分類,雜湊值相同的,串到同一條鏈上,這樣便於儲存,也節省空間。

單鏈表的具體實現如下:

struct data{
    int key;
    struct data *next; 
};

我們用next這個指標指向這個元素所串著的下一個元素,key就是雜湊值。

那麼,搞定了雜湊表的基本問題,讓我們來做一題練練手吧。

問題 : 生成字串

題目描述

假設字串只由字元‘0’,‘1’,‘*’組成,其中字元‘*’表示該字元可由字元‘0’或‘1’替代。
現有一些字串,根據這些字串生成所有可生成的字串。如:
{10,*1,0* }可生成{10,01,11,00 }
{101,001,*01}可生成{101,001}
注意後一個例子中‘*01’並沒有生成新的字串。

輸入

第一行是兩個整數m,n。(1≤m≤15,1≤n≤2500)m表示字串的長度,n表示字串的個數。兩個整數之間由一個空格隔開。以下n行每行各有一個字串。檔案中各行的行首、行末沒有多餘的空格。

輸出

輸出檔案只有一個整數,表示所能生成的字串的個數。

樣例輸入

2 3
10
*1
0*

樣例輸出

4

程式碼實現:

#include<bits/stdc++.h>
using namespace std;
#define zero '0'
#define one '1'
string s[2333];
int n,m;
int f[23333];
char s1[23333];
int maxn;
void _hash(){
    int er=1;
    for(int i=0;i<m-1;i++)er*=2;
    int su=0;
    for(int i=0;i<m;i++){
        int bp=s1[i]-'0';
        su+=bp*er;
        er/=2;
    }
    if(f[su]==0){
        f[su]=1;
        maxn++;
    }
}
void make(string st,int t){
    if(st[t]=='*'){
        s1[t]=zero;
        if(t==m-1)_hash();
        else make(st,t+1);
        s1[t]=one;
        if(t==m-1)_hash();
        else make(st,t+1);
    } 
    else{
        s1[t]=st[t];
        if(t==m-1)_hash();
        else make(st,t+1);
    }
}
int main(){
    cin>>m>>n;
    for(int i=0;i<n;i++)cin>>s[i];
    for(int i=0;i<n;i++)make(s[i],0);
    cout<<maxn;
}