UTHash使用教程

UTHash使用教程

快速入门

想快速入门该模块请访问:介绍,数据接口,示例代码

介绍

Hash散列,通过关于键值(key)的函数,将数据映射到内存存储中一个位置来访问。这个过程叫做Hash,这个映射函数称做散列函数,存放记录的数组称做散列表(Hash Table),又叫哈希表

C语言中没有专门的hash处理函数,因此通常采用第三方编写的库 —— uthash

uthash是一个使用宏定义处理的C语言哈希表头文件。因此添加uthash只需要 #include “uthash.h” 即可完成高效hash操作。

一般采用hash表时,都是希望对某一组数据结构进行高效的增删改查

数据接口

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;
宏名用法含义
HASH_ADD_INTusage:[ HASH_ADD_INT(head, id, user) ]在head增加一个INT键变量id所对应的键值对结构,该结构内容为user
HASH_FIND_INTusage:[ HASH_FIND_INT(head, &user_id, user) ]在head查找INT类型键变量的值user_id所对应的键值对结构user
HASH_DELusage:[ HASH_DEL(head, user)]删除head中,键值对结构为user的键值对结构

uthash INT 示例代码:学生管理系统

1. 整体思路如下
  • 创建一个哈稀表完成 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 update\n");
		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: %d\n", stuID);
		return -1;
	}

	__deleteStudent(pmHashItem);
	printf("stuID %d delete successfully\n");
	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 create\n");
		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: %d\n", stuID);
		return -1;
	}

	printf("stu id: %d  | ", pmHashItem->id);
	printf("stu name: %s | ", pmHashItem->stuInfo->name);
	printf("stu exam: %d\n", 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 = %d\n", pmHashItem->id, pmHashItem->stuInfo->name, pmHashItem->stuInfo->examPerform);
    }
}
6. 完整代码
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#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 update\n");
		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: %d\n", stuID);
		return -1;
	}

	__deleteStudent(pmHashItem);
	printf("stuID %d delete successfully\n");
	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 create\n");
		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: %d\n", stuID);
		return -1;
	}

	printf("stu id: %d  | ", pmHashItem->id);
	printf("stu name: %s | ", pmHashItem->stuInfo->name);
	printf("stu exam: %d\n", 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 = %d\n", pmHashItem->id, pmHashItem->stuInfo->name, pmHashItem->stuInfo->examPerform);
    }
}

int main()
{
    int i;
    peopleManger_int *stu = NULL;

    /* create elements */
    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 = %d\n", stu->id, stu->stuInfo->name, stu->stuInfo->examPerform);
    }

    printf("delete a, go over\n");
    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;
}
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值