hlist原本是定义在内核list.h里面的结构体,主要用在解决哈希表冲突时使用链接(chaining)方法时候用到的结构体。结构体定义简单、相关的接口也比较丰富,可以直接拿到用户层使用。最常见的一种使用场景如下图:

htable是hash数组,每个数组元素是一个hlist_head结构体。当多个结点的hash key值相同时,直接添加在对应的结点链表里就可以了。下面介绍相关数据结构和操作接口使用。

链表头和结点的结构体定义:

/* 链表头 */
struct hlist_head {struct hlist_node *first;
};/* 链表结点,具体的数据结构体只需要包含这个结构体就可以了 */
struct hlist_node {struct hlist_node *next, **pprev;
}; 

链表头和结点使用前需要初始化:

//hlist_head 初始化
#define HLIST_HEAD_INIT { .first = NULL }    //静态初始化
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) //动态初始化//hlist_node 初始化
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{h->next = NULL;h->pprev = NULL;
}

常用接口包括添加、删除和修改:

//添加结点至链表首部
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h);
//删除前有判断
static inline void hlist_del_init(struct hlist_node *n);
//判断链表头是否为空,是的话返回1
static inline int hlist_empty(const struct hlist_head *h);
//遍历结点
hlist_for_each(pos, head) //遍历结点过程中有删除结点操作使用这个接口
hlist_for_each_safe(pos, n, head) 
//遍历获取结点里的数据
hlist_for_each_entry(tpos, pos, head, member)
//遍历结点过程中有删除结点操作使用这个接口
hlist_for_each_entry_safe(tpos, pos, n, head, member)    

假设结点结构体定义如下;

//结点结构体
struct hdata_node {unsigned int data;struct hlist_node list;
};

下面是一个小李子,采用除法散列法计算hash值,结点定义如上,包含添加、删除和查询操作。

/**  Description : linux应用层编程之哈希链表hlist的使用*  Date        :20180713*  Author      :fuyuande*  Mail        : mrsonko@126.com**/#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>#include "hlistdemo.h"#define log(fmt, arg...) printf(""fmt,##arg)
#define MAX_ADDR 256void main(int argc, char **argv){struct hlist_head htable[MAX_ADDR];     //hash数组struct hdata_node *hnode = NULL;struct hlist_node *hlist = NULL, *n = NULL;int i = 0, quit = 1, opt = 0, key;unsigned int data;/* hlist_head 动态初始化 */for(i = 0; i < MAX_ADDR; i++)        //hash数组动态初始化INIT_HLIST_HEAD(&htable[i]);log("*********************\n\n""input options:\n""1: insert\n"           //插入"2: serach\n"           //查询"3: delete\n"           //删除"0: quit\n""\n*********************\n");  while(quit != 0){log("\ninput options:");scanf("%d",  &opt);switch(opt){//插入case  1://分配结点hnode = calloc(1, sizeof(struct hdata_node));if(!hnode){log("insert fail \n");break;}//hlist_node 结点初始化INIT_HLIST_NODE(&hnode->list);log("\ninput data:");scanf("%d",  &hnode->data);key = hnode->data % MAX_ADDR;//添加到链表首部hlist_add_head(&hnode->list, &htable[key]);break;//查询case  2:log("\ninput data:");scanf("%d",  &data);         key = data % MAX_ADDR;if(hlist_empty(&htable[key]))log("data not exist \n");else{//遍历对应的槽位,匹配值就打印hlist_for_each_entry(hnode, hlist, &htable[key], list){if(hnode->data == data)log("find data : %u \n", hnode->data);}}                break;//删除case  3:log("\ninput data:");scanf("%d",  &data);         key = data % MAX_ADDR;if(hlist_empty(&htable[key]))log("data not exist ,delete fail \n");else{//遍历对应的槽,匹配值就删除hlist_for_each_entry_safe(hnode, hlist, n, &htable[key], list){if(hnode->data == data){hlist_del(&hnode->list);break;}}}                            log("delete fail\n");                break;case 0:quit = 0;break;default:log("unrecognized option!");break;                }}//退出程序前释放资源for(i=0; i < MAX_ADDR; i++){//遍历每一个槽,有结点就删除hlist_for_each_entry_safe(hnode, hlist, n, &htable[i], list){           hlist_del(&hnode->list); log("delete %u \n", hnode->data);free(hnode);hnode = NULL;}}log("exit\n");
}

代码放在:git@github.com:FuYuanDe/hlist_demo.git

git clone之后直接make运行。

またね!

Linux环境编程 哈希链表结构 hlist 介绍与用例相关推荐

  1. 林世霖. linux环境编程图文指南,linux环境编程图文指南

    linux环境编程图文指南是一本linux编程环境配置指南,由林世霖.钟锦辉和李建辉三人共同编著.本书定位Linux环境编程入门与提高,全书拥有近400余幅案例图表,200多篇源代码,作者很多编程初入 ...

  2. linux 应用层编程之内核链表list的使用

    linux内核提供了一个经典通用的双向循环链表list的实现,任何模块都可以借助该接口实现自己的内部循环链表.因为是通用的,可以直接移植到用户态中使用,下面介绍相关的接口与一个简单操作例子,包括链表的 ...

  3. Linux 环境编程 day01 Linux系统介绍、GNU编译工具、静态/共享库、环境变量表

    Linux 环境编程 day01 Linux系统介绍.GNU编译工具.静态/动态库.环境变量表 学习Linux环境编程的原因 UNIX系统介绍 Linux系统介绍 GNU工程 POSIX标准 GNU通 ...

  4. linux环境编程从应用,linux环境编程:从应用到内核

    <UNIX环境高级编程>(简称APUE)几乎是Linux领域程序员人手必备的一本书.但在掌握和理解APUE的内容后,又该如何继续提高自己的技能,如何更深入地理解Linux环境编程及其背后的 ...

  5. Linux环境编程(4)文件操作相关内容补充

    Linux环境编程(4) 文件同步: 1.在写入数据时内存与磁盘之间也有一个缓冲区,这种机制降低了磁盘读写次数,提高了读写的效率. 2.但这种机制带来的后果就是磁盘中的数据与实写入的数据不匹配,系统提 ...

  6. Linux 环境编程 用户层定时器使用二 timer_create的使用

    用户层定时器有两种,一种是timerfd,另一种是timer_create,前者比较新,使用比较方便. Linux环境编程 用户层定时器使用一 timerfd的使用 https://blog.csdn ...

  7. 嵌入式Linux系统编程学习之一目录结构

    嵌入式Linux系统编程学习之一目录结构 文章目录 嵌入式Linux系统编程学习之一目录结构 前言 一.Linux目录结构 前言 Linux目录结构 一.Linux目录结构 /bin:存放Linux的 ...

  8. Linux环境编程05

    目录 Linux环境编程05 一.信号相关基本概念 二.信号捕获 三.进程休眠信号 四.信号集和信号阻塞 五.附带数据信息的信号处理(较难) 六.定时器 Linux环境编程05 声明:本学习笔记为个人 ...

  9. Linux环境编程姜林美,Linux环境编程习题_编程题_答案.pdf

    Linux环境编程习题_编程题_答案 Linux 境编程-人民邮电出版社-姜林美 课后习题(编程题)答案 第三章 1 第五章 4 第六章 9 第七章 19 第八章 22 第九章 35 第十章 38 三 ...

最新文章

  1. Android7.0以后的ninja编译系统
  2. java乘法代码_java九九乘法表代码
  3. 排名 教材 数字电子技术_数字电子技术教材改革及实践
  4. 面试自我介绍优秀范文
  5. python实用脚本(三)—— 通过有道智云API实现翻译
  6. 偏差、误差、训练误差、测试误差
  7. 【MATLAB】创建网格图和曲面图
  8. Arcgis10.8中将三维的高程点转换为二维的高程点
  9. KV存储相关基础知识
  10. 苹果设备如何进入恢复模式
  11. pitfall override private method
  12. java 枚举values()方法
  13. 21种优化产品转化率的设计技巧
  14. 【应用随机过程】04. 马尔可夫链的平稳分布
  15. 一篇文章普及各种ios基本知识
  16. 莫比乌斯函数(Mobius)的求法 每日一遍,算法再见!
  17. 未来计算机的特点是什么,【简答题】未来计算机的发展将会呈现以下几个趋势:...
  18. Ubuntu与ROS的Docker桌面系统与ROS在线练习课程(在线Linux虚拟机)
  19. 魔塔之拯救白娘子~我的第一个VB6+DX8做的小游戏源码~14开始游戏-流程处理
  20. 卡巴斯基CEO称勒索病毒为最严重的网络攻击之一

热门文章

  1. MERGE INTO
  2. 成功人士,默默做的30件事 (4-6)
  3. 篝火 2004 年11-15
  4. python优先队列_python实现最大优先队列
  5. 学python还是php2019_有2019年开始学PHP的人吗,可不可以分享一下你是如何考虑的?...
  6. 空间到底是什么?---車粒子
  7. python tushare获取股票数据_Python 金融: TuShare API 获取股票数据 (1)
  8. 【Paper】An Experiment Comparing Double Exponential Smoothing and Kalman Filter-Based Predict
  9. 【Matlab 控制】利用 Simulink 对微分代数方程建模
  10. 【数理知识】《随机过程》方兆本老师-第3章-Markov 过程