1. 哈希的定义
在数据元素的存储位置和它的关键字之间建立一个映射关系f,通过f可以直接得到关键字所代表的数据元素
2. 哈希表
哈希技术中用于存储数据元素的数据结构
3. 哈希函数
哈希技术中的映射关系f
4. 哈希技术的关键点
① 哈希表:哈希技术需要具体的数据结构为基础,如数组、链表、二叉树......
②哈希函数:哈希技术需要映射关键字和数据元素的存储位置,依赖于数学运算,如四则运算、逻辑运算、比较......
5. 哈希的操作
① 创建哈希: Hash* Hash_Create();
② 销毁哈希: void Hash_Destroy(Hash* hash);
③ 清空哈希: void Hash_Clear(Hash* hash);
④ 加入键值对: int Hash_Add(Hash* hash, HashKey* key, HashValue* value);
⑤ 删除键值对: HashValue* Hash_Remove (Hash* hash, HashKey* key);
⑥ 根据建获取值: HashValue* Hash_Get(Hash* hash, HashKey* key);
⑦ 获取键值对数目: int Hash_Count(Hash* hash);
6. 哈希的实现
哈希表 = 数组 + 链表
① DList.h
#ifndef DLIST_H #define DLIST_H typedef enum _Ret { RET_OK, RET_OOM, RET_STOP, RET_PARAMS, RET_FAIL } Ret; struct _DList; typedef struct _DList DList; typedef void (*DListDataDestroyFunc)(void* ctx, void* data); typedef int (*DListDataCompareFunc)(void* ctx, void* data); typedef Ret (*DListDataVisitFunc)(void* ctx, void* data); DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_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, DListDataCompareFunc cmp, void* ctx); Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx); void dlist_destroy(DList* thiz); #endif
② DList.c
#include <stdlib.h> #include "DList.h" typedef struct _DListNode { struct _DListNode* prev; struct _DListNode* next; void* data; }DListNode; struct _DList { DListNode* first; DListDataDestroyFunc data_destroy; void* data_destroy_ctx; }; static void dlist_destroy_data(DList* thiz, void* data) { if(thiz->data_destroy != NULL) { thiz->data_destroy(thiz->data_destroy_ctx, data); } return; } static DListNode* dlist_create_node(DList* thiz, void* data) { DListNode* node = malloc(sizeof(DListNode)); if(node != NULL) { node->prev = NULL; node->next = NULL; node->data = data; } return node; } static void dlist_destroy_node(DList* thiz, DListNode* node) { if(node != NULL) { node->next = NULL; node->prev = NULL; dlist_destroy_data(thiz, node->data); free(node); } return; } DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx) { DList* thiz = malloc(sizeof(DList)); if(thiz != NULL) { thiz->first = NULL; thiz->data_destroy = data_destroy; thiz->data_destroy_ctx = data_destroy_ctx; } return thiz; } static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last) { DListNode* iter = thiz->first; while(iter != NULL && iter->next != NULL && index > 0) { iter = iter->next; index--; } if(!fail_return_last) { iter = index > 0 ? NULL : iter; } return iter; } Ret dlist_insert(DList* thiz, size_t index, void* data) { DListNode* node = NULL; DListNode* cursor = NULL; if((node = dlist_create_node(thiz, data)) == NULL) { return RET_OOM; } if(thiz->first == NULL) { thiz->first = node; return RET_OK; } cursor = dlist_get_node(thiz, index, 1); if(index < dlist_length(thiz)) { if(thiz->first == cursor) { thiz->first = node; } else { cursor->prev->next = node; node->prev = cursor->prev; } node->next = cursor; cursor->prev = node; } else { cursor->next = node; node->prev = cursor; } return RET_OK; } Ret dlist_prepend(DList* thiz, void* data) { return dlist_insert(thiz, 0, data); } Ret dlist_append(DList* thiz, void* data) { return dlist_insert(thiz, -1, data); } Ret dlist_delete(DList* thiz, size_t index) { DListNode* cursor = dlist_get_node(thiz, index, 0); if(cursor != NULL) { if(cursor == thiz->first) { thiz->first = cursor->next; } if(cursor->next != NULL) { cursor->next->prev = cursor->prev; } if(cursor->prev != NULL) { cursor->prev->next = cursor->next; } dlist_destroy_node(thiz, cursor); } return RET_OK; } Ret dlist_get_by_index(DList* thiz, size_t index, void** data) { DListNode* cursor = dlist_get_node(thiz, index, 0); if(cursor != NULL) { *data = cursor->data; } return cursor != NULL ? RET_OK : RET_FAIL; } Ret dlist_set_by_index(DList* thiz, size_t index, void* data) { DListNode* cursor = dlist_get_node(thiz, index, 0); if(cursor != NULL) { cursor->data = data; } return cursor != NULL ? RET_OK : RET_FAIL; } size_t dlist_length(DList* thiz) { size_t length = 0; DListNode* iter = thiz->first; while(iter != NULL) { length++; iter = iter->next; } return length; } Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx) { Ret ret = RET_OK; DListNode* iter = thiz->first; while(iter != NULL && ret != RET_STOP) { ret = visit(ctx, iter->data); iter = iter->next; } return ret; } int dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx) { int i = 0; DListNode* iter = thiz->first; while(iter != NULL) { if(cmp(ctx, iter->data) == 0) { break; } i++; iter = iter->next; } return i; } void dlist_destroy(DList* thiz) { DListNode* iter = thiz->first; DListNode* next = NULL; while(iter != NULL) { next = iter->next; dlist_destroy_node(thiz, iter); iter = next; } thiz->first = NULL; free(thiz); return; }
③ HashTable.h
#ifndef HASHTABLE_H_ #define HASHTABLE_H_ #include "DList.h" typedef int(*DataHashFunc)(void* data); typedef DListDataDestroyFunc DataDestroyFunc; typedef DListDataCompareFunc DataCompareFunc; typedef DListDataVisitFunc DataVisitFunc; typedef struct HashTable_ { DataHashFunc hashFunc; DList** slots; int slotNr; DataDestroyFunc dataDestroy; void* dataDestroyCtx; } HashTable; HashTable* HashTableCreate(DataDestroyFunc dataDestroy, void* ctx, DataHashFunc hashFunc, int slotNr); Ret HashTableInsert(HashTable* hashTable, void* data); Ret HashTableDelete(HashTable* hashTable, DataCompareFunc cmp, void* data); Ret HashTableFind(HashTable* hashTable, DataCompareFunc cmp, void* data, void** retData); int HashTableLength(HashTable* hashTable); Ret HashTableForeach(HashTable* hashTable, DataVisitFunc visit, void* ctx); void HashTableDestroy(HashTable* hashTable); #endif
④ HashTable.c
#include <stdlib.h> #include <stdio.h> #include <string.h> #include "HashTable.h" HashTable* HashTableCreate(DataDestroyFunc dataDestroy, void* ctx, DataHashFunc hashFunc, int slotNr) { HashTable* pNewHashTable = (HashTable*)malloc(sizeof(HashTable)); if(pNewHashTable != NULL) { pNewHashTable->hashFunc = hashFunc; pNewHashTable->slotNr = slotNr; pNewHashTable->dataDestroy = dataDestroy; pNewHashTable->dataDestroyCtx = ctx; pNewHashTable->slots = (DList**)malloc(slotNr * sizeof(DList*)); if(pNewHashTable->slots != NULL) { memset(pNewHashTable->slots, 0, (slotNr * sizeof(DList*))); } else { free(pNewHashTable); pNewHashTable = NULL; } } return pNewHashTable; } Ret HashTableInsert(HashTable* hashTable, void* data) { Ret ret = RET_FAIL; int index = 0; if(hashTable != NULL) { index = hashTable->hashFunc(data) % hashTable->slotNr; if(hashTable->slots[index] == NULL) { hashTable->slots[index] = dlist_create(hashTable->dataDestroy, hashTable->dataDestroyCtx); } dlist_append(hashTable->slots[index], data); ret = RET_OK; } return ret; } Ret HashTableDelete(HashTable* hashTable, DataCompareFunc cmp, void* data) { Ret ret = RET_FAIL; int index = 0; DList* dList = NULL; if(hashTable != NULL) { index = hashTable->hashFunc(data) % hashTable->slotNr; dList = hashTable->slots[index]; if(dList != NULL) { index = dlist_find(dList, cmp, data); dlist_delete(dList, index); ret = RET_OK; } } return ret; } Ret HashTableFind(HashTable* hashTable, DataCompareFunc cmp, void* data, void** retData) { Ret ret = RET_FAIL; int index = 0; DList* dList = NULL; if(hashTable != NULL && cmp != NULL && data != NULL && retData != NULL) { index = hashTable->hashFunc(data) % hashTable->slotNr; dList = hashTable->slots[index]; if(dList != NULL) { index = dlist_find(dList, cmp, data); dlist_get_by_index(dList, index, retData); ret = RET_OK; } } return ret; } int HashTableLength(HashTable* hashTable) { int sum = 0; int index = 0; if(hashTable != NULL) { for(index = 0; index < hashTable->slotNr; index++) { if(hashTable->slots[index] != NULL) { sum = sum + dlist_length(hashTable->slots[index]); } } } return sum; } Ret HashTableForeach(HashTable* hashTable, DataVisitFunc visit, void* ctx) { int index = 0; if(hashTable != NULL) { for(index = 0; index < hashTable->slotNr; index++) { if(hashTable->slots[index] != NULL) { dlist_foreach(hashTable->slots[index], visit, ctx); } } } return RET_OK; } void HashTableDestroy(HashTable* hashTable) { int index = 0; if(hashTable != NULL) { if(hashTable->slots != NULL) { for(index = 0; index < hashTable->slotNr; index++) { if(hashTable->slots[index] != NULL) { dlist_destroy(hashTable->slots[index]); hashTable->slots[index] = NULL; } } free(hashTable->slots); hashTable->slots = NULL; } free(hashTable); hashTable = NULL; } }
注:数组是最简单的哈希实现