Hash-雜湊/雜湊 基礎知識梳理
字典的兩種描述方法:跳錶和雜湊(hash)
限制適用範圍:有序陣列
採用雜湊技術將記錄儲存在一塊連續的儲存空間中,這塊連續的儲存空間愛你被稱為散列表或者雜湊表。
雜湊技術是在記錄的儲存位置和他的關鍵字之間建立一個確定的對應關係f(雜湊函式),使得每個關鍵字key對應一個儲存位置f(key),根據這個對應關係找到給定值key的對映f(key),如果查詢集合中存在這個記錄,則必定在f(key)的位置上。
最常用的除法對映:f(k)=k%D
k是關鍵字,D是散列表的大小,f(k)對應為雜湊地址
hash:把任意長度的輸入(預對映pre-image),通過雜湊演算法變成固定長度的輸出,該輸出就是雜湊值,這是一種壓縮對映,雜湊值的空間通常遠遠小於輸入的空間,不同的輸入可能會被雜湊成相同的輸出,因此不能從雜湊值來唯一的確定輸入值。
hash就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要函式。
應用領域:資訊保安領域的加密演算法(如不同長度的資訊被轉換成雜亂無章的128位編碼值)
線性表、樹、圖等結構,其中的資料元素之間存在某種邏輯關係。可以連線圖示比奧斯,而雜湊技術的記錄之間不存在邏輯關係,只是和關鍵字相關。雜湊技術既是一種儲存方法也是一種查詢方法。
雜湊主要是面向查詢的儲存結構,最適合查詢與給定值相等的記錄,
不適合範圍:查詢和一個關鍵字對應很多記錄的查詢,最大值最小值查詢,記錄的排序,限制範圍查詢
雜湊函式的構造:計算簡單、雜湊地址分佈均勻
原來的關鍵字-------依據某種規律變成另一組數字
直接定址法--線性條件
數字分析法---關鍵字的位數較大,且關鍵字的若干位分佈較均勻
平方取中法---關鍵字分佈未知,位數不大
摺疊法 ----關鍵字分佈未知,位數較多
隨機數法------關鍵字長度不等時比較合適
除留餘數法----關鍵在於選擇合適的p,散列表表長為m,通常m為小於或者等於表長(最好接近)的最小指數或不包含小於20質因數的合數
雜湊函式選擇需要考慮的因素:
計算雜湊地址所需要的時間
關鍵字的長度
散列表的大小
關鍵字的分佈情況
記錄查詢的頻率
雜湊衝突的處理:
開放定址法 一旦發生衝突,就去尋找下一個空的雜湊地址,只要散列表足夠大,空的雜湊地址總能被找到,記錄會被存入。是一種線性探測的方法
再雜湊函式法
鏈地址法 在當前位置給單鏈表增加節點
公共溢位區法 衝突的關鍵字放在另外的公共溢位區來存放
散列表查詢演算法實現:
hashtable就是散列表結構、elem是一個動態陣列
#define success 1
#define unsuccess 0
#define hashsize 12 //散列表長是陣列的長度
#define nullkey -32768
typedef struct
{
int *elem; // 陣列元素儲存的基址,動態分配陣列
int count; //當前資料元素個數
} hashtable;
int m=0;//散列表表長 全域性變數
status InitHashTable(HashTable *H)
{
int i;
m=hashsize;
H->count =m;
H->elem=(int *)malloc(m*sizeof(int));
for (int i=0;i<m;i++)
H->elem[i]=nullkey;
return ok;
}
//雜湊函式
int hash(int key)
{
retrun key % m;//除留餘數法
}
//插入關鍵字進行散列表
void inserthash(hashtable *H,int key)
{
int addr =hash(key);//雜湊地址
while(H->elem[addr]!=nullkey)
addr=(addr+1)%m;
H->elem[addr]=key;
}
//查詢關鍵字
status searchhash(hashtable H,int key,int *addr)
{
*addr=hash(key);
while(H.elem[*addr]!=key)
{
*addr=(*addr+1)%m;
if (H.elem[*addr]==nullkey||*addr==hash(key))
{
retrun unsuccess;
}
}
return success;
}