基本演算法入門 字串雜湊(Hash) C

2022-05-11 16:28:39 字數 3137 閱讀 8513

說得通俗一點,字串雜湊實質上就是把每個不同的字串轉成不同的整數

為什麼會有這樣的需要呢?很明顯,儲存乙個超長的字串和儲存乙個超大但是能存的下的整數,後者所佔的空間會少的多,但主要還是為了方便判斷乙個字串是否出現過,這是最基礎的部分。

當然也很容易想到,如果有不同的字串轉成同乙個整數,那麼區分功能就基本廢掉 ,所以我們需要乙個演算法把每個字串轉成唯一的整數。所以字串雜湊演算法就應運而生,雜湊演算法的難點也就在於如何構造乙個合適的hash函式來滿足我們的需求。

下面就簡單介紹幾種字串雜湊的基本方法。

一般地,給定乙個字串 \(s=s_1s_2s_3s_4...s_n\),令\(idx(x)=x-'a'+1\),當然,直接(int)x(用它的ascll碼)也一樣。

這種方法是利用資料結構unsigned long long的範圍自然溢位:即當儲存的資料大於unsigned long long的儲存範圍時,會自動mod \(2^-1\),就不用mod其他質數來保證唯一性了。

unsigned long long hash[n]

hash[i]=hash[i−1]∗p+idx(s[i]);

注意:這裡的p一定要是個質數,不然可能無法保證唯一性。

相當於自然溢位法沒有了自動取模的操作,所以需要自己進行取模操作。但是這種hash方法在模數較小的時候的穩定性不一定得到保證,所以在這個方面不如其他方法。

hash[i]=(hash[i−1])∗p+idx(s[i])%mod;
注意:這裡的\(p\)和\(mod\)都是質數,且滿足\(p。最好在選取的時候把\(p\)和\(mod\)的值取大一點。

舉例如取\(p=13,mod=101\),對字串\(abc\)進行hash

hash[0]=1;

hash[1]=(hash[0] × 13 + 2)%101=15;

hash[2]=(hash[1] × 13 + 3)%101=97;

所以最終字串\(abc\)的hash值就是97

其實網上很多部落格講了多hash,但我覺得雙hash已經足夠穩定了,再多一些也只是浪費時間而已。

顧名思義,雙hash就是對乙個hash值用兩個不同的質數進行兩次\(mod\)操作,然後最後用一對數\(\)來表示乙個字串的雜湊值,這樣的一對數的重複機率加上選擇較大的質數,衝突率幾乎為0。

hash1[i]=(hash1[i−1])∗p+idx(s[i]) % mod1

hash2[i]=(hash2[i−1])∗p+idx(s[i]) % mod2

這樣的雜湊很安全

為了防止衝突,要選擇合適的素數,像1e9+7,1e9+9的一些素數,出題人一般會卡一下下,所以盡量選擇其他的素數,防止被卡。下面是一些可供選擇的素數。

上界和下界指的是離素數最近的\(2^n\)的值。

lwrupr% err

prime

2^52^610.416667

53 2^6

2^71.041667

97 2^7

2^80.520833

193 2^8

2^91.302083

389 2^9

2^10

0.130208

769 2^10

2^11

0.455729

1543

2^11

2^12

0.227865

3079

2^12

2^13

0.113932

6151

2^13

2^14

0.008138

12289

2^14

2^15

0.069173

24593

2^15

2^16

0.010173

49157

2^16

2^17

0.013224

98317

2^17

2^18

0.002543

196613

2^18

2^19

0.006358

393241

2^19

2^20

0.000127

786433

2^20

2^21

0.000318

1572869

2^21

2^22

0.000350

3145739

2^22

2^23

0.000207

6291469

2^23

2^24

0.000040

12582917

2^24

2^25

0.000075

25165843

2^25

2^26

0.000010

50331653

2^26

2^27

0.000023

100663319

2^27

2^28

0.000009

201326611

2^28

2^29

0.000001

402653189

2^29

2^30

0.000011

805306457

2^30

2^31

0.000000

1610612741

如果我們求出乙個串的hash,就可以\(o(1)\)求解其子串的hash值。

公式的推導太複雜...乾脆直接貼上來 (絕對不是我想偷懶)

若已知乙個\(|s|=n\)的字串的hash值,\(hash[i]\),\(1≤i≤n\),其子串\(sl..sr,1≤l≤r≤n\),對應的hash值為:

\[hash=((hash[r]−hash[l−1]∗p^)\%mod+mod)\%mod

\]ov.

字串 字串雜湊hash演算法

以洛谷p3370為引子引入吧 雜湊其實是所有字串操作中,筆者認為最簡單的操作了 except輸入輸出qwq 雜湊的過程,其實可以看作對乙個串的單向加密過程,並且需要保證所加的密不能高概率重複 就像不能讓隔壁老王輕易地用它家的鑰匙開啟你家門一樣qwq 通過這種方式來替代一些很費時間的操作。比如,最常見...

字串雜湊 Hash

字串雜湊,用通俗點的說法就是將乙個字串轉換成乙個整數,而且用雜湊轉換出來的整數,不同的字串,不出意外整數也不一樣 存在極少的情況一樣 從而更方便地確定某個字串是否重複出現過或者對字串進行其他的判斷。基本思想 假設乙個字串 abcdabcd 將整個字串看成乙個p p一般取131或者13331比較好,可...

Hash 字串 字串雜湊

luo gu luogu luogup 3370 p3370 p337 0如題,給定n個字串 第i個字串長度為mi,字串內包含數字 大小寫字母 請求出n個字串中共有多少個不同的字串。第一行包含乙個整數n,為字串的個數。接下來n行每行包含乙個字串,為所提供的字串。輸出包含一行,包含乙個整數,為不同的字...