uthash的使用

570 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情

简介

在一个项目开发过程中,哈希表在大量数据的处理过程里不可避免的一种数据结构。如果自己构建,算法的设计是个比较复杂的任务。算法好的情况下,可以做到常数插入,常数读取的效率。故不必重复造轮子,有轮子拿来直接用,有兴趣可以拆轮子自己研究一下。 下载地址 :github.com/troydhanson… 文档:troydhanson.github.io/uthash/

全部依赖的文件只有一个头文件,结构上简单粗暴。 可以看一下这个开源项目的结构

image.png src文件夹中就是我们需要依赖的头文件。 头文件使用宏编写,所以编译阶段会直接内链到我们的代码中,效率没有影响。

image.png doc文件夹中包含使用文档。 tests文件夹中包含测试代码。

接口类型

哈希结构体定义

#include "uthash.h"

struct my_struct {
    int id;                    /* key */
    char name[10];
    UT_hash_handle hh;         /* makes this structure hashable */
};
添加
UTHASH_VERSION:版本号
HASH_ADD_INT:添加新节点,键值是整数
HASH_ADD_STR:添加新节点,键值是字符串
HASH_ADD:添加新节点,不关心类型

查找
HASH_FIND_INT: 查找指定的节点,键值是整数
HASH_FIND_STR: 查找指定的节点,键值是字符串
HASH_FIND_PTR: 查找指定的节点,键值是指针
HASH_FIND: 通用的查找指定的节点
删除
HASH_DEL:从哈希表中删除一个指定的节点
HASH_CLEAR:清空表,最好不用,他不会释放由应用深情的资源
遍历
HASH_SORT:安全的遍历所有的哈希节点
计数
HASH_COUNT

接口使用

添加一个节点,键值是整数型

struct my_struct *users = NULL; //初始化为NULL
int  ZAddHash(int KeyId,char* Val)
{
    struct my_struct *s;
    HASH_FIND_INT(users, &KeyId, s);  /* id already in the hash? */
    if(s == NULL) return 1;
    s = malloc(sizeof *s);
    s->id = KeyId;
    strcpy(s->name, Val);
    HASH_ADD_INT(users, id, s);  //这个id是结构体中的id,需一样的名字
    return 0;
}
每一个节点都是应用申请的空间,后续需自己删释放
键值应为都是唯一的,不可重复 ,故先检查是否存在该键值。
查找节点
struct my_struct *find_user(int KeyId) {
    struct my_struct *s;

    HASH_FIND_INT(users, &KeyId, s);  
    return s;
}
此处也可以使用通用的查找接口:HASH_FIND。
如果失败返回NULL
成功,则返回找到的节点地址
删除节点
int delete_user(int KeyId) {
    struct my_struct *user
    HASH_FIND_INT(users, &KeyId, user);  
    if(user == NULL) return 1;
    HASH_DEL(users, user);  /* user: pointer to deletee */
    free(user);             /* optional; it's up to you! */
    return 0;
}
按照键值,先查找,找到后删除节点,并释放资源
成功返回0
失败返回1,指找不到节点
清空hash表
#typedef void (*func)(int a,void*b)
int clearHash(func Ops) 
{
    struct my_struct *current_user, *tmp;
    HASH_ITER(hh, users, current_user, tmp) {
        Ops(1,NULL)
        HASH_DEL(users, current_user);  /* delete; users advances to next */
        free(current_user);             /* optional- if you want to free  */
    }
    users = NULL
    return 0;
}
 定义一个函数指针,在清空表的时候,顺便可以执行一下我们想做的操作

代码

#include<stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<uthash.h>

struct my_struct {
    int id;                
    char name[10];
    UT_hash_handle hh;     
};

struct my_struct *users = NULL; //初始化为NULL
int  ZAddHash(int KeyId,char* Val)
{
    struct my_struct *s;
    HASH_FIND_INT(users, &KeyId, s);  /* id already in the hash? */
    if(s == NULL) return 1;
    s = malloc(sizeof *s);
    s->id = KeyId;
    strcpy(s->name, Val);
    HASH_ADD_INT(users, id, s);  //这个id是结构体中的id,需一样的名字
    return 0;
}
struct my_struct *find_user(int KeyId) {
    struct my_struct *s;

    HASH_FIND_INT(users, &KeyId, s);  
    return s;
}

int delete_user(int KeyId) {
    struct my_struct *user
    HASH_FIND_INT(users, &KeyId, user);  
    if(user == NULL) return 1;
    HASH_DEL(users, user);  /* user: pointer to deletee */
    free(user);             /* optional; it's up to you! */
    return 0;
}

#typedef void (*func)(int a,void*b)
int clearHash(func Ops) 
{
    struct my_struct *current_user, *tmp;
    HASH_ITER(hh, users, current_user, tmp) {
        if(Ops)Ops(1,current_user)
        HASH_DEL(users, current_user);  /* delete; users advances to next */
        free(current_user);             /* optional- if you want to free  */
    }
    users = NULL
    return 0;
}

void PrintfNode(int a,void * ptr)
{
    struct my_struct *user = (struct my_struct *)ptr;
    printf(" name[%s]\n",user->name);
}

int main(int argc, char** argv)
{
    char in[10];
    int id=1, 
    struct my_struct *s;

    for(int i = 0;i < 20;i++){
        ZAddHash(i,"this is test!!");
    }
    clearHash(PrintfNode);
    return 0;
}

实现的结构并没有全部调用,实现了对添加节点和清空表的测试。