我是靠谱客的博主 美满彩虹,最近开发中收集的这篇文章主要介绍LINUX中哈希表的原理与应用,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1. 哈希表的定义

linux-5.11.6include/linux/types.h    //linux中关于哈希表结构体的定义
struct hlist_head {
	struct hlist_node *first;
};

struct hlist_node {
	struct hlist_node *next, **pprev;
};

整个哈希表结构如下图所示,其中ppre是个二级指针,它指向前一个节点的第一个指针变量,例如node1的ppre指向mylist的first指针,node2的ppre指向node1的next指针。

 2. 哈希表的声明和初始化、节点增加、遍历等

 (1)哈希表的声明和初始化
linux-5.11.6includelinuxlist.h
//hlist数据结构的操作函数和宏
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
	h->next = NULL;
	h->pprev = NULL;
}

(2)在哈希表中增加节点
在内核代码list.h中增加节点的函数为:
//把一个哈希链表的节点插入到哈希链表的头节点的后边
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
//把一个节点插入到一个哈希链表的节点的前边
static inline void hlist_add_before(struct hlist_node *n,
					struct hlist_node *next)
static inline void hlist_add_behind(struct hlist_node *n,
				    struct hlist_node *prev)
static inline void hlist_add_fake(struct hlist_node *n)

(3)遍历哈希表
linux-5.11.6includelinuxlist.h
#define hlist_for_each(pos, head) 
	for (pos = (head)->first; pos ; pos = pos->next)

头插法增加节点参考下图:

        hlist_add_before作用是把一个节点插入到一个哈希链表的节点的前边,首先把将要插入的节点的pprev成员变量指向next的前边的节点,要插入的节点的next指向下一个节点,然后next节点的pprev就要指向已经插入的节点的next节点的地址,已经插入的节点的pprev指向的前一个节点的值就要变成已经插入节点的地址

static inline void hlist_add_before(struct hlist_node *n,
					struct hlist_node *next)
{
	n->pprev = next->pprev;
	n->next = next;
	next->pprev = &n->next;
	*(n->pprev) = n;
}

内核驱动代码如下:

// hashlist.c
// Created by linux on 2020/9/25.
//
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/list.h>

#define N 10
//数字链表
struct numlist{
    struct hlist_head hlistHead;
};
//数字链表节点
struct numnode{
    int num;
    struct hlist_node hlistNode;
};
struct  numlist nhead;
struct  numnode nnode;

static int __init hlist_init(void){
    //init head node
    struct hlist_node *pos;
    struct numnode *listnode;
    int i;
    struct numnode *p;

    printk("hashlist is starting...n");
    //初始化头节点
    INIT_HLIST_HEAD(&nhead.hlistHead);

    for ( i = 0; i < N; ++i) {
        listnode = (struct numnode *)kmalloc(sizeof(struct numnode),GFP_KERNEL);
        listnode->num = i + 1;

        //头插法,添加节点在头节点之前
        hlist_add_head(&(listnode->hlistNode), &nhead.hlistHead);
        printk("Node %d has added to the hash list...n",i+1);
    }
    //遍历链表
    i = 1;
    hlist_for_each(pos, &nhead.hlistHead){	//移动pos的值
        //使用contain_of, 根据元素hlistNode的值得到用户结构指针
        p = hlist_entry(pos, struct numnode, hlistNode);
        printk("Node %d data:%dn",i,p->num);
        i++;
    }
    return 0;
}

static void __exit hashlist_exit(void){
    struct hlist_node *pos,*n;
    struct numnode *p;
    int i;

    i = 1;
    //遍历数字链表,根据链表头hlistHead遍历
    hlist_for_each_safe(pos,n,&nhead.hlistHead){
        hlist_del(pos);		//删除哈希节点
        //取得删除节点的数据域值
        p = hlist_entry(pos,struct numnode,hlistNode);
        kfree(p);
        printk("Node %d has removed from the hashlist ...n",i++);
    }
    printk("hash list is exiting...n");
}

module_init(hlist_init);
module_exit(hashlist_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("linux");


Makefile

obj-m := hashlist.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH :=/usr/src/linux-headers-$(LINUX_KERNEL)

all:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

执行结果:

本文来自于:LINUX中哈希表的原理与应用

最后

以上就是美满彩虹为你收集整理的LINUX中哈希表的原理与应用的全部内容,希望文章能够帮你解决LINUX中哈希表的原理与应用所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部