想快速入门该模块请访问:介绍,数据接口,示例代码
介绍Hash :散列,通过关于键值(key)的函数,将数据映射到内存存储中一个位置来访问。这个过程叫做Hash,这个映射函数称做散列函数,存放记录的数组称做散列表(Hash Table),又叫哈希表。
C语言中没有专门的hash处理函数,因此通常采用第三方编写的库 —— uthash。
uthash是一个使用宏定义处理的C语言哈希表头文件。因此添加uthash只需要 #include “uthash.h” 即可完成高效hash *** 作。
一般采用hash表时,都是希望对某一组数据结构进行高效的增删改查
源码github官网:https://github.com/troydhanson/uthash官方教程官网:https://troydhanson.github.io/uthash/官方参考示例:uthash-master/tests/example.c如果找不到示例代码,也可以参考这个博主摘抄的示例,也来自官方示例https://blog.csdn.net/fan_h_l/article/details/107241520 数据接口 1. 定义hash结构
假设我们要定义一个{ key : value } 为 { id : data }的哈希表,则需要按如下方式进行定义。
typedef struct example_user_t { int id; int data; UT_hash_handle hh; } example_user_t;2. 接口介绍INT类型的接口(宏)
uthash的接口都是宏定义,因此需要了解每个入参到底是变量还是转义标识符。
首先介绍几个概念便于后续理解:
哈希结构 - 代表上文的example_user_t结构体哈希键变量 - 代表上文 int id 中的id哈希键变量的值 - 若上文 int id = 8,那么8就是这个值哈希值变量 - 代表上文的 int data哈希值变量的值 - 代表上文 data的实际值哈希头 - 通常完成一个哈希表的创建后,需要有个哈希头进行索引,每个哈希宏也都需要传入这个参数,通常成为head哈希键值对 - 表示哈希结构申明的指针变量,例如 example_user_t *user;
宏名 用法 含义
创建一个哈稀表完成 int 类型到 StudentInfo 结构体的映射。即 { int: StudentInfo };
实现CRUD增删改查功能
2. 结构设计// 既然使用hash表,首先,建立哈希表结构体[int, StudentInfo, UT_hash_handle] // UT_hash_handle 是建立哈希索引和调用哈希宏所必须的结构体 // 再增加StudentInfo结构体,本案例的内容只有name 和 examPerform,名字和成绩,这可以根据应用场景需要进行额外增加。 // 最后建立g_Class的全局变量用于存放哈希表表头。 typedef struct StudentInfo { char name[50]; int examPerform; } StudentInfo; typedef struct peopleManger_int { int id; StudentInfo *stuInfo; UT_hash_handle hh; } peopleManger_int; peopleManger_int *g_Class;3. uthash函数封装
// 因为我们哈希表的键为int型。因此用到的核心宏是 // HASH_ADD_INT usage:[ HASH_ADD_INT(哈希表头,键变量名,当前增加哈希结构)] // HASH_FIND_INT usage:[ HASH_FIND_INT(哈希表头,键变量的值,用于存放当前当前增加哈希结构)] // HASH_DEL usage:[ HASH_DEL(哈希表头,需要删除的值变量的指针)] // ------------------------------------------------------------------------------------- // 这里的 **item 是外部申明的值变量指针,在内部进行申请内存,因此需要采用双指针表示地址的形式。 static void __createStudent(peopleManger_int **item, int stuID) { *item = (peopleManger_int *)malloc(sizeof(peopleManger_int)); (*item)->id = stuID; HASH_ADD_INT(g_Class, id, *item); } // 这里可以看出,查找HASH_FIND_INT时候,通常会先申请一个空的哈希结构item,然后将全局哈希头中键变量ID的对应的hash结构传给item static peopleManger_int * __findStudent(int stuID) { peopleManger_int *item = NULL; HASH_FIND_INT(g_Class, &stuID, item); return item; } // 哈希删除之后需要释放堆上的空间。 static void __deleteStudent(peopleManger_int *item) { HASH_DEL(g_Class, item); free(item->stuInfo); free(item); }4. 增删改查
// 基于上述封装函数我们可以完成增删改查四个接口 int pm_createStudent(int stuID, char *stuName, int exam) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem != NULL) { printf("has student already, please use updaten"); return -1; } __createStudent(&pmHashItem, stuID); pmHashItem->stuInfo = (StudentInfo *)malloc(sizeof(StudentInfo)); memcpy(pmHashItem->stuInfo->name, stuName, sizeof(char) * (strlen(stuName) + 1)); pmHashItem->stuInfo->examPerform = exam; return 0; } int pm_deleteStudent(int stuID) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem == NULL) { printf("can not find item: %dn", stuID); return -1; } __deleteStudent(pmHashItem); printf("stuID %d delete successfullyn"); return 0; } int pm_updateStudent(int stuID, char *stuName, int exam) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem == NULL) { printf("dont have student already, please use createn"); return -1; } pmHashItem->id = stuID; memset(pmHashItem->stuInfo->name, 0, sizeof(char) * 50); memcpy(pmHashItem->stuInfo->name, stuName, sizeof(char) * (strlen(stuName) + 1)); pmHashItem->stuInfo->examPerform = exam; return 0; } int pm_readStudent(int stuID) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem == NULL) { printf("can not find item: %dn", stuID); return -1; } printf("stu id: %d | ", pmHashItem->id); printf("stu name: %s | ", pmHashItem->stuInfo->name); printf("stu exam: %dn", pmHashItem->stuInfo->examPerform); return 0; }5.遍历打印所有元素
void pm_printStudentName() { peopleManger_int *pmHashItem = NULL; for (pmHashItem = g_Class; pmHashItem != NULL; pmHashItem = (peopleManger_int *)(pmHashItem->hh.next)) { printf("stu %d, name %s, exam = %dn", pmHashItem->id, pmHashItem->stuInfo->name, pmHashItem->stuInfo->examPerform); } }6. 完整代码
#include#include #include #include "uthash.h" typedef struct StudentInfo { char name[50]; int examPerform; } StudentInfo; typedef struct peopleManger_int { int id; StudentInfo *stuInfo; UT_hash_handle hh; } peopleManger_int; peopleManger_int *g_Class; static void __createStudent(peopleManger_int **item, int stuID) { *item = (peopleManger_int *)malloc(sizeof(peopleManger_int)); (*item)->id = stuID; HASH_ADD_INT(g_Class, id, *item); } static peopleManger_int * __findStudent(int stuID) { peopleManger_int *item = NULL; HASH_FIND_INT(g_Class, &stuID, item); return item; } static void __deleteStudent(peopleManger_int *item) { HASH_DEL(g_Class, item); free(item->stuInfo); free(item); } int pm_createStudent(int stuID, char *stuName, int exam) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem != NULL) { printf("has student already, please use updaten"); return -2; } __createStudent(&pmHashItem, stuID); pmHashItem->stuInfo = (StudentInfo *)malloc(sizeof(StudentInfo)); memcpy(pmHashItem->stuInfo->name, stuName, sizeof(char) * (strlen(stuName) + 1)); pmHashItem->stuInfo->examPerform = exam; return 0; } int pm_deleteStudent(int stuID) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem == NULL) { printf("can not find item: %dn", stuID); return -1; } __deleteStudent(pmHashItem); printf("stuID %d delete successfullyn"); return 0; } int pm_updateStudent(int stuID, char *stuName, int exam) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem == NULL) { printf("dont have student already, please use createn"); return -2; } pmHashItem->id = stuID; memset(pmHashItem->stuInfo->name, 0, sizeof(char) * 50); memcpy(pmHashItem->stuInfo->name, stuName, sizeof(char) * (strlen(stuName) + 1)); pmHashItem->stuInfo->examPerform = exam; return 0; } int pm_readStudent(int stuID) { peopleManger_int *pmHashItem = NULL; pmHashItem = __findStudent(stuID); if (pmHashItem == NULL) { printf("can not find item: %dn", stuID); return -1; } printf("stu id: %d | ", pmHashItem->id); printf("stu name: %s | ", pmHashItem->stuInfo->name); printf("stu exam: %dn", pmHashItem->stuInfo->examPerform); return 0; } void pm_printStudentName() { peopleManger_int *pmHashItem = NULL; for (pmHashItem = g_Class; pmHashItem != NULL; pmHashItem = (peopleManger_int *)(pmHashItem->hh.next)) { printf("stu %d, name %s, exam = %dn", pmHashItem->id, pmHashItem->stuInfo->name, pmHashItem->stuInfo->examPerform); } } int main() { int i; peopleManger_int *stu = NULL; printf("-----create element-----n"); for(i = 0; i < 10; i++) { char name[10] = "a_xiao"; name[0] = 'a' + i; printf("here"); pm_createStudent(i, name, 90 + i); } printf("-----read element-----n"); for(stu=g_Class; stu != NULL; stu=(peopleManger_int *)(stu->hh.next)) { printf("stu %d, name %s, exam = %dn", stu->id, stu->stuInfo->name, stu->stuInfo->examPerform); } printf("delete a, go overn"); pm_deleteStudent(0); printf("-----read element-----n"); pm_printStudentName(); pm_updateStudent(1, "xiaoming", 99); pm_updateStudent(0, "xiaohua", 99); pm_readStudent(1); pm_readStudent(0); return 0; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)