1. 程式人生 > >字串雜湊到整數函式,演算法

字串雜湊到整數函式,演算法

基本概念
所謂完美雜湊函式,就是指沒有衝突的雜湊函式,即對任意的 key1 != key2 有h(key1) != h(key2)。
設定義域為X,值域為Y, n=|X|,m=|Y|,那麼肯定有m>=n,如果對於不同的key1,key2屬於X,有h(key1)!=h(key2),那麼稱h為完美雜湊函式,當m=n時,h稱為最小完美雜湊函式(這個時候就是一一映射了)。

在處理大規模字串資料時,經常要為每個字串分配一個整數ID。這就需要一個字串的雜湊函式。怎麼樣找到一個完美的字串hash函式呢?
有一些常用的字串hash函式。像BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等。都是比較經典的。

常用的字串Hash函式還有ELFHash,APHash等等,都是十分簡單有效的方法。這些函式使用位運算使得每一個字元都對最後的函式值產生影響。另外還有以MD5和SHA1為代表的雜湊函式,這些函式幾乎不可能找到碰撞。

常用字串雜湊函式有 BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等。對於以上幾種雜湊函式,我對其進行了一個小小的評測。

Hash函式 資料1 資料2 資料3 資料4 資料1得分 資料2得分 資料3得分 資料4得分 平均分
BKDRHash 2 0 4774 481 96.55 100 90.95 82.05 92.64
APHash 2 3 4754 493 96.55 88.46 100 51.28 86.28
DJBHash 2 2 4975 474 96.55 92.31 0 100 83.43
JSHash 1 4 4761 506 100 84.62 96.83 17.95 81.94
RSHash 1 0 4861 505 100 100 51.58 20.51 75.96
SDBMHash 3 2 4849 504 93.1 92.31 57.01 23.08 72.41
PJWHash 30 26 4878 513 0 0 43.89 0 21.95
ELFHash 30 26 4878 513 0 0 43.89 0 21.95

其中資料1為100000個字母和數字組成的隨機串雜湊衝突個數。資料2為100000個有意義的英文句子雜湊衝突個數。資料3為資料1的雜湊值與 1000003(大素數)求模後儲存到線性表中衝突的個數。資料4為資料1的雜湊值與10000019(更大素數)求模後儲存到線性表中衝突的個數。

經過比較,得出以上平均得分。平均數為平方平均數。可以發現,BKDRHash無論是在實際效果還是編碼實現中,效果都是最突出的。APHash也是較為優秀的演算法。DJBHash,JSHash,RSHash與SDBMHash各有千秋。PJWHash與ELFHash效果最差,但得分相似,其演算法本質是相似的。

複製程式碼
unsigned int SDBMHash(char *str)
{
    unsigned int hash = 0;
 
    while (*str)
    {
        // equivalent to: hash = 65599*hash + (*str++);        hash = (*str++) + (hash << 6) + (hash << 16) - hash;
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// RS Hash Functionunsigned int RSHash(char *str)
{
    unsigned int b = 378551;
    unsigned int a = 63689;
    unsigned int hash = 0;
 
    while (*str)
    {
        hash = hash * a + (*str++);
        a *= b;
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// JS Hash Functionunsigned int JSHash(char *str)
{
    unsigned int hash = 1315423911;
 
    while (*str)
    {
        hash ^= ((hash << 5) + (*str++) + (hash >> 2));
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// P. J. Weinberger Hash Functionunsigned int PJWHash(char *str)
{
    unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8);
    unsigned int ThreeQuarters    = (unsigned int)((BitsInUnignedInt  * 3) / 4);
    unsigned int OneEighth        = (unsigned int)(BitsInUnignedInt / 8);
    unsigned int HighBits         = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
    unsigned int hash             = 0;
    unsigned int test             = 0;
 
    while (*str)
    {
        hash = (hash << OneEighth) + (*str++);
        if ((test = hash & HighBits) != 0)
        {
            hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
        }
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// ELF Hash Functionunsigned int ELFHash(char *str)
{
    unsigned int hash = 0;
    unsigned int x    = 0;
 
    while (*str)
    {
        hash = (hash << 4) + (*str++);
        if ((x = hash & 0xF0000000L) != 0)
        {
            hash ^= (x >> 24);
            hash &= ~x;
        }
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// BKDR Hash Functionunsigned int BKDRHash(char *str)
{
    unsigned int seed = 131; // 31 131 1313 13131 131313 etc..    unsigned int hash = 0;
 
    while (*str)
    {
        hash = hash * seed + (*str++);
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// DJB Hash Functionunsigned int DJBHash(char *str)
{
    unsigned int hash = 5381;
 
    while (*str)
    {
        hash += (hash << 5) + (*str++);
    }
 
    return (hash & 0x7FFFFFFF);
}
 
// AP Hash Functionunsigned int APHash(char *str)
{
    unsigned int hash = 0;
    int i;
 
    for (i=0; *str; i++)
    {
        if ((i & 1) == 0)
        {
            hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
        }
        else
        {
            hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
        }
    }
 
    return (hash & 0x7FFFFFFF);
}
複製程式碼

程式設計珠璣中的一個hash函式

複製程式碼
//用跟元素個數最接近的質數作為散列表的大小
#define NHASH 29989
#define MULT 31

unsigned in hash(char *p)
{
    unsigned int h = 0;
    for (; *p; p++)
        h = MULT *h + *p;
    return h % NHASH;
}
複製程式碼

相關推薦

字串整數函式演算法

基本概念 所謂完美雜湊函式,就是指沒有衝突的雜湊函式,即對任意的 key1 != key2 有h(key1) != h(key2)。 設定義域為X,值域為Y, n=|X|,m=|Y|,那麼肯定有m>=n,如果對於不同的key1,key2屬於X,有h(key1)!=h(

python中 表應用常見函式 MD5和SHA2演算法

通過雜湊函式計算資料儲存 insert(key, value) 插入鍵值對 get(key) 獲取值 delete(key) 刪除值 常見雜湊函式 除法雜湊:h(k) = k % m 乘法雜湊:h(k) = floor(m*(

演算法筆記_HASH字串

HASH字串雜湊的核心就是進位制轉換,轉化為十進位制整數的HASH整數雜湊,沒有什麼特別. 單純A到Z(全大寫字母)或者a到z(全小寫字母)視為26進位制. 大小寫混合視為52進位制 問題來了,大小寫混合還混上字母怎麼辦呢?有兩種想法:     

通過Java實現HMAC字串成為全部由字母組成的密文串

以下Java程式碼可以將任何字串通過HMAC雜湊,並輸出成由大寫的A到P組成的密文字串。 public class HMAC { private final static String KEY_MAC = "HMACMD5"; /** * 全域性陣列 *

ELFhash 字串演算法(以ELFHash詳解)

字串雜湊演算法(以ELFHash詳解)   更多字串雜湊演算法請參考:http://blog.csdn.net/AlburtHoffman/article/details/19641123 先來了解一下何為雜湊: 雜湊表是根據設定的雜湊函式H(key)和處

linux下將整數轉化為字串用法(itoa()函式sprintf()函式

1.1在linux系統下,沒有itoa()函式,只有atoi()函式。其中itoa()函式的標頭檔案如下:#include<stdlib.h>1.2想要實現將整數轉化為字串,可以用如下函式實現。sprintf(str,"%d",rand());//將整形變數轉換為

[SCOI2007]壓縮(動態規劃,區間dp,字串)

[SCOI2007]壓縮 狀態:設\(dp[i][j]\)表示前i個字元,最後一個\(M\)放置在\(j\)位置之後的最短字串長度. 轉移有三類,用刷表法來實現. 第一種是直接往壓縮串後面填字元,這樣就是: \[dp[i+1][j]=min(dp[i+1][j],dp[i][j]+1)\] 另外一種

C++【模板】字串

介紹:關於字串hash,一句話概括,就是把字串有效的轉化為一個整數 hash[i]=(hash[i-1]*p+idx(s[i]))%mod for example:取p=13, mod=101,求abc對應的整數 hash[0]=1; 表示a對映1。 hash[1]=(hash[0]

51Nod1553 週期串查詢 字串 線段樹

原文連結https://www.cnblogs.com/zhouzhendong/p/51Nod1553.html 題目傳送門 - 51Nod1553 題意   有一個串只包含數字字元。串的長度為n,下標從1開始。   有兩種操作方式:   1 l r c (1≤l≤r≤n, c是數字字元),表示將

字串--聰聰的加法等式

題目: 聰聰昨天費了九牛二虎之力終於計算出一個形如 A + B

URAL 1989(線段樹+字串

題意:給一個字串(<=1e5), 進行操作和查詢(<=1e5)。 1)將指定位置的字元改為c 2)詢問l-r的子串,是否是迴文串。 多項式雜湊: Hash[i] = Hash[i - 1] * x + s[i](其中1 < i <= n,Has

牛客練習賽33 E. tokitsukaze and Similar String (字串

題目連結:https://ac.nowcoder.com/acm/contest/308/E 題意:中文題 見連結 題解:雜湊預處理(三雜湊模板) 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll lon

字串 模板

模板 #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn=2e4+10; const int inf=0x7ffffff; inline i

tokitsukaze and Similar String(字串

題目連結: tokitsukaze and Similar String   題意: tokitsukaze獲得了一個長度為n (1≤n≤10^5),由a-z小寫字母組成的字串。 我們定義兩個字串是相似的,當且僅當能通過多次以下操作,使得兩個字串相等。並且把需要操

字串(詳解+模版)

參考部落格: 詳解1 詳解2 詳解3 個人理解: 字串Hash的種類還是有很多種的,不過在ACM中一般只會用到一種名為“BKDR Hash”的字串Hash演算法。它的主要思路是選取恰當的進位制,可以把字串中的字元看成一個大數字中的每一位數字。關於進位制的選擇實際上非常自由,大

牛客練習賽28 D 隨風飄(dp + 字串

能用字串雜湊解決的問題,千萬別用字尾陣列、字典樹什麼的了…… 這題有很多個詢問,每次詢問是從n箇中拿走k個字串,問拿走之後的答案。我們顯然不能把所有拿走的方案列舉一遍,所以考慮計算每一個字串的貢獻。這裡我的貢獻指第i個字串與它前面的字串的貢獻。而這個貢獻就是

牛客國慶集訓派對Day5 H-我不愛她 (KMP+字串

題目描述 終於活成了自己討厭的樣子。   天空仍燦爛,它愛著大海。 你喜歡大海,我愛過你。 世界上充滿了巧合。我們把每句話當成一個字串,我們定義a對b的巧合值為a的最長字尾的長度並且它是恰好是b的字首,這裡的字尾或者字首包括字串的本身。 比如字串“天空仍燦

字串[hash模板]

有這麼一類神奇的問題,給你一堆字串,然後問你有多少本質不同的字串 ~~ 或許有頭鐵的同志可以開一個map ~~ 所以有了hash大法 大致思想 我們判斷兩個字串相等,無非就是判斷他們每一位是不是相等,但是如果讓你判斷兩個數字是不是相等,是不是就簡單了許多呢?

字串+二分--poj2758Checking the Text

去年寒假講的題··· 傳送門 因為插入很少所以可以每次暴力重構 查詢就用二分+雜湊查詢lcplcplcp 好多細節···題目裡查詢的是原數列的x,yx,yx,y坑了不少人 #include<ios

leetcode 49. Group Anagrams【素數相乘處理字串

Given an array of strings, group anagrams together. Example: Input: ["eat", "tea", "tan", "ate",