前面對鏈式雜湊表的定義、實現、分析的一下,感覺也不是想象中的那麼難,只要把思路理清,在草稿紙上畫下他的實現思路,代碼閱讀起來也就一目瞭然了。下次再看時,只要把當初畫的草圖一拿出來就知道,當初定義的函數介面:插入、刪除、尋找是怎麼實現的。資料結構本身就是很抽象的東西。對初學者來說,畫草圖是很容易理解代碼實現思路。 下面介紹另外一種雜湊表的實現方法 :開地址雜湊表的描述。 在鏈式雜湊表中,元素存在在每個地址的桶中。而開地址雜湊表,元素存放在表本身中。因為註定不能和鏈式雜湊表一樣解決衝突。在開地址雜湊表中解決衝突的方式就是探查這個表,直到找個放這個元素的槽,或者找到這個元素。當然如果遍曆完整個表也沒有找到這個元素,說明元素沒有在表中。 檢索雜湊表的效率主要有2個因素有關:雜湊表的負載因子(元素的總個數處於桶的個數)和 元素均勻分布的程度。線性探查 線性探查的雜湊函數定義:h(k,i) = (h`(k)+i)mod m ,k是鍵(插入的元素),i表示探查的次數,i是大於等於0小於m.m槽個數。h`是一個輔助雜湊函數。h`=k mod m.下面一個簡單例子介紹下:雙散列 最有效探查開地址雜湊表的方法之一,就是通過計算兩個輔助雜湊函數雜湊編碼的和來得到雜湊編碼。雙散列的雜湊函數定義為:h(k,i) = (h1(k) + ih2(k)) mod m h1和 h2是兩個輔助雜湊函數
開地址雜湊表的實現和分析疑問:就是結構體中定義的一個變數vacated 在代碼中的作用:個人理解沒有起到什麼實質的作用,就是儲存了上一次刪除操作的一個位置~。有其他更好理解的給解釋下~
/*ohtbl.h*/#ifndef OHTBL_H#define OHTBL_H#include <stdlib.h>/*定義開地址雜湊表結構體*/typedef struct Ohtbl_{ int positions;/*槽位的個數*/ void *vacated;/*指標將被初始化來指向一個特殊的地址空間, 來證明這個特殊地址上曾經刪除過一個元素*/ int (*h1)(const void * key); int (*h2)(const void *key); int (*match)(const void *key1,const void *key2); void (*destroy)(void *data); int size;/*元素的個數*/ void **table;/*儲存元素的數組(malloc申請)*/}Ohtbl;/*函數介面*/int ohtbl_init(Ohtbl *htbl,int positions,int (*h1)(const void *key),int (*h2)(const void *key),int (*match)(const void *key1,const void *key2),void (*destroy)(void *data));void ohtbl_destroy(Ohtbl *htbl);int ohtbl_insert(Ohtbl *htbl,const void *data);int ohtbl_remove(Ohtbl *htbl,void **data);int ohtbl_lookup(const Ohtbl *htbl,void **data);#define ohtbl_size(htbl) ((htbl) ->size)#endif
/*ohtbl.c*/#include <stdlib.h>#include <string.h>#include "./include/ohtbl.h"/*預訂一個記憶體地位為騰出的元素*/static char vacated;/*結構體初始化 *return 初始化成功: 0, 失敗:-1. */int ohtbl_init(Ohtbl * htbl, int positions, int(* h1)(const void * key), int(* h2)(const void * key), int(* match)(const void * key1, const void * key2), void(* destroy)(void * data)){ int i; /*申請空間為雜湊表*/ if ((htbl ->table = (void **)malloc(positions *sizeof(void *))) == NULL) return -1; /*初始化每個positions*/ htbl ->positions = positions; for (i = 0; i < htbl->positions; i++) htbl -> table[i] = NULL; /*設定騰出成員的記憶體位址*/ htbl->vacated = &vacated; /*初始化封裝的函數*/ htbl -> h1 = h1; htbl -> h2 = h2; htbl ->match = match; htbl ->destroy = destroy; /*初始化元素個數*/ htbl ->size = 0; return 0;}/*開地址雜湊表銷毀 * * */ int ohtbl_destroy(Ohtbl * htbl){ int i; if (htbl ->destroy !=NULL){ /*使用使用者定義的函數去釋放存放資料的記憶體*/ for (i = 0; i < htbl ->positions; i++){ if (htbl ->table[i] != NULL && htbl ->table[i] != htbl ->vacated) htbl ->destroy(htbl ->table[i]); } } /*釋放table 記憶體*/ free(htbl ->table); /*清空雜湊表結構體*/ memest(htbl,0,sizeof(Ohtbl)); return;}/* 雜湊表中插入元素 *return 初始化成功: 0, 失敗:-1. * 資料已經在雜湊表內返回:1 */int ohtbl_insert(Ohtbl * htbl, const void * data){ void *temp; int position = 0; int i = 0; /*但雜湊表已經滿的話返回-1*/ if (htbl ->size == htbl ->positions) return -1; /*如果資料已經在雜湊表內,返回1*/ temp = (void *)data; if (ohtbl_lookup(htbl, &temp) == 0) return 1; /*找到雜湊編碼值存在資料*/ for (i = 0; i <htbl -> positions; i++){ /*獲得雜湊編碼值*/ position = (htbl->h1(data) + i * htbl ->h2(data)) %htbl ->positions; if (htbl ->table[position] == NULL || htbl ->table[position] ==htbl ->vacated){ /*插入資料*/ htbl ->table[position] = (void *)data; htbl ->size ++; return 0; } } return -1;}/* 刪除雜湊表數值 *return 初始化成功: 0, 失敗:-1. */int ohtbl_remove(Ohtbl * htbl, void * * data){ int i = 0; int position = 0; if (htbl ->size == 0) return -1; for (i = 0; i <htbl -> positions; i++){ /*獲得雜湊編碼值*/ position = (htbl->h1(data) + i * htbl ->h2(data)) %htbl ->positions; if (htbl ->table[position] == NULL){/*表明元素未存放到雜湊表內*/ return -1; } else if (htbl ->table[position] == htbl ->vacated){ /*搜尋vacated 之外*/ continue; } else if(htbl -> match(htbl->table[position],*data)){ *data = htbl->table[position]; htbl->table[position] = htbl ->vacated; htbl->size --; return 0; } } return -1}/*尋找資料 *return 初始化成功: 0, 失敗:-1. */int ohtbl_lookup(const Ohtbl * htbl, void * * data){ int position = 0; int i = 0; for (i = 0; i <htbl -> positions; i++){ /*獲得雜湊編碼值*/ position = (htbl->h1(data) + i * htbl ->h2(data)) %htbl ->positions; if (htbl ->table[position] == NULL){/*表明元素未存放到雜湊表內*/ return -1; } else if(htbl -> match(htbl->table[position],*data)){ *data = htbl->table[position]; return 0; } } return -1;}