Linux内核数据结构 散列表

news2024/9/29 5:30:15

1、散列表数据结构

  • 在Linux内核中,散列表(哈希表)使用非常广泛。本文将对其数据结构和核心函数进行分析。和散列表相关的数据结构有两个:hlist_headhlist_node

    //hash桶的头结点
    struct hlist_head {
    	struct hlist_node *first;//指向每一个hash桶的第一个结点的指针
    };
    //hash桶的普通结点
    struct hlist_node {
    	struct hlist_node *next;//指向下一个结点的指针
    	struct hlist_node **pprev;//指向上一个结点的next指针的地址
    };
    
  • 对应的结构如下
    在这里插入图片描述

    • hash_table 为散列表(数组),其中的元素类型为 struct hlist_head 。以 hlist_head 为链表头的链表,其中的节点hash值是相同的(也叫冲突)。first指针指向链表中的节点①,然后节点①的 pprev 指针指向 hlist_head 中 的 first ,节点①的 next 指针指向节点②,以此类推。
    • hash_table 的列表头仅存放一个指针,也就是 first 指针,指向的是对应链表的头结点,没有tail指针,也就是指向链表尾节点的指针,这样的考虑是为了节省空间——尤其在 hash bucket (数组size)很大的情况下可以节省一半的指针空间。
    • pprev是一个二级指针, 它指向前一个节点的next指针的地址 。为什么我们需要这样一个指针呢?它的好处是什么?
      • 哈希表的目的是为了方便快速的查找,所以哈希表中hash桶的数量通常比较大,否则“冲突”的概率会非常大,这样也就失去了哈希表的意义。如何做到既能维护一张大表,又能不使用过多的内存呢?就只能从数据结构上下功夫了。所以对于哈希表的每个hash桶,它的结构体中只存放一个指针,解决了占用空间的问题。现在又出现了另一个问题:数据结构不一致。显然,如果hlist_node采用传统的nextprev指针,对于第一个节点和后面其他节点的处理会不一致。hlist_node巧妙地将pprev指向上一个节点的next指针的地址,由于hlist_headfirst域指向的结点类型和hlist_node指向的下一个结点的结点类型相同,这样就解决了通用性!
      • 下面讲解结点相关操作的时候会有更详细的解释。

2、散列表删除结点

  • 如果要删除hash桶对应链表中的第一个普通结点
    在这里插入图片描述对应的程序代码如下:

    static inline void __hlist_del(struct hlist_node *n) 
    { 
    	 struct hlist_node *next = n->next;//获取指向第二个普通结点的指针 
    	 struct hlist_node **pprev = n->pprev;//保留待删除的第一个结点的pprev域(即头结点first域的地址),此时 pprev = &first 
    	 *pprev = next; 
    	 /*
    	 因为pprev = &first,所以*pprev = next,相当于 first = next
    	 即将hash桶的头结点指针指向原来的第二个结点,如上图中的黑线1
    	 */
    	 if (next) //如果第二个结点不为空
    	 next->pprev = pprev;//将第二个结点的pprev域设置为头结点first域的地址,如上图中的黑线2 
    }
    
  • 如果要删除hash桶对应链表中的非第一个结点
    在这里插入图片描述对应的程序代码如下:

    static inline void __hlist_del(struct hlist_node *n) 
    { 
    	 struct hlist_node *next = n->next;//获取指向待删除结点的下一个普通结点的指针 
    	 struct hlist_node **pprev = n->pprev;//获取待删除结点的pprev域 
    	 *pprev = next; //修改待删除结点的pprev域,逻辑上使待删除结点的前驱结点指向待删除结点的后继结点,如上图中的黑线1
    	 
    	 if (next) //如果待删除结点的下一个普通结点不为空
    	 next->pprev = pprev;//设置下一个结点的pprev域,如上图中的黑线2,保持hlist的结构 
    }
    

    可以看到删除第一个普通结点和删除非第一个普通结点的代码是一样的。

  • 下面再来看看如果hlist_node中包含两个分别指向前驱结点和后继结点的指针。
    在这里插入图片描述很明显删除hash桶对应链表中的非第一个普通结点,只需要如下两行代码:

    n->next->prev = n->prev;
    n->prev->next = n->next;
    

    可是,如果是删除的hash桶对应链表中的第一个普通结点:此时 n->prev->next = n->next 就会出问题,因为hash桶的表头结点没有next域,所以,明显在这种情况下删除hash桶对应链表的第一个普通结点和非第一个普通结点的代码是不一样的。 同理结点插入操作也存在同样的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/933590.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux学习笔记-Ubuntu系统下配置ssh免密访问

Ubuntu系统下配置ssh免密访问 一、基本信息二、ssh安装2.1 查看是否已经安装ssh2.2 安装ssh2.3 查看ssh安装状态 三、启动、停止,及开机自启动3.1 启动ssh3.2 关闭ssh3.3 使用systemctl设置ssh服务自启动3.4 使用systemctl关闭ssh开机启动 四、配置通过密钥进行免密…

Spring Authorization Server入门 (十六) Spring Cloud Gateway对接认证服务

前言 之前虽然单独讲过Security Client和Resource Server的对接,但是都是基于Spring webmvc的,Gateway这种非阻塞式的网关是基于webflux的,对于集成Security相关内容略有不同,且涉及到代理其它微服务,所以会稍微比较麻…

基于Spring Gateway路由判断器实现各种灰度发布场景

文章目录 1、灰度发布实现1.1 按随机用户的流量百分比实现灰度1.2 按人群划分实现的灰度1.2.1 通过Header信息实现灰度1.2.2 通过Query信息实现灰度1.2.3 通过RemoteAdd判断来源IP实现灰度 2、路由判断器2.1. After2.2. Before2.3. Between2.4. Cookie2.5. Header2.6. Host2.7.…

C++ Primer 第2章 变量和基本类型

C Primer 第2章 变量和基本类型 2.1 基本内置类型2.1.1 算术类型一、带符号类型和无符号类型练习 2.1.2 类型转换一、含有无符号类型的表达式 2.1.3 字面值常量一、整型和浮点型字面值二、字符和字符串字面值三、转义序列四、指定字面值的类型五、布尔字面值和指针字面值 2.2 变…

软考A计划-系统集成项目管理工程师-小抄手册(共25章节)-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 👉关于作者 专注于Android/Unity和各种游…

MySQL—MySQL主从如何保证强一致性

一、前言 涉及到的东西:两阶段提交,binlog三种格式 1、两阶段提交 在持久化 redo log 和 binlog 这两份日志的时候,如果出现半成功的状态,就会造成主从环境的数据不一致性。这是因为 redo log 影响主库的数据,binlog…

【大数据】Doris:基于 MPP 架构的高性能实时分析型数据库

Doris:基于 MPP 架构的高性能实时分析型数据库 1.Doris 介绍 Apache Doris 是一个基于 MPP(Massively Parallel Processing,大规模并行处理)架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知&#xff…

Kali Linux中的ARP欺骗攻击如何进行

在Kali Linux中进行ARP欺骗攻击是一种常见的网络攻击方法,它允许攻击者篡改局域网中的ARP表,以便将网络流量重定向到攻击者控制的位置。 步骤: 安装必要工具: 首先,确保 已经安装了Kali Linux,并在终端中安…

解除用户账户控制提醒

解决用户账户控制提醒 1. 前言2. 解决用户账户控制提醒2.1 控制面板2.2 注册表2.3 UAC服务 结束语 1. 前言 当我们使用电脑时,有时进行安装应用或者打开应用时,总会弹出一个提示框,要选择点击是否允许程序运行; 系统经常弹出用户…

流处理详解

【今日】 目录 一 Stream接口简介 Optional类 Collectors类 二 数据过滤 1. filter()方法 2.distinct()方法 3.limit()方法 4.skip()方法 三 数据映射 四 数据查找 1. allMatch()方法 2. anyMatch()方法 3. noneMatch()方法 4. findFirst()方法 五 数据收集…

azure data studio SQL扩展插件开发笔记

node.js环境下拉取脚手架 npm install -g yo generator-azuredatastudio yo azuredatastudio 改代码 运行 调试扩展,在visual studio code中安装插件即可 然后visual studio code打开进行修改运行即可 image.png 运行后自动打开auzre data studio了, 下面…

深度学习9:简单理解生成对抗网络原理

目录 生成算法 生成对抗网络(GAN) “生成”部分 “对抗性”部分 GAN如何运作? 培训GAN的技巧? GAN代码示例 如何改善GAN? 结论 生成算法 您可以将生成算法分组到三个桶中的一个: 鉴于标签&#…

6. 使用python将多个Excel文件合并到同一个excel-附代码解析

【目录】 文章目录 6. 使用python将多个Excel文件合并到同一个excel-附代码解析1. 目标任务2. 结果展示3. 代码示例4. 代码解析4.1 导入库4.2 调用库的类、函数、变量语法4.3 os.listdir-返回目录中的文件名列表4.4 startswith-用于判断一个字符串是否以指定的前缀开头4.5 ends…

如何评估开源项目的活跃度和可持续性?

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

深度学习1.卷积神经网络-CNN

目录 卷积神经网络 – CNN CNN 解决了什么问题? 需要处理的数据量太大 保留图像特征 人类的视觉原理 卷积神经网络-CNN 的基本原理 卷积——提取特征 池化层(下采样)——数据降维,避免过拟合 全连接层——输出结果 CNN …

postgresql-字符函数

postgresql-字符函数 字符串连接字符与编码字符串长度大小写转换子串查找与替换截断与填充字符串格式化MD5 值字符串拆分字符串反转 字符串连接 concat(str, …)函数用于连接字符串,并且忽略其中的 NULL 参数;concat_ws(sep, str, …) 函数使用指定分隔…

小研究 - Java虚拟机内存管理(三)

Java 语言的面向对象,平台无关,安全,开发效率高等特点,使其在许多领域中得到了越来越广泛的应用。但是由于Java程序由于自身的局限性,使其无法应用于实时领域。由于垃圾收集器运行时将中断Java程序的运行,其…

【手写promise——基本功能、链式调用、promise.all、promise.race】

文章目录 前言一、前置知识二、实现基本功能二、实现链式调用三、实现Promise.all四、实现Promise.race总结 前言 关于动机,无论是在工作还是面试中,都会遇到Promise的相关使用和原理,手写Promise也有助于学习设计模式以及代码设计。 本文主…

9个python自动化脚本,PPT批量生成缩略图、添加图片、重命名

引言 最近一番在整理资料,之前买的PPT资源很大很多,但归类并不好,于是一番准备把这些PPT资源重新整理一下。统计了下,这些PPT资源大概有2000多个,一共30多G,一个一个手动整理这个投入产出比也太低了。 作为…

CotEditor for mac 4.0.1 中文版(开源文本编辑器)

coteditorformac是一款简单实用的基于Cocoa的macOS纯文本编辑器,coteditormac版本可以用来编辑网页、结构化文本、程序源代码等文本文件,使用起来非常方便。 CotEditor for Mac具有正则表达式搜索和替换、语法高亮、编码等实用功能,而CotEdi…