雜湊
1,思想
引入:直接把輸入的數作為陣列的下標來對這個數的性質進行統計
但是如果輸入的範圍大於10^9或是字串,就不能將它們直接作為陣列下標了。
核心思想:
將元素通過乙個函式轉為整數,使得該整數可以盡量唯一地代表這個元素。【這個函式就是雜湊函式】
即:如果乙個元素在轉換前為key,那麼轉換後就是乙個整數h(key)
對於key是整數的情況,常用的方法有:直接定址法、平方取中法、除留餘數法等
直接定址法就是直接把key作為陣列下表,是最常用最實用的雜湊應用
或是線性變化(h(key)= a* key + b)
而平方取中法是取key的平方的中間若干位作為hash值(很少用);
除留餘數法是指把key除以乙個數mod得到的餘數作為hash值的方法,
即h(key) = key % mod
通過這個雜湊函式,可以把很大的數轉換為不超過mod的函式,這樣就可以將它作為可行的陣列小標(⚠️:表長tsize必須不小於mod,不然會產生越界)
顯然當mod是乙個素數(質數)時,h(key)能盡可能覆蓋[0,mod)範圍內的每乙個數。
因此一般為了方便起見,取tsize是乙個素數,而mod直接取成與tsize相等。
2,衝突
當除留餘數法產生兩個及以上的h(key)時,這種情況稱為「衝突」
解決衝突的方法:
1)線性探測法(linear probing)
當發生衝突時,檢查下乙個位置h(key) + 1是否被占用,如果沒有就使用這個位置,否則繼續檢查下乙個位置,直到找到乙個可以使用過的位置,或者發現表中所有位置都已經被使用。(容易導致扎堆——表中連續若干位置都被使用)
2)平方探測法(quadratic probing)
可以盡可能的避免扎堆現象,當表中下標為h(key)的位置被佔時,將按下面的順序檢查表中的位置:
h(key)+ 1^2、h(key) - 1^2、h(key) + 2^2、h(key)-2^2、h(key)+3^2、…
若果檢查過程中h(key)超過了表長tsize,那麼就把h(key)+k^2對錶長tsize取模;
若果檢查過程**現h(key)-k^2<0的情況(假設表的首位為0),那麼將((h(key)-k^2)%tsize+tsize)%tsize作為結果(等價於將h(key)-k^2不斷加上tsize直到出現第乙個非負數。
如果想避免負數的麻煩,可以只進行正向的平方探測法。可以證明,如果k在[0,tsize]範圍內都無法找到位置,那麼當k>=tszie,也一定無法找到位置
3)鏈位址法(拉鍊法)
鏈位址法不計算新的hash值,而是把所有的h(key)相同的key連線成一條單鏈表。
可以設定乙個陣列link,範圍時link[0]~link[mod],其中link[k]存放h(key)= h的一條單鏈表,於是當多個關鍵字key的hash值都是h時,就可以直接把這些衝突的key直接用單鏈表連線起來,此時就可以便利這條單鏈表來尋找所有h(key)= h的key。
3,字串hash初步
這裡重點在於討論將乙個字串轉換為唯一的整數。
先假設字串都是又大寫a~z構成。不妨把a~z視為0~25,這樣就把26個大寫字母對應到了二十六進製制,這樣就可以按照二十六進製制轉為十進位制的思路,由進製轉化的結論可知,得到的十進位制時唯一的,由此便可以實現將字串對映為整數的需求**換為整數最大時26^len - 1, len為字串長度)
int hashfunc(char s, int len)
return id;
}
⚠️:如果字串s的長度比較長,那麼轉換成的整數也會很大,因此使用時len不能太長。
如果字串**現了小寫字母,那麼可以把a~z作為0~25,而把a~z作為26~51,這樣就變成了五十二進位制轉換為十進位制的問題,做法相同。
int hashfunc(char s, int len)else if(s[i] >= 『a』 && s[i] <= 『z』)
}}
而如果出現了數字,一般有兩種處理方法:
1)按照小寫字母的處理方法,增大進製到62
2)如果保證在字串的末尾時確定個數的數字,那麼就可以把前面英文本母的部分按上面的思路轉化為整數,再將末尾的數字直接拼接上去。
例如:字串「bcd4」,可以把「bcd」轉換為整數731,然後直接拼接上末尾的4變成7314即可。
示例**:
int hashfunc(chat s, int len)
id = id * 10 + (s[len - 1] - '0');
return id;
}
練習題目:
給出n個字串,再給出m個查詢字串,問每個查詢字串子在n個字串出現的次數。
#includeconst int maxn = 100;
char s[maxn][5];
char temp[5];
int hasttable[26 * 26 * 26 +10];
int hashfunc(char s, int len)
return id;
}int main(int argc, char const *ar**)
for (int i = 0; i < m; ++i)
return 0;
}
你在用什麼思想編碼 事務指令碼 OR 物件導向?
最近在公司內部做技術交流的時候,說起技能提公升的問題,調研大家想要培訓什麼,結果大出我意料,很多人想要培訓 物件導向編碼。於是我丟擲乙個問題 你覺得我們現在的 是物件導向的嗎?有人回答 是,有人回答否。我對這個問題的回答是 語法上,是了,但是架構上或者思想上,不是。我們現在的大部分 如果要死扣乙個名...
你在用什麼思想編碼 事務指令碼 OR 物件導向?
最近在公司內部做技術交流的時候,說起技能提公升的問題,調研大家想要培訓什麼,結果大出我意料,很多人想要培訓 物件導向編碼。於是我丟擲乙個問題 你覺得我們現在的 是物件導向的嗎?有人回答 是,有人回答否。我對這個問題的回答是 語法上,是了,但是架構上或者思想上,不是。我們現在的大部分 如果要死扣乙個名...
雜湊表 Hash 的應用
hs 定義陣列 hs 定義hash表,使用雜湊表的鍵可以直接訪問對應的值,如 hs 王五 或者 hs.王五 的值為 75 hs 定義文字字串 1 hs 2張三 3男412歲 5 hash表的新建 修改 刪除 1 新建hash表 2 rs 3 rs45 rs 6 rs.name lily 7 rs.s...