在HashTable中,用到了DList来解决冲突,我们不用重新实现其内部的DList,只需将已经实现的双向链表DList组合到HashTable中使用即可。下面给出工程的全部代码:
1. Makefile
-D name: Predefine name as a macro. (man gcc可以看到)
2. typedef.h
#include <stdio.h> #include <assert.h> #include <stdlib.h> #ifndef TYPEDEF_H #define TYPEDEF_H typedef enum _Ret { RET_OK, RET_OOM, RET_STOP, RET_INVALID_PARAMS, RET_FAIL }Ret; typedef void (*DataDestroyFunc)(void* ctx, void* data); typedef int (*DataCompareFunc)(void* ctx, void* data); typedef Ret (*DataVisitFunc)(void* ctx, void* data); typedef int (*DataHashFunc)(void* data); #ifdef __cplusplus #define DECLS_BEGIN extern "C" { #define DECLS_END } #else #define DECLS_BEGIN #define DECLS_END #endif/*__cplusplus*/ #define return_if_fail(p) if(!(p)) \ {printf("%s:%d Warning: "#p" failed.\n", \ __func__, __LINE__); return;} #define return_val_if_fail(p, ret) if(!(p)) \ {printf("%s:%d Warning: "#p" failed.\n",\ __func__, __LINE__); return (ret);} #define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;} typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp); #endif/*TYPEDEF_H*/
3. hash_table.h
#include <stdio.h> #include "typedef.h" #ifndef HASH_TABLE_H #define HASH_TABLE_H DECLS_BEGIN struct _HashTable; typedef struct _HashTable HashTable; HashTable* hash_table_create(DataDestroyFunc data_destroy, void* ctx, DataHashFunc hash, int slot_nr); size_t hash_table_length(HashTable* thiz); Ret hash_table_insert(HashTable* thiz, void* data); Ret hash_table_delete(HashTable* thiz, DataCompareFunc cmp, void* data); Ret hash_table_find(HashTable* thiz, DataCompareFunc cmp, void* data, void** ret_data); Ret hash_table_foreach(HashTable* thiz, DataVisitFunc visit, void* ctx); void hash_table_destroy(HashTable* thiz); DECLS_END #endif/*HASH_TABLE*/
4.hash_table.c
#include "dlist.h" #include "hash_table.h" struct _HashTable { DataHashFunc hash; DList** slots; size_t slot_nr; DataDestroyFunc data_destroy; void* data_destroy_ctx; }; HashTable* hash_table_create(DataDestroyFunc data_destroy, void* ctx, DataHashFunc hash, int slot_nr) { HashTable* thiz = NULL; return_val_if_fail(hash != NULL && slot_nr > 1, NULL); thiz = (HashTable*)malloc(sizeof(HashTable)); if(thiz != NULL) { thiz->hash = hash; thiz->slot_nr = slot_nr; thiz->data_destroy_ctx = ctx; thiz->data_destroy = data_destroy; if((thiz->slots = (DList**)calloc(sizeof(DList*)*slot_nr, 1)) == NULL) { free(thiz); thiz = NULL; } } return thiz; } Ret hash_table_insert(HashTable* thiz, void* data) { size_t index = 0; return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); index = thiz->hash(data)%thiz->slot_nr; if(thiz->slots[index] == NULL) { thiz->slots[index] = dlist_create(thiz->data_destroy, thiz->data_destroy_ctx); } return dlist_prepend(thiz->slots[index], data); } Ret hash_table_delete(HashTable* thiz, DataCompareFunc cmp, void* data) { int index = 0; DList* dlist = NULL; return_val_if_fail(thiz != NULL && cmp != NULL, RET_INVALID_PARAMS); index = thiz->hash(data)%thiz->slot_nr; dlist = thiz->slots[index]; if(dlist != NULL) { index = dlist_find(dlist, cmp, data); return dlist_delete(dlist, index); } return RET_FAIL; } size_t hash_table_length(HashTable* thiz) { size_t i = 0; size_t nr = 0; return_val_if_fail(thiz != NULL, 0); for(i = 0; i < thiz->slot_nr; i++) { if(thiz->slots[i] != NULL) { nr += dlist_length(thiz->slots[i]); } } return nr; } Ret hash_table_find(HashTable* thiz, DataCompareFunc cmp, void* data, void** ret_data) { int index = 0; DList* dlist = NULL; return_val_if_fail(thiz != NULL && cmp != NULL && ret_data != NULL, RET_INVALID_PARAMS); index = thiz->hash(data)%thiz->slot_nr; dlist = thiz->slots[index]; if(dlist != NULL) { index = dlist_find(dlist, cmp, data); return dlist_get_by_index(dlist, index, ret_data); } return RET_FAIL; } Ret hash_table_foreach(HashTable* thiz, DataVisitFunc visit, void* ctx) { size_t i = 0; return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS); for(i = 0; i < thiz->slot_nr; i++) { if(thiz->slots[i] != NULL) { dlist_foreach(thiz->slots[i], visit, ctx); } } return RET_OK; } void hash_table_destroy(HashTable* thiz) { size_t i = 0; if(thiz != NULL) { for(i = 0; i < thiz->slot_nr; i++) { if(thiz->slots[i] != NULL) { dlist_destroy(thiz->slots[i]); thiz->slots[i] = NULL; } } free(thiz->slots); free(thiz); } return; } #ifdef HASH_TABLE_TEST #include "test_helper.c" int main(int argc, char* argv[]) { int i = 0; int n = 10000; int ret_data = 0; HashTable* hash_table = hash_table_create(NULL, NULL, hash_int, 31); for(i = 0; i < n; i++) { assert(hash_table_length(hash_table) == i); assert(hash_table_insert(hash_table, (void*)i) == RET_OK); assert(hash_table_length(hash_table) == (i + 1)); assert(hash_table_find(hash_table, cmp_int, (void*)i, (void**)&ret_data) == RET_OK); assert(ret_data == i); } for(i = 0; i < n; i++) { assert(hash_table_delete(hash_table, cmp_int, (void*)i) == RET_OK); assert(hash_table_length(hash_table) == (n - i -1)); assert(hash_table_find(hash_table, cmp_int, (void*)i, (void**)&ret_data) != RET_OK); } hash_table_destroy(hash_table); return 0; } #endif/*HASH_TABLE_TEST*/
5. 最后来复习一下以前写的几个文件
typedef.h
#include <stdio.h> #include <assert.h> #include <stdlib.h> #ifndef TYPEDEF_H #define TYPEDEF_H typedef enum _Ret { RET_OK, RET_OOM, RET_STOP, RET_INVALID_PARAMS, RET_FAIL }Ret; typedef void (*DataDestroyFunc)(void* ctx, void* data); typedef int (*DataCompareFunc)(void* ctx, void* data); typedef Ret (*DataVisitFunc)(void* ctx, void* data); typedef int (*DataHashFunc)(void* data); #ifdef __cplusplus #define DECLS_BEGIN extern "C" { #define DECLS_END } #else #define DECLS_BEGIN #define DECLS_END #endif/*__cplusplus*/ #define return_if_fail(p) if(!(p)) \ {printf("%s:%d Warning: "#p" failed.\n", \ __func__, __LINE__); return;} #define return_val_if_fail(p, ret) if(!(p)) \ {printf("%s:%d Warning: "#p" failed.\n",\ __func__, __LINE__); return (ret);} #define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;} typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp); #endif/*TYPEDEF_H*/
dlist.h
#include <stdio.h> #include "typedef.h" #ifndef DLIST_H #define DLIST_H DECLS_BEGIN struct _DList; typedef struct _DList DList; DList* dlist_create(DataDestroyFunc data_destroy, void* ctx); Ret dlist_insert(DList* thiz, size_t index, void* data); Ret dlist_prepend(DList* thiz, void* data); Ret dlist_append(DList* thiz, void* data); Ret dlist_delete(DList* thiz, size_t index); Ret dlist_get_by_index(DList* thiz, size_t index, void** data); Ret dlist_set_by_index(DList* thiz, size_t index, void* data); size_t dlist_length(DList* thiz); int dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx); Ret dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx); void dlist_destroy(DList* thiz); DECLS_END #endif/*DLIST*/