❶ 單向散列演算法的常見演算法
常見散列函數(Hash函數)有: MD5(Message Digest Algorithm 5):是RSA數據安全公司開發的一種單向散列演算法,MD5被廣泛使用,可以用來把不同長度的數據塊進行暗碼運算成一個128位的數值。 SHA(Secure Hash Algorithm)這是一種較新的散列演算法,可以對任意長度的數據運算生成一個160位的數值。 MAC(Message Authentication Code):消息認證代碼,是一種使用密鑰的單向函數,可以用它們在系統上或用戶之間認證文件或消息,常見的是HMAC(用於消息認證的密鑰散列演算法)。 CRC(Cyclic Rendancy Check):循環冗餘校驗碼,CRC校驗由於實現簡單,檢錯能力強,被廣泛使用在各種數據校驗應用中。佔用系統資源少,用軟硬體均能實現,是進行數據傳輸差錯檢測地一種很好的手段(CRC 並不是嚴格意義上的散列演算法,但它的作用與散列演算法大致相同,所以歸於此類)。
❷ 什麼是哈希演算法,公式是什麼
哈希是 hash的音譯,就是 散列, 散列演算法是把一系列的值轉換為地址(位置,數字)的一類演算法, 沒有公式. 實際上這不是一種而是一類演算法, 好的散列演算法和不好的散列演算法差別很大. 散列一般是難以反向運算的.原因是輸入和輸出理論上是多對一的操作. (把無限的問題空間映射到有限的地址位置,肯定必須多對一)
加密本質上是換了一種編碼方式,使得不可閱讀. 實際上把英文翻譯成中文,對一個不懂中文的老外來說,這也是一種不嚴密的加密. 加密和散列不同,加密是存在一個解密的演算法的,所以加密運算一般是可逆的, 一般是一對一的.
❸ 什麼是散列法
散列法是把字元串映射到整數的處理,
通常是到一個相對小的范圍。一個
「散列函數」
映射一個字元串
(或其它的數據結構)
到一個有界的數字
(散列存貯桶),這個數字可以更容易的用於數組的索引或者進行反復的比較。明顯的,
一個從潛在的有很多組的字元串到小范圍整數的映射不是唯一的。任何使用散列的演算法都要處理
「沖突」
的可能。有許多散列函數和相關的演算法被開發了出來;
一個全面的說明已經超出了本文的范圍。
❹ 數據結構與演算法之美筆記——散列表(上)
摘要:
我們已經知道隨機訪問數組元素時間復雜度只有 ,效率極高,當我們想利用數組的這個特性時就需要將元素下標與存儲信息對應。例如,一個商店只有四件商品,依次編號 0 至 3,這樣就可以將四件商品信息按照編號對應下標的方式存儲到數組中,依據編號就可以快速從數組中找到相應商品信息。
如果一段時間之後,商店盈利並且重新進貨 100 件商品,商家想對大量商品在編號上區分類別,這時候需要使用類別編號加順序編號的方式標識每件商品,這種編號變得復雜,並不能直接對應數組下標,此時的商品編號又該如何對應數組下標以實現快速查找商品的功能?這時候我們可以將類別編號去除之後按照順序編號對應數組下標,同樣也能享受數組高效率隨機訪問的福利。這個例子中,商品編號稱為「 鍵 」或「 關鍵字 」,將鍵轉化為數組對應下標的方法就是「 散列函數 」或「 Hash 函數 」,由散列函數生成的值叫做「 散列值 」或「 Hash 值 」,而這樣的數組就是散列表。
從散列表的原理來看,數據通過散列函數計算得到散列值是關鍵,這個步驟中散列函數又是其中的核心,一個散列函數需要遵守以下三個原則。
因為散列函數生成的散列值對應數組下標,而數組下標就是非負整數,所以需要滿足第一個原則;兩個相等的數據經過散列演算法得到的散列值肯定相等,否則利用散列值在散列表中查找數據就無從談起;至於第三個原則雖然在情理之中,卻不那麼容易做到,即使是被廣泛運用的散列演算法也會出現散列值沖突的情況,導致無法滿足第三個原則。
散列函數作為散列表的核心部分,必然不能拖散列表的執行效率後腿,畢竟散列表的查詢、插入和刪除操作都需要經過散列函數,所以散列函數不能太復雜,執行效率不能太低。由於散列函數不可避免地都會出現散列沖突情況,散列函數要盡量降低散列沖突,使散列值能夠均勻地分布在散列表中。
解決散列沖突主要有「 開放定址 」(open addressing)和「 鏈表法 」(chaining)兩類方法。
開放定址法是指插入操作時,當生成的散列值對應槽位已經被其他數據佔用,就探測空閑位置供插入使用,其中探測方法又分為「 線性探測 」(Linear Probing)、「 二次探測 」(Quadratic Probing)和「 雙重散列 」(Double hashing)三種。
線性探測是其中較為簡單的一種,這種探測方式是當遇到散列沖突的情況就順序查找(查找到數組尾部時轉向數組頭部繼續查找),直到查找到空槽將數據插入。當進行查找操作時,也是同樣的操作,利用散列值從散列表中取出對應元素,與目標數據比對,如果不相等就繼續順序查找,直到查找到對應元素或遇到空槽為止,最壞情況下查找操作的時間復雜度可能會下降為 。
散列表除了支持插入和查找操作外,當然也支持刪除操作,不過並不能將需刪除的元素置為空。如果刪除操作是將元素置為空的話,查找操作遇到空槽就會結束,存儲在被刪除元素之後的數據就可能無法正確查找到,這時的刪除操作應該使用標記的方式,而不是使用將元素置空,當查找到被標識已刪除的元素將繼續查找,而不是就此停止。
線性探測是一次一個元素的探測,二次探測就是使用都是線性探測的二次方步長探測。例如線性探測是 ,那二次探測對應的就是 。
雙重探測是當第一個散列函數沖突時使用第二個散列函數運算散列值,利用這種方式探測。例如,當 沖突時,就使用 計算散列值,如果再沖突就使用 計算散列值,依此類推。
關於散列表的空位多少使用「 裝載因子 」(load factor)表示,裝載因子滿足數學關系 ,也就是說裝載因子越大,散列表的空閑空間越小,散列沖突的可能性也就越大,一般我們會保持散列表有一定比例的空閑空間。
為了保持散列表一定比例的空閑空間,在裝載因子到達一定閾值時需要對散列表數據進行搬移,但散列表搬移比較耗時。你可以試想下這樣的步驟,在申請一個新的更大的散列表空間後,需要將舊散列表的數據重新通過散列函數生成散列值,再存儲到新散列表中,想想都覺得麻煩。
散列表搬移的操作肯定會降低散列表的操作效率,那能不能對這一過程進行改進?其實可以將低效的擴容操作分攤至插入操作,當裝載因子達到閾值時不一次性進行散列表搬移,而是在每次插入操作時將一個舊散列表數據搬移至新散列表,這樣搬移操作的執行效率得到了提高,插入操作的時間復雜度也依然能保持 的高效。當新舊兩個散列表同時存在時查詢操作就要略作修改,需先在新散列表中查詢,如果沒有查找到目標數據再到舊散列表中查找。
當然,如果你對內存有更高效的利用要求,可以在裝載因子降低至某一閾值時對散列表進行縮容處理。
除了開放定址之外,還可以使用鏈表法解決散列沖突的問題。散列值對應的槽位並不直接存儲數據,而是將數據存儲在槽位對應的鏈表上,當進行查找操作時,根據散列函數計算的散列值找到對應槽位,再在槽位對應的鏈表上查找對應數據。
鏈表法操作的時間復雜度與散列表槽位和數據在槽位上的分布情況有關,假設有 n 個數據均勻分布在 m 個槽位的散列表上,那鏈表法的時間復雜度為 。鏈表法可以不用像開放定址一樣關心裝載因子,但需要注意散列函數對散列值的計算,使鏈表結點能夠盡可能均勻地分布在散列表槽位上,避免散列表退化為鏈表。有時黑客甚至會精心製造數據,利用散列函數製造散列沖突,使數據集中某些槽位上,造成散列表性能的極度退化。
面對這樣的惡意行為散列表只能坐以待斃嗎?其實不然,當槽位上的鏈表過長時,可以將其改造成之前學習過的跳錶等,鏈表改造為跳錶後查詢的時間復雜度也只是退化為 ,依然是可以接受的范圍。
鏈表法在存儲利用上比開放定址更加高效,不用提前申請存儲空間,當有新數據時申請一個新的結點就行。而且鏈表法對裝載因子也不那麼敏感,裝載因子的增高也只是意味著槽位對應的鏈表更長而已,鏈表增長也有將鏈表改造為跳錶等結構的應對策略,所以鏈表法在裝載因子超過 1 的情況下都可保持高效。
開放定址不存在像鏈表法一樣有鏈表過長而導致效率降低的煩惱,不過裝載因子是開放定址的晴雨表,裝載因子過高會造成散列沖突機率的上升,開放定址就需要不斷探測空閑位置,演算法的執行成本會不斷被提高。而且在刪除操作時只能將數據先標記為刪除,對於頻繁增刪的數據效率會受到影響。
當然也可以在這種風險出現前進行散列表的動態擴容,不過這樣就會出現大量空閑的存儲空間,導致存儲的利用效率過低,這種現象在數據量越大的情況下越明顯。所以開放定址比較適用於數據量較小的情況。
鏈表法對於散列沖突的處理更加靈活,同時對存儲空間的利用效率也更高,但鏈表結點除了存儲數據外還需要存儲指針,如果存儲數據較小指針佔用的存儲甚至會導致整體存儲翻倍的情況,但存儲數據較大時指針佔用的存儲也就可以忽略不計,所以鏈表法較適合存儲數據對象較大,但頻繁的增刪操作不會對鏈表法造成明顯的影響。因為這樣的特點,鏈表法更加適合大數據量,或者數據對象較大的時候,如果數據操作頻繁,那鏈表法更是不二之選。
散列表由數組擴展而來,使用散列函數將鍵計算為散列值,散列值對應數據存儲的數組下標。雖然散列表的執行效率較高,但會有散列沖突的問題,可以通過開放定址法和鏈表法解決此問題。
開放定址存儲利用效率較低,適用數據量較小並且增刪不頻繁的情況,如果數據量較大,增刪頻繁的情況更加適用鏈表法,相對之下鏈表法更加普適。
❺ 散列演算法的演算法思想
我也只能說說思想
散列演算法的演算法就是爭取一個蘿卜一個坑的原則
比如說有5個數 12,25,30,45,50,這幾個數有個規律,就是十位數都不相同,
如果我設置一個散列函數f(value)=value/10;平常的時候,我們查找50,要比較
5次(其他演算法可能不同),這里用散列演算法只需要1次,就是解散列函數,key=50/10
=5,要找的數就在第5個位子.但是上面問題還是很多的,比如說查找55呢?就會出
錯<因為55解散列函數之後,也是在第5個位子>,還有等等等問題,很顯然這個是我
散列函數沒設置好,當你把散列函數設置好了後,由於數據的龐大,沖突很有可能
產生,那麼就需要我們來處理沖突了,所以寫散列演算法就是設置好的散列函數和
處理沖突的過程.這里散列演算法涉及的查找就跟查找的數量無關,跟沖突率有直接
的關系
❻ 散列演算法的軟體開發散列演算法
軟體開發 中的散列函數或散列演算法,又稱哈希函數,英語:Hash Function,是一種從任何一種數據中創建小的數字「指紋」的方法。散列函數把消息或數據壓縮成摘要,使得數據量變小,將數據的格式固定下來。該函數將數據打亂混合,重新創建一個叫做散列值的指紋。散列值通常用來代表一個短的隨機字母和數字組成的字元串。好的散列函數在輸入域中很少出現散列沖突。在散列表和數據處理中,不抑制沖突來區別數據,會使得資料庫記錄更難找到。
所有散列函數都有如下一個基本特性:如果兩個散列值是不相同的(根據同一函數),那麼這兩個散列值的原始輸入也是不相同的。這個特性是散列函數具有確定性的結果,具有這種性質的散列函數稱為單向散列函數。但另一方面,散列函數的輸入和輸出不是唯一對應關系的,如果兩個散列值相同,兩個輸入值很可能是相同的。但也可能不同,這種情況稱為「散列碰撞」,這通常是兩個不同長度的散列值,刻意計算出相同的輸出值。輸入一些數據計算出散列值,然後部分改變輸入值,一個具有強混淆特性的散列函數會產生一個完全不同的散列值。
典型的散列函數都有無限定義域,比如任意長度的位元組字元串,和有限的值域,比如固定長度的比特串。在某些情況下,散列函數可以設計成具有相同大小的定義域和值域間的一一對應。一一對應的散列函數也稱為排列。可逆性可以通過使用一系列的對於輸入值的可逆「混合」運算而得到。
由於散列函數的應用的多樣性,它們經常是專為某一應用而設計的。例如,加密散列函數假設存在一個要找到具有相同散列值的原始輸入的敵人。一個設計優秀的加密散列函數是一個「單向」操作:對於給定的散列值,沒有實用的方法可以計算出一個原始輸入,也就是說很難偽造。為加密散列為目的設計的函數,如MD5,被廣泛的用作檢驗散列函數。這樣軟體下載的時候,就會對照驗證代碼之後才下載正確的文件部分。此代碼有可能因為環境因素的變化,如機器配置或者IP地址的改變而有變動。以保證源文件的安全性。
錯誤監測和修復函數主要用於辨別數據被隨機的過程所擾亂的事例。當散列函數被用於校驗和的時候,可以用相對較短的散列值來驗證任意長度的數據是否被更改過。