uthash

2023-11-15

在软件开发中,不可不免的会使用到hash表,hash表的优点这里就不说了,以下介绍一个hash表的C实现,

uthash是用宏实现的,使用的时候非常方便,只用包含uthash.h即可。

Uthash的三个数据结构:

1. typedef struct UT_hash_bucket {

   struct UT_hash_handle *hh_head;

   unsigned count;

   unsigned expand_mult;

} UT_hash_bucket;

UT_hash_bucket作用提供根据hash进行索引。

2.typedef struct UT_hash_table {

   UT_hash_bucket *buckets;

   unsigned num_buckets, log2_num_buckets;

   unsigned num_items;

   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */

   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ 

   unsigned ideal_chain_maxlen;

   unsigned nonideal_items;             

   unsigned ineff_expands, noexpand;

   uint32_t signature; /* used only to find hash tables in external analysis */

#ifdef HASH_BLOOM

   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */

   uint8_t *bloom_bv;

   char bloom_nbits;

#endif

} UT_hash_table;

UT_hash_table可以看做hash表的表头。

3. typedef struct UT_hash_handle {

   struct UT_hash_table *tbl;

   void *prev;                       /* prev element in app order      */

   void *next;                       /* next element in app order      */

   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */

   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */

   void *key;                        /* ptr to enclosing struct's key  */

   unsigned keylen;                  /* enclosing struct's key len     */

   unsigned hashv;                   /* result of hash-fcn(key)        */

} UT_hash_handle;

UT_hash_handle,用户自定义数据必须包含的结构。

三种数据结构的关系如下:

说明:

每一个节点(用户自定义的)必须包含一个UT_hash_handle hh

key:用户自定义,可以是int, string和指针。

hh_prev: 指向前一个UT_hash_handle 

hh_next: 指向下一个UT_hash_handle

hashv:根据key计算出的hash

prev: 指向前一个数据节点(Hash冲突时)

next: 指向下一个数据节点(Hash冲突时)

hho: 数据节点中hh于用户节点首地址的差。

--------------------------------------------我是分割线---------------------------------------

二、uthash的基本用法

由于C语言中,并没有对hash表这类的高级数据结构进行支持,即使在目前通用的C++中,也只支持栈、队列等几个数据结构,对于map,其实是以树结构来实现的,而不是以hash表实现。

uthash是一个C语言的hash表实现。它以宏定义的方式实现hash表,不仅加快了运行的速度,而且与关键类型无关的优点。

uthash使用起来十分方便,只要将头文件uthash.h包含进去就可以使用。

目前,uthash的最新版本(1.9)支持如下平台:

  • Linux
  •   Mac OS X
  • Windows using vs2008 and vs 2010
  • Solaris
  • OpenBSD

 

      通常这足够通用了。唯一的不足是在windows下,在uthash这旧版本中,并不支持vs2008和2010,而是支持MinGW。

 uthash支持:增加、查找、删除、计数、迭代、排序、选择等操作。

第一步:包含头文件

[c-sharp] view plaincopy
  1. #include "uthash.h"  
 

第二步:自定义数据结构。每个结构代表一个键-值对,并且,每个结构中要有一个UT_hash_handle成员。

[c-sharp] view plaincopy
  1. struct my_struct {  
  2. int id; /* key */  
  3. char name[10];  
  4. UT_hash_handle hh; /* makes this structure hashable */  
  5. };  
 

第三步:定义hash表指针。这个指针为前面自定义数据结构的指针,并初始化为NULL。

[c-sharp] view plaincopy
  1. struct my_struct *users = NULL; /* important! initialize to NULL */  
 

第四步:进行一般的操作。

增加:

[c-sharp] view plaincopy
  1. int add_user(int user_id, char *name) {  
  2. struct my_struct *s;  
  3. s = malloc(sizeof(struct my_struct));  
  4. s->id = user_id;  
  5. strcpy(s->name, name);  
  6. HASH_ADD_INT( users, id, s ); /* id: name of key field */  
  7. }  
 

查找:

[c-sharp] view plaincopy
  1. struct my_struct *find_user(int user_id) {  
  2. struct my_struct *s;  
  3. HASH_FIND_INT( users, &user_id, s ); /* s: output pointer */  
  4. return s;  
  5. }  
 

删除:

[c-sharp] view plaincopy
  1. void delete_user(struct my_struct *user) {  
  2. HASH_DEL( users, user); /* user: pointer to deletee */  
  3. free(user); /* optional; it’s up to you! */  
  4. }  
 

计数:

[c-sharp] view plaincopy
  1. unsigned int num_users;  
  2. num_users = HASH_COUNT(users);  
  3. printf("there are %u users/n", num_users);  
 

迭代:

[c-sharp] view plaincopy
  1. void print_users() {  
  2. struct my_struct *s;  
  3. for(s=users; s != NULL; s=s->hh.next) {  
  4. printf("user id %d: name %s/n", s->id, s->name  
  5. }  
  6. }  
 

排序:

[c-sharp] view plaincopy
  1. int name_sort(struct my_struct *a, struct my_struct *b) {  
  2. return strcmp(a->name,b->name);  
  3. }  
  4. int id_sort(struct my_struct *a, struct my_struct *b) {  
  5. return (a->id - b->id);  
  6. }  
  7. void sort_by_name() {  
  8. HASH_SORT(users, name_sort);  
  9. }  
  10. void sort_by_id() {  
  11. HASH_SORT(users, id_sort);  
  12. }  
 

要注意,在uthash中,并不会对其所储存的值进行移动或者复制,也不会进行内存的释放。




--------------------------------------------我是分割线---------------------------------------

uthash使用代码例子

  1. #include "uthash.h"  
  2. #include <stdlib.h>   /* malloc */  
  3. #include <stdio.h>    /* printf */  
  4. #include <time.h>  
  5.   
  6. typedef struct example_user_t {  
  7.     int id;  
  8.     int cookie;  
  9.     UT_hash_handle hh;  
  10. } example_user_t;  
  11.   
  12. int main(int argc,char *argv[]) {  
  13.     int i;  
  14.     example_user_t *user, *users=NULL;  
  15.   
  16.     srand((unsigned int)time(NULL));  
  17.     /* create elements */  
  18.     for(i=0;i<10;i++) {  
  19.         if ( (user = (example_user_t*)malloc(sizeof(example_user_t))) == NULL) exit(-1);  
  20.         user->id = rand()%100;  
  21.         user->cookie = i*i;  
  22.         HASH_ADD_INT(users,id,user);  
  23.     }  
  24.   
  25.     for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) {  
  26.         printf("user %d, cookie %d\n", user->id, user->cookie);  
  27.     }  
  28.    return 0;  


---------------------------------我是分割线-------------------------------------

4. 其他类型key的使用

  本节主要关于key值类型为其他任意类型,例如整型、字符串、指针、结构体等时的用法。

  注意:在使用key值为浮点类型时,由于浮点类型的比较受到精度的影响,例如:1.0000000002被认为与1相等,这些问题在uthash中也存在。

  4.1. int类型key

  前面就是以int类型的key作为示例,总结int类型key使用方法,可以看到其查找和插入分别使用专用接口:HASH_FIND_INT和ASH_ADD_INT。

  4.2. 字符指针char*类型key与字符数组char key[100]类型key

  特别注意在Strting类型中,uthash对指针char*和字符数组(例如char key[100])做了区分,这两种情况下使用的接口函数时不一样的。在添加的时候,key的类型为指针时使用接口函数HASH_ADD_KEYPTR,key的类型为字符数组时,使用接口函数HASH_ADD_STR,除了添加的接口不一样外,其他的查找、删除、变量等接口函数都是一样的。

  4.3.使用地址作为key

  在uthash中也可使用地址做key进行hash操作,使用地址作为key值时,其类型为void*,这样它就可以支持任意类型的地址了。在使用地址作为key时,插入和查找的专用接口函数为HASH_ADD_PTR和HASH_FIND_PTR,其余接口是一样的。

  4.3.其他非常用类型key

  在uthash中还可使用结构体作为key,甚至可以采用组合的方式让多个值作为key,这些在其官方的网站张均有较详细的使用示例。在使用uthash需要注意以下几点:

  在定义hash结构体时不要忘记定义UT_hash_handle的变量

  需确保key值唯一,如果插入key-value对时,key值已经存在,再插入的时候就会出错。

  不同的key值,其增加和查找调用的接口函数不一样,具体可见第4节。一般情况下,不通类型的key,其插入和查找接口函数是不一样的,删除、遍历、元素统计接口是通用的,特殊情况下,字符数组和字符串作为key值时,其插入接口函数不一样,但是查找接口是一样的
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

uthash 的相关文章

  • SQL 查询指定行数的数据。

    今天遇到一个关于 查询指定行数的数据 的sql查询语句问题 突然发现以前没怎么接触过 刚才想起来了 赶紧看了下文档 又上网搜了下 有了下面的东西 不知道有没有什么地方不对 oracle 先看一下文档中关于any和all的例子 很不错噢 An
  • 多线程系列之——事件内核对象

    所有内核对象里面事件内核对象是最简单的一个 它包括一个使用计数 还有两个布尔值 一个布尔值用来表示事件是手动重置事件还是自动重置事件 另一个布尔值表示当前是否处于触发状态 当一个手动重置事件被触发的时候 所有等待该事件的线程都能变成调度状态
  • C语言pcre库的使用及验证IP地址的合法性

    PCRE是一个用C语言编写的正则表达式函数库 它十分易用 同时功能也很强大 性能超过了POSIX正则表达式库和一些经典的正则表达式库 在使用PCRE库时 首先肯定是需要安装pcre的 不过一般的系统都会有自带的PCRE库 不过如果想使用最新
  • JNA模拟复杂的C类型——Java映射char*、int*、float*、double*

    文章目录 引言 Java Native Type Conversions Java和C基本类型指针对应关系 Pointer的具体用法 引言 最近项目在用Java调用C写的一些三方库 没办法直接调 用Java封装一下C的接口 这就少不了要用到
  • 写时拷贝技术(copy-on-write)

    传统的fork 系统调用直接把所有的资源复制给新创建的进程 这种实现过于简单并且效率低下 因为它拷贝的数据也许并不共享 更糟的情况是 如果新进程打算立即执行一个新的映像 那么所有的拷贝都将前功尽弃 Linux的fork 使用写时拷贝 cop
  • c++得到窗口句柄

    include
  • LeetCode题目笔记——17.19消失的两个数字

    文章目录 题目描述 题目难度 困难 方法一 暴力 代码 代码优化 方法二 数学方法 代码 总结 题目描述 题目直达 题目难度 困难 方法一 暴力 虽然题目说你能在 O N 时间内只用 O 1 的空间找到它们吗 但是也没有限制我们不能用暴力
  • 值得学习与推荐的c/c++框架和函数库

    这几天不上班 翻翻Evernote中记录的一些笔记 刚好有时间把记录的一些好玩链接转载一下 这篇文章里提到的很多库都用过 尤其是图像处理相关库 尤其是opencv及cximage 当时做图像算法时 很多算法就是从上面找来 然后自己修改的 比
  • Trace Function Enter, Exit and Leave

    http developer nokia com community wiki Trace Function Enter Exit and Leave
  • Dev-C++之开启装逼效果

    Dev C 是个不错的C IDE 在10年前 它是很不错 在现在 它是个以界面丑陋和调试像吃粑粑这两点著称 如下图 实在是丑到离谱 丑到无法忍受 可是没办法呀 人家CCF规定比赛用这个 你个小蒟蒻吵什么 我现在就来讲讲怎么把你的Dev C
  • 在聚会中常玩数七的游戏,七的倍数和带有七的数字都不能说,比如14,27,28。请找出1~100的不能说的数字。...

    利用ES5的filter高阶函数来实现 var arr 1 2 3 4 5 6 7 17 27 21 22 28 100 r arr filter function x return x 10 7 x 7 0 alert r 7 14 17
  • C++学习笔记12:输入输出流实例整理(文本文件读写,二进制文件读写,一组数据的文件读写,随机访问文件实例

    这也太难记了555老阔疼 文件读写示例 include
  • enable_shared_from_this使用介绍

    文章目录 enable shared from this定义 使用场合 源码实现 注意 enable shared from this定义 定义于头文件 template lt class T gt class enable shared
  • C++中的并发多线程网络通讯

    C 中的并发多线程网络通讯 一 引言 C 作为一种高效且功能强大的编程语言 为开发者提供了多种工具来处理多线程和网络通信 多线程编程允许多个任务同时执行 而网络通信则是现代应用程序的基石 本文将深入探讨如何使用C 实现并发多线程网络通信 并
  • C/C++编程:令人印象深刻的高级技巧案例

    C C 编程语言在软件开发领域有着悠久的历史 由于其高效 灵活和底层访问能力 至今仍然被广泛应用 本文将介绍一些在C C 编程中令人印象深刻的高级技巧 帮助读者提升编程水平 更加高效地使用这两种强大的编程语言 一 指针运算与内存管理 C C
  • C 语言运算符详解

    C 语言中的运算符 运算符用于对变量和值进行操作 在下面的示例中 我们使用 运算符将两个值相加 int myNum 100 50 虽然 运算符通常用于将两个值相加 就像上面的示例一样 它还可以用于将变量和值相加 或者将变量和另一个变量相加
  • C 语言文件读取全指南:打开、读取、逐行输出

    C 语言中的文件读取 要从文件读取 可以使用 r 模式 FILE fptr 以读取模式打开文件 fptr fopen filename txt r 这将使 filename txt 打开以进行读取 在 C 中读取文件需要一点工作 坚持住 我
  • C++ 中 const 和 constexpr 关键字解析:常量、函数和指针

    很多 C 的初学者看到 const 这个关键字的第一反应都是一头雾水 主要是因为 const 可 以出现在很多的位置 以及后面加入的 constexpr 更是常常感到困惑 今天就为大家一一解释出现它们的含义和以及作用 const 关键字 c
  • C++中的引用

    一 引用的概念 引用不是新定义一个变量 而是给已有变量取一个别名 编译器不会为引用变量开辟内存空间 而和它引用的变量共用一块内存空间 注意 由于C 兼容C 所以 既可以是引用符号 也可以是取地址 int a 0 int b a cout l
  • 在 OS X 上的 virtualenv 中安装 scrapy 加密时发生错误 [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我正在安装 scrapypip in virtualenv on OS X 10 11 当它安装密码学时 它说 buil

随机推荐

  • 二叉树的性质

    二叉树的性质以及满二叉树 完全二叉树 性质一 在二叉树的第i层 最多有2的 i 1 次方个结点i gt 1 性质二 深度为k的二叉树上最多有含有2的k次方 1个结点 k gt 1 性质三 对于任何一个二叉树 若它含有n0个叶子结点 n2个度
  • Spring Bean自动装配的简介

    转自 Spring Bean自动装配的简介说明 Spring Bean装配为依赖关系注入 Spring Bean装配方式称之为 Spring Bean依赖注入方式Spring Bean容器拥有多种装配Bean方式 如 使用XML 装配Bea
  • 数据科学—K均值算法实践

    K均值算法实践 问题描述 目标 数据集 分析 算法阐述 代码实现 结果 问题描述 现在有一组数据 需要通过聚类方法发掘其内在结构 目标 对数据进行聚类分析 将数据分为四类 k 4 数据集 clusterdata txt存储待聚类数据 共包含
  • jQuery操作CheckBox的方法(选中,取消,取值)详解

  • 通讯协议024——全网独有的OPC AE知识四之接口(八)

    本文简单介绍OPC AE规范的IOPCEventAreaBrowser接口的相关知识 更多通信资源请登录网信智汇 wangxinzhihui com OPC AE规范描述了OPC事件服务器应该实现的对象和接口 实现在多个OPC客户端间共享事
  • 2.5.6 共享分区CPU分配

    最后更新2021 07 27 共享分区CPU分配这个动作是系统Hypervisor自动完成的 我们只能通过HMC定义规则 但不能直接干预 CPU分配受几个限定参数影响 分别是Physical Processor 物理CPU 分配数量 Vir
  • Spring MVC视图解析器简介说明

    转自 Spring MVC视图解析器简介说明 Spring MVC视图解析器简介说明 下文讲述 Spring MVC视图 的相关说明 如下所示 Spring 视图解析器 Spring视图解析器用于对Spring中的视图进行解析 如下配置所示
  • 大话西游详细解读

    其实要理清 大话西游 的脉络 只要弄清楚命运对至尊宝的安排 和他面对命运和爱情的心路历程就够了 如果再理一下紫霞和白晶晶的故事 大话西游 的故事就纤毫毕现了 如下 至尊宝的故事 无奈的命运与无望的爱至尊宝原来是家在五岳山第四编101号B1的
  • 2023年IT行业就业前景分析,准职场人必看!

    随着疫情的放开 2022已接近尾声 新的一年即将来临 作为打工人最关心的肯定是2023年的就业市场以及行业未来发展前景 如何最直观地看待这个行业是否还有前景 最好的方式就是看市场需求 作为准职场人的你 速速关注起来 根据智联招聘10月发布的
  • 学习笔记——JDBC

    初识JDBC 文章目录 初识JDBC 一 JDBC是什么 二 使用步骤 1 JDBC开发前的准备工作 1 1 下载对应驱动的jar包 1 2 针对文本编辑器的方式开发的配置 1 3针对编译软件 例如IDEA开发的配置 2 JDBC编程 2
  • 立创梁山派GD32F450ZGT6--屏幕扩展板LVGL应用

    该文章工程是基于裸机情况下运行的LVGL 通过GUI Guider 1 4 0进行页面布局配置 一 介绍 GUI Guider是恩智浦为LVGL开发了一个上位机GUI设计工具 可以通过拖放控件的方式设计LVGL GUI页面 加速GUI的设计
  • 大语言模型之十-Byte Pair Encoding

    Tokenizer 诸如GPT 3 4以及LlaMA LlaMA2大语言模型都采用了token的作为模型的输入输出 其输入是文本 然后将文本转为token 正整数 然后从一串token 对应于文本 预测下一个token 进入OpenAI官网
  • 攻防世界 Morse writeup

    题目 三 题型 crypto 题目 Morse 来源 攻防世界 https adworld xctf org cn challenges list 思路 直接利用摩斯密码进行解密 具体步骤 Step1 根据题目猜测是摩斯密码 Step2 将
  • 2019最近计算机毕业设计-题目汇总大全-系列5

    javaweb python爱好者 如果对以下项目感兴趣可以邮箱 cswork2019 163 com 与我沟通交流 课题名称 备注 区块链交易信息的获取与可视化分析 基于2D物理引擎 液体 的H5小游戏 基于Cocos2D的微信小游戏的设
  • 高校圆桌派第三期话题征集强势来袭~

    高校圆桌派 话题风暴等你来 即日起参与 高校圆桌派 活动 就有机会获得CSDN高校圆桌大礼包和CSDN周边礼品免费包邮送到家 高校圆桌派第二期话题征集结果公示 1 刚毕业的程序员有必要执着于进入大厂吗 小厂和大厂怎么选择 2 新能源汽车行业
  • 最简单的获取安卓应用sha1值的方法

    每个安卓应用都有一个签名证书 签名证书可以由jdk生成 当证书生成后 证书就有其sha1值 md5值和sha256值 使用此证书打包后的apk 也有其一样的sha1值 md5值和sha256值 有两种方法可以获取sha1值 1 解压apk
  • 百度:度度熊有一个N个数的数组,他想将数组从大到小排好序...

    度度熊有一个N个数的数组 他想将数组从大到小排好序 但是萌萌的度度熊只会下面这个操作 任取数组中的一个数然后将它放置在数组的最后一个位置 问最少操作多少次可以使得数组从小到大有序 输入描述 首先输入一个正整数N 接下来的一行输入N个整数 N
  • 缤纷多彩的404页面(404.html)

    文章来源 https www skyqian com archives 404 Pages html 一般而言 第一时间会在博客更新 CSDN随缘更新 引言 别离滋味浓于酒 著人瘦 此情不及墙东柳 春色年年如旧 勿埋我心 404是个很常见的
  • Redis以及Jedis的GEO地图功能

    Redis以及Jedis的GEO地图功能 引言 redis是一个高性能的非关系型数据库 作为一个单线程的应用程序 速度非常快 并且不存在多线程情况下的共同资源访问锁的问题 PS 太久没有写文章 老脸一红 今日记录一下Redis的地图坐标功能
  • uthash

    在软件开发中 不可不免的会使用到hash表 hash表的优点这里就不说了 以下介绍一个hash表的C实现 uthash是用宏实现的 使用的时候非常方便 只用包含uthash h即可 Uthash的三个数据结构 1 typedef struc