前面寫過一篇雜湊表在檢索SIP電話中的應用,是在閱讀代碼中遇到的,而專門去學習了雜湊表的基本思想和雜湊函數。下面自己閱讀C演算法精解書籍中自己總結了下面的內容。只總結一小部分,隨後會繼續更新。現在也在學習思維導圖的應用,前面的部落格中已經使用過。下面就利用思維導圖總結的雜湊表的內容:
下面介紹個經典的字串雜湊函數:
/*hashpjw.c*/unsigned int hashpjw(const void *key){ const char *ptr; unsigned int val; val = 0; ptr = key; while (*ptr != '\0'){ unsigned int tmp; val = (val << 4) +(*ptr); if (tmp = (val & 0xf0000000)){ val = val ^ (tmp >> 24); val = val ^ tmp; } ptr++; } return val%PRIME_TBLSIZ //桶的個數}鏈式雜湊表構造圖
鏈式雜湊表的實現和定義
/*chtbl.h*/#ifndef CHTBL_H#define CHTBL_H#include <stdlib.h>/*單鏈表的標頭檔*/#include "list.h"/* 定義一個鏈式雜湊表的結構體*/typedef struct Chtbl_ { int buckets; /*雜湊表分配桶的個數*/ int (*h)(const void *key);/*雜湊函數指標h */ int (*match)(const void *key1,const void *key2);/*判斷2個鍵是否匹配*/ void (*destroy)(void *data);/*釋放記憶體空間*/ int size;/*成員個數*/ List *table;/*雜湊表中鏈表桶的頭指標*/}Chtbl;/* 函數介面*/int chtbl_init (Chtbl *htbl,int buckets,int (*h)(const void *key),int (*match)(const void *key1,const void *key2),void (*destroy)(void *data));int chtbl_destroy (Chtbl *htbl);int chtbl_insert(Chtbl *htbl,const void *data);int chtbl_remove (Chtbl *htbl,void **data);int chtbl_lookup(const Chtbl *htbl,void **data);#define chtbl_size(Chtbl *htbl) ((htbl)->size)#endif
/*chtbl_c*/#include <stdlib.h>#include <string.h>#include "./include/list.h"#include "./include/chtbl.h"/* 初始化雜湊表結構體*/int chtbl_init(Chtbl * htbl, int buckets, int(* h)(const void * key), int(* match)(const void * key1, const void * key2), void(* destroy)(void * data)){ int i; /* 申請空間為桶*/ if ((htbl->table = (List *)malloc(buckets * sizeof(List))) == NULL){ return -1; } /* 初始化雜湊表*/ htbl->buckets = buckets; for (i = 0; i < buckets; i++){ list_init(&htbl->table[i], destroy); } htbl->h = h; htbl->match = match; htbl->destroy = destroy; htbl->size = 0; return 0;}/*雜湊表銷毀*/void chtbl_destroy(Chtbl * htbl){ int i; if (htbl == NULL) return; /*銷毀各個桶*/ for (i = 0; i < htbl->buckets; i++){ list_destory(htbl->table[i]); } /* 釋放hash table 空間*/ free(htbl->table); /*清空htbl結構體*/ memset(htbl,0,sizeof(Chtbl)); return ; }/* 插入資料 * return 成功返回0;失敗返回-1;存在返回1; * */int chtbl_insert(Chtbl * htbl, const void * data){ void *temp; int bucket; int retval; /*如何data已經在雜湊表中返回1*/ temp = (void *)data; if (chtbl_lookup(htbl, &temp) == 0) return 1; /*獲得雜湊鍵*/ bucket = htbl ->h(data) % htbl->buckets; /*插入雜湊表*/ if ((retval = list_ins_next(htbl->table[bucket], NULL, data)) == 0) htbl ->size ++; return retval;}/*刪除資料 *return 成功返回0;失敗返回-1; */int chtbl_remove(Chtbl * htbl, void * * data){ ListElmt *element = NULL; ListElmt *prev = NULL; int bucket = -1; /*獲得雜湊鍵*/ bucket = htbl ->h(*data)%htbl -> buckets; /*尋找在雜湊表中的data*/ for (element = list_head(&htbl->table [bucket]);element != NULL;element = list_next(element)){ if (htbl->match(*data,list_data(element))){ if (list_rem_next(&htbl->table[bucket], prev, data) == 0){ htbl->size --; return 0; } else { return -1; } } prev = element; } return -1;}/* 在雜湊表中尋找元素 *return :如果找到元素返回0;否則返回-1. */int chtbl_lookup(const Chtbl * htbl, void * * data){ ListElmt *element; int bucket; /*獲得雜湊鍵*/ bucket = htbl -> h(*data)%htbl->buckets; /*在雜湊表中尋找元素*/ for (element = list_head(&htbl->table [bucket]);element != NULL;element = list_next(element)){ if (htbl->match(*data,list_data(element))){ *data = list_data(element); return 0; } } return -1;}