hash函數

hash函數

Hash,一般翻譯做散列、雜湊,或音譯為哈希,就是把任意長度的輸入(又叫做預映射,pre-image),通過散列演演算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出,而不可能從散列值來唯一的確定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。

定義


了解了hash基本定義,就不能不提到一些著名的hash演演算法,MD5 和 SHA1 可以說是目前應用最廣泛的Hash演演算法,而它們都是以 MD4 為基礎設計的。那麼它們都是什麼意思呢?
這裡簡單說一下:

MD4

MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年設計的,MD 是 Message Digest 的縮寫。它適用在32位字長的處理器上用高速軟體實現--它是基於 32位操作數的位操作來實現的。

MD5

MD5(RFC 1321)是 Rivest 於1991年對MD4的改進版本。它對輸入仍以512位分組,其輸出是4個32位字的級聯,與 MD4 相同。MD5比MD4來得複雜,並且速度較之要慢一點,但更安全,在抗分析和抗差分方面表現更好

SHA1

SHA1是由NIST NSA設計為同DSA一起使用的,它對長度小於2^64位的輸入,產生長度為160bit的散列值,因此抗窮舉(brute-force)性更好。SHA-1 設計時基於和MD4相同原理,並且模仿了該演演算法。

概念

若結構中存在和關鍵字K相等的記錄,則必定在f(K)的存儲位置上。由此,不需比較便可直接取得所查記錄。稱這個對應關係f為散列函數(Hash function),按這個事先建立的表為散列表
對不同的關鍵字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),這種現象稱碰撞。具有相同函數值的關鍵字對該散列函數來說稱做同義詞。綜上所述,根據散列函數H(key)和處理衝突的方法將一組關鍵字映射到一個有限的連續的地址集(區間)上,並以關鍵字在地址集中的“象”作為記錄在表中的存儲位置,這種表便稱為散列表,這一映象過程稱為散列造表或散列,所得的存儲位置稱散列地址。
若對於關鍵字集合中的任一個關鍵字,經散列函數映象到地址集合中任何一個地址的概率是相等的,則稱此類散列函數為均勻散列函數(Uniform Hash function),這就是使關鍵字經過散列函數得到一個“隨機的地址”,從而減少衝突。

性質

所有散列函數都有如下一個基本特性:如果兩個散列值是不相同的(根據同一函數),那麼這兩個散列值的原始輸入也是不相同的。這個特性是散列函數具有確定性的結果。但另一方面,散列函數的輸入和輸出不是一一對應的,如果兩個散列值相同,兩個輸入值很可能是相同的,但不絕對肯定二者一定相等(可能出現哈希碰撞)。輸入一些數據計算出散列值,然後部分改變輸入值,一個具有強混淆特性的散列函數會產生一個完全不同的散列值。
典型的散列函數都有無限定義域,比如任意長度的位元組字元串,和有限的值域,比如固定長度的比特串。在某些情況下,散列函數可以設計成具有相同大小的定義域和值域間的一一對應。一一對應的散列函數也稱為排列。可逆性可以通過使用一系列的對於輸入值的可逆“混合”運算而得到。

常用HASH函數

散列函數能使對一個數據序列的訪問過程更加迅速有效,通過散列函數,數據元素將被更快地定位。常用Hash函數有:
1.直接定址法。取關鍵字或關鍵字的某個線性函數值為散列地址。即H(key)=key或H(key) = a·key + b,其中a和b為常數(這種散列函數叫做自身函數)
2.數字分析法。分析一組數據,比如一組員工的出生年月日,這時我們發現出生年月日的前幾位數字大體相同,這樣的話,出現衝突的幾率就會很大,但是我們發現年月日的後幾位表示月份和具體日期的數字差別很大,如果用後面的數字來構成散列地址,則衝突的幾率會明顯降低。因此數字分析法就是找出數字的規律,儘可能利用這些數據來構造衝突幾率較低的散列地址。
3.平方取中法。取關鍵字平方后的中間幾位作為散列地址。
4.摺疊法。將關鍵字分割成位數相同的幾部分,最後一部分位數可以不同,然後取這幾部分的疊加和(去除進位)作為散列地址。
5.隨機數法。選擇一隨機函數,取關鍵字作為隨機函數的種子生成隨機值作為散列地址,通常用於關鍵字長度不同的場合。
6.除留餘數法。取關鍵字被某個不大於散列表表長m的數p除后所得的餘數為散列地址。即 H(key) = key MOD p,p<=m。不僅可以對關鍵字直接取模,也可在摺疊、平方取中等運算之後取模。對p的選擇很重要,一般取素數或m,若p選的不好,容易產生碰撞。

處理衝突方法

1.開放定址法;Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1),其中H(key)為散列函數,m為散列表長,di為增量序列,可有下列三種取法:
1). di=1,2,3,…,m-1,稱線性探測再散列;
2). di=1^2,-1^2,2^2,-2^2,3^2,…,±k^2,(k<=m/2)稱二次探測再散列;
3). di=偽隨機數序列,稱偽隨機探測再散列。
2. 再散列法:Hi=RHi(key),i=1,2,…,k RHi均是不同的散列函數,即在同義詞產生地址衝突時計算另一個散列函數地址,直到衝突不再發生,這種方法不易產生“聚集”,但增加了計算時間。
3. 鏈地址法(拉鏈法)
4. 建立一個公共溢出區

查找性能分析

散列表的查找過程基本上和造表過程相同。一些關鍵碼可通過散列函數轉換的地址直接找到,另一些關鍵碼在散列函數得到的地址上產生了衝突,需要按處理衝突的方法進行查找。在介紹的三種處理衝突的方法中,產生衝突后的查找仍然是給定值與關鍵碼進行比較的過程。所以,對散列表查找效率的量度,依然用平均查找長度來衡量。
查找過程中,關鍵碼的比較次數,取決於產生衝突的多少,產生的衝突少,查找效率就高,產生的衝突多,查找效率就低。因此,影響產生衝突多少的因素,也就是影響查找效率的因素。影響產生衝突多少有以下三個因素:
1.散列函數是否均勻;
2.處理衝突的方法;
3.散列表的裝填因子。
散列表的裝填因子定義為:α= 填入表中的元素個數/散列表的長度
α是散列表裝滿程度的標誌因子。由於表長是定值,α與“填入表中的元素個數”成正比,所以,α越大,填入表中的元素較多,產生衝突的可能性就越大;α越小,填入表中的元素較少,產生衝突的可能性就越小。
實際上,散列表的平均查找長度是裝填因子α的函數,只是不同處理衝突的方法有不同的函數。
了解了hash基本定義,就不能不提到一些著名的hash演演算法,MD5和SHA-1可以說是應用最廣泛的Hash演演算法,而它們都是以MD4為基礎設計的。
常用hash演演算法的介紹:
(1)MD4
MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年設計的,MD 是 Message Digest(消息摘要)的縮寫。它適用在32位字長的處理器上用高速軟體實現——它是基於 32位操作數的位操作來實現的。
(2)MD5
MD5(RFC 1321)是 Rivest 於1991年對MD4的改進版本。它對輸入仍以512位分組,其輸出是4個32位字的級聯,與 MD4 相同。MD5比MD4來得複雜,並且速度較之要慢一點,但更安全,在抗分析和抗差分方面表現更好。
(3)SHA-1及其他
SHA1是由NIST NSA設計為同DSA一起使用的,它對長度小於2的輸入,產生長度為160bit的散列值,因此抗窮舉(brute-force)性更好。SHA-1 設計時基於和MD4相同原理,並且模仿了該演演算法。

散列函數應用

由於散列函數的應用的多樣性,它們經常是專為某一應用而設計的。例如,加密散列函數假設存在一個要找到具有相同散列值的原始輸入的敵人。一個設計優秀的加密散列函數是一個“單向”操作:對於給定的散列值,沒有實用的方法可以計算出一個原始輸入,也就是說很難偽造。為加密散列為目的設計的函數,如MD5,被廣泛的用作檢驗散列函數。這樣軟體下載的時候,就會對照驗證代碼之後才下載正確的文件部分。此代碼有可能因為環境因素的變化,如機器配置或者IP地址的改變而有變動。以保證源文件的安全性。
錯誤監測和修複函數主要用於辨別數據被隨機的過程所擾亂的事例。當散列函數被用於校驗和的時候,可以用相對較短的散列值來驗證任意長度的數據是否被更改過。
錯誤校正
使用一個散列函數可以很直觀的檢測出數據在傳輸時發生的錯誤。在數據的發送方,對將要發送的數據應用散列函數,並將計算的結果同原始數據一同發送。在數據的接收方,同樣的散列函數被再一次應用到接收到的數據上,如果兩次散列函數計算出來的結果不一致,那麼就說明數據在傳輸的過程中某些地方有錯誤了。這就叫做冗餘校驗。
對於錯誤校正,假設相似擾動的分佈接近最小(a distribution of likely perturbations is assumed at least approximately)。對於一個信息串的微擾可以被分為兩類,大的(不可能的)錯誤和小的(可能的)錯誤。我們對於第二類錯誤重新定義如下,假如給定 H(x) 和 x+s,那麼只要s足夠小,我們就能有效的計算出x。那樣的散列函數被稱作錯誤校正編碼。這些錯誤校正編碼有兩個重要的分類:循環冗餘校驗和里德所羅門碼。
語音識別
對於像從一個已知列表中匹配一個MP3文件這樣的應用,一種可能的方案是使用傳統的散列函數——例如MD5,但是這種方案會對時間平移、CD讀取錯誤、不同的音頻壓縮演演算法或者音量調整的實現機制等情況非常敏感。使用一些類似於MD5的方法有利於迅速找到那些嚴格相同(從音頻文件的二進位數據來看)的音頻文件,但是要找到全部相同(從音頻文件的內容來看)的音頻文件就需要使用其他更高級的演演算法了。
那些並不緊隨IT工業潮流的人往往能反其道而行之,對於那些微小差異足夠魯棒的散列函數確實存在。現存的絕大多數散列演演算法都是不夠魯棒的,但是有少數散列演演算法能夠達到辨別從嘈雜房間里的揚聲器里播放出來的音樂的魯棒性。有一個實際的例子是Shazam[1]服務。用戶可以用電話機撥打一個特定的號碼,並將電話機的話筒靠近用於播放音樂的揚聲器。該項服務會分析正在播放的音樂,並將它與存儲在資料庫中的已知的散列值進行比較。用戶就能夠收到被識別的音樂的曲名(需要收取一定的費用)
信息安全
Hash演演算法在信息安全方面的應用主要體以下的3個方面:
(1)文件校驗
我們比較熟悉的校驗演演算法有奇偶校驗和CRC校驗,這2種校驗並沒有抗數據篡改的能力,它們一定程度上能檢測並糾正數據傳輸中的通道誤碼,但卻不能防止對數據的惡意破壞。
MD5 Hash演演算法的"數字指紋"特性,使它成為應用最廣泛的一種文件完整性校驗和(Checksum)演演算法,不少Unix系統有提供計算md5 checksum的命令。
(2)數字簽名
Hash演演算法也是現代密碼體系中的一個重要組成部分。由於非對稱演演算法的運算速度較慢,所以在數字簽名協議中,單向散列函數扮演了一個重要的角色。對Hash值,又稱"數字摘要"進行數字簽名,在統計上可以認為與對文件本身進行數字簽名是等效的。而且這樣的協議還有其他的優點。
(3) 鑒權協議
如下的鑒權協議又被稱作挑戰—認證模式:在傳輸通道是可被偵聽,但不可被篡改的情況下,這是一種簡單而安全的方法。以上就是一些關於hash以及其相關的一些基本預備知識。

哈希函數

(1)餘數法:先估計整個哈希表中的表項目數目大小。然後用這個估計值作為除數去除每個原始值,得到商和餘數。用餘數作為哈希值。因為這種方法產生衝突的可能性相當大,因此任何搜索演演算法都應該能夠判斷衝突是否發生並提出取代演演算法。
(2)摺疊法:這種方法是針對原始值為數字時使用,將原始值分為若干部分,然後將各部分疊加,得到的最後四個數字(或者取其他位數的數字都可以)來作為哈希值。
(3)基數轉換法:當原始值是數字時,可以將原始值的數制基數轉為一個不同的數字。例如,可以將十進位的原始值轉為十六進位的哈希值。為了使哈希值的長度相同,可以省略高位數字。
(4)數據重排法:這種方法只是簡單的將原始值中的數據打亂排序。比如可以將第三位到第六位的數字逆序排列,然後利用重排后的數字作為哈希值。
哈希函數並不通用,比如在資料庫中用能夠獲得很好效果的哈希函數,用在密碼學或錯誤校驗方面就未必可行。在密碼學領域有幾個著名的哈希函數。這些函數包括MD2、MD4以及MD5,利用散列法將數字簽名轉換成的哈希值稱為信息摘要(message-digest),另外還有安全散列演演算法(SHA),這是一種標準演演算法,能夠生成更大的(60bit)的信息摘要,有點兒類似於MD4演演算法。

文件的hash值

大家都知道emule是基於P2P(Peer-to-peer的縮寫,指的是對等體網路下客戶到客戶文件傳輸的軟體),它採用了"多源文件傳輸協議”(MFTP,the Multisource FileTransfer Protocol)。在協議中,定義了一系列傳輸、壓縮和打包還有積分的標準,emule 對於每個文件都有md5-hash的演演算法設置,這使得該文件,並且在整個網路上都可以追蹤得到。
MD5-Hash-文件的數字文摘通過Hash函數計算得到。不管文件長度如何,它的Hash函數計算結果是一個固定長度的數字。與加密演演算法不同,這一個Hash演演算法是一個不可逆的單向函數。採用安全性高的Hash演演算法,如MD5、SHA時,兩個不同的文件幾乎不可能得到相同的Hash結果。因此,一旦文件被修改,就可檢測出來。
當我們的文件放到emule裡面進行共享發布的時候,emule會根據hash演演算法自動生成這個文件的hash值,他就是這個文件的身份標誌,它包含了這個文件的基本信息,然後把它提交到所連接的伺服器。當有他人想對這個文件提出下載請求的時候,這個hash值可以讓他人知道他正在下載的文件是不是就是他所想要的。尤其是在文件的其他屬性被更改之後(如名稱等)這個值就更顯得重要。而且伺服器還提供了,這個文件當前所在的用戶的地址,埠等信息,這樣emule就知道到哪裡去下載了。
一般來講我們要搜索一個文件,emule在得到了這個信息后,會向被添加的伺服器發出請求,要求得到有相同hash值的文件。而伺服器則返回持有這個文件的用戶信息。這樣我們的客戶端就可以直接的和擁有那個文件的用戶溝通,看看是不是可以從他那裡下載所需的文件。
對於emule中文件的hash值是固定的,也是的,它就相當於這個文件的信息摘要,無論這個文件在誰的機器上,他的hash值都是不變的,無論過了多長時間,這個值始終如一,當我們在進行文件的下載上傳過程中,emule都是通過這個值來確定文件。
hash文件
我們經常在emule日誌裡面看到,emule正在hash文件,這裡就是利用了hash演演算法的文件校驗性這個功能了,文章前面已經說了一些這些功能,其實這部分是一個非常複雜的過程,在ftp,bt等軟體裡面都是用的這個基本原理,emule裡面是採用文件分塊傳輸,這樣傳輸的每一塊都要進行對比校驗,如果錯誤則要進行重新下載,這期間這些相關信息寫入met文件,直到整個任務完成,這個時候part文件進行重新命名,然後使用move命令,把它傳送到incoming文件裡面,然後met文件自動刪除,所以我們有的時候會遇到hash文件失敗,就是指的是met裡面的信息出了錯誤不能夠和part文件匹配,另外有的時候開機也要瘋狂hash,有兩種情況一種是你在第一次使用,這個時候要hash提取所有文件信息,還有一種情況就是上一次你非法關機,那麼這個時候就是要進行排錯校驗了。
關於hash的演演算法研究,一直是信息科學裡面的一個前沿,尤其在網路技術普及的,他的重要性越來越突出,其實我們每天在網上進行的信息交流安全驗證,我們在使用的操作系統密鑰原理,裡面都有它的身影,特別對於那些研究信息安全有興趣的朋友,這更是一個打開信息世界的鑰匙,他在hack世界裡面也是一個研究的焦點。

userhash

道理同上,當我們在第一次使用emule的時候,emule會自動生成一個值,這個值也是的,它是我們在emule世界裡面的標誌,只要你不卸載,不刪除config,你的userhash值也就永遠不變,積分制度就是通過這個值在起作用,emule裡面的積分保存,身份識別,都是使用這個值,而和你的id和你的用戶名無關,你隨便怎麼改這些東西,你的userhash值都是不變的,這也充分保證了公平性。其實他也是一個信息摘要,只不過保存的不是文件信息,而是我們每個人的信息。

散列表


散列表是散列函數的一個主要應用,使用散列表能夠快速的按照關鍵字查找數據記錄。(注意:關鍵字不是像在加密中所使用的那樣是秘密的,但它們都是用來“解鎖”或者訪問數據的。)例如,在英語字典中的關鍵字是英文單詞,和它們相關的記錄包含這些單詞的定義。在這種情況下,散列函數必須把按照字母順序排列的字元串映射到為散列表的內部數組所創建的索引上。
散列表散列函數的幾乎不可能/不切實際的理想是把每個關鍵字映射到的索引上(參考散列),因為這樣能夠保證直接訪問表中的每一個數據。
一個好的散列函數(包括大多數加密散列函數)具有均勻的真正隨機輸出,因而平均只需要一兩次探測(依賴於裝填因子)就能找到目標。同樣重要的是,隨機散列函數幾乎不可能出現非常高的衝突率。但是,少量的可以估計的衝突在實際狀況下是不可避免的(參考生日悖論)。
在很多情況下,heuristic散列函數所產生的衝突比隨機散列函數少的多。Heuristic函數利用了相似關鍵字的相似性。例如,可以設計一個heuristic函數使得像FILE0000.CHK,FILE0001.CHK,FILE0002.CHK,等等這樣的文件名映射到表的連續指針上,也就是說這樣的序列不會發生衝突。相比之下,對於一組好的關鍵字性能出色的隨機散列函數,對於一組壞的關鍵字經常性能很差,這種壞的關鍵字會自然產生而不僅僅在攻擊中才出現。性能不佳的散列函數表意味著查找操作會退化為費時的線性搜索。
散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。

擴展


MD5、SHA1的破解
2004年8月17日,在美國加州聖芭芭拉召開的國際密碼大會上,山東大學王小雲教授在國際會議上首次宣布了她及她的研究小組的研究成果——對MD5、HAVAL-128、MD4和RIPEMD四個著名密碼演演算法的破譯結果。次年二月宣布破解SHA-1密碼。

命令描述


Linux命令——hash
hash命令用來顯示、添加和清除哈希表。該命令的語法格式如下所示。
語法
hash [-l] [-r] [-p ] [-t ]
選項說明
選項說明
-l顯示哈希表,包括路徑
-r清除哈希表
-p 向哈希表中增加內容
-t 顯示指定命令的完整路徑
HASH命令
hash 每次傳輸完數據緩衝區中的數據后就顯示一個#號

演演算法用途


HASH主要用於信息安全領域中加密演演算法,它把一些不同長度的信息轉化成雜亂的128位的編碼里,叫做HASH值. 也可以說,hash就是找到一種數據內容和數據存放地址之間的映射關係。Hash演演算法在信息安全方面的應用主要體現在以下的3個方面:
(1)文件校驗
我們比較熟悉的校驗演演算法有奇偶校驗和CRC校驗,這2種校驗並沒有抗數據篡改的能力,它們一定程度上能檢測並糾正數據傳輸中的通道誤碼,但卻不能防止對數據的惡意破壞。
MD5 Hash演演算法的"數字指紋"特性,使它成為目前應用最廣泛的一種文件完整性校驗和(Checksum)演演算法,不少Unix系統有提供計算md5 checksum的命令。
(2)數字簽名
Hash 演演算法也是現代密碼體系中的一個重要組成部分。由於非對稱演演算法的運算速度較慢,所以在數字簽名協議中,單向散列函數扮演了一個重要的角色。對 Hash 值,又稱"數字摘要"進行數字簽名,在統計上可以認為與對文件本身進行數字簽名是等效的。而且這樣的協議還有其他的優點。
(3)鑒權協議
如下的鑒權協議又被稱作"挑戰--認證模式:在傳輸通道是可被偵聽,但不可被篡改的情況下,這是一種簡單而安全的方法。

hash文件


我們經常在emule日誌裡面看到,emule正在hash文件,這裡就是利用了hash演演算法的文件校驗性這個功能了,文章前面已經說了一些這些功能,其實這部分是一個非常複雜的過程,在ftp,bt等軟體裡面都是用的這個基本原理,emule裡面是採用文件分塊傳輸,這樣傳輸的每一塊都要進行對比校驗,如果錯誤則要進行重新下載,這期間這些相關信息寫入met文件,直到整個任務完成,這個時候part文件進行重新命名,然後使用move命令,把它傳送到incoming文件裡面,然後met文件自動刪除,所以我們有的時候會遇到hash文件失敗,就是指的是met裡面的信息出了錯誤不能夠和part文件匹配,另外有的時候開機也要瘋狂hash,有兩種情況一種是你在第一次使用,這個時候要hash提取所有文件信息,還有一種情況就是上一次你非法關機,那麼這個時候就是要進行排錯校驗了。
關於hash的演演算法研究,一直是信息科學裡面的一個前沿,尤其在網路技術普及的今天,他的重要性越來越突出,其實我們每天在網上進行的信息交流安全驗證,我們在使用的操作系統密鑰原理,裡面都有它的身影,特別對於那些研究信息安全有興趣的朋友,這更是一個打開信息世界的鑰匙,它在hack世界裡面也是一個研究的焦點.

程序實現


// 說明:Hash函數(即散列函數)在程序設計中的應用目標 ------ 把一個對象通過某種轉換機制對應到一個
//size_t類型(即unsigned long)的整型值。
// 而應用Hash函數的領域主要是 hash表(應用非常廣)、密碼等領域。
// 實現說明:
// ⑴、這裡使用了函數對象以及泛型技術,使得對所有類型的對象(關鍵字)都適用。
// ⑵、常用類型有對應的偏特化,比如string、char*、各種整形等。
// ⑶、版本可擴展,如果你對某種類型有特殊的需要,可以在後面實現專門化。
// ⑷、以下實現一般放在頭文件中,任何包含它的都可使用hash函數對象。
//------------------------------------實現------------------------------------------------
#include
using std::string;
inlinesize_thash_str(const char* s)
{
unsigned long res = 0;
for (; *s; ++s)
res = 5 * res + *s;
returnsize_t(res);
}
template
struct hash
{
size_toperator () (const Key& k) const;
};
// 一般的對象,比如:vector< queue >;的對象,需要強制轉化
template < class Key >
size_thash::operator () (const Key& k) const
{
size_tres = 0;
size_tlen = sizeof(Key);
const char* p = reinterpret_cast(&k);
while (len--)
{
res = (res<<1)^*p++;
}
return res;
}
// 偏特化
template<>
size_thash< string >::operator () (const string& str) const
{
return hash_str(str.c_str());
}
typedef char* PChar;
template<>
size_thash::operator () (const PChar& s) const
{
return hash_str(s);
}
typedef const char* PCChar;
template<>
size_thash::operator () (const PCChar& s) const
{
return hash_str(s);
}
template<> size_t hash::operator () (const char& x) const { return x; }
template<> size_t hash::operator () (const unsigned char& x) const { return x; }
template<> size_t hash::operator () (const signed char& x) const { return x; }
template<> size_t hash::operator () (const short& x) const { return x; }
template<> size_t hash::operator () (const unsigned short& x) const { return x; }
template<> size_t hash::operator () (const int& x) const { return x; }
template<> size_t hash::operator () (const unsigned int& x) const { return x; }
template<> size_t hash::operator () (const long& x) const { return x; }
template<> size_t hash::operator () (const unsigned long& x) const { return x; }
// 使用說明:
//
// ⑴、使用時首先由於是泛型,所以要加上關鍵字類型。
//
// ⑵、其次要有一個函數對象,可以臨時、局部、全局的,只要在作用域就可以。
//
// ⑶、應用函數對象作用於對應類型的對象。
//----------------------- hash函數使用舉例 -------------------------
#include
#include
#include
using namespace std;
int main()
{
vector vstr⑵;
vstr[0] = "sjw";
vstr[1] = "suninf";
hash strhash; // 局部函數對象
cout << " Hash value: " << strhash(vstr[0]) << endl;
cout << " Hash value: " << strhash(vstr[1]) << endl;
cout << " Hash value: " << hash< vector >() (vstr) << endl;
cout << " Hash value: " << hash() (100) << endl; // hash() 臨時函數對象
return 0;
}