6.C_数据结构_查询_哈希表

news2024/11/13 14:47:33

概述

哈希表的查询是通过计算的方式获取数据的地址,而不是依次比较。在哈希表中,有一个键值key,通过一些函数转换为哈希表的索引值。

其中:这个函数被称为哈希函数、散列函数、杂凑函数,记为:H(key)

哈希函数构造与冲突:

直接地址法、平方取中法、叠加法、保留余数法、随机函数法

  • 保留除数法(质数除余法):

设哈希表空间长度为m,则哈希函数为:H(key) = key%p     其中:p<=m 且 p为最大质数。

  • 冲突:

冲突是指表中某个地址已经存放了记录,但新的记录通过计算之后也要存放在这个地址。比如:p=3,key1=3,key2=6,key1、key2取余之后都是0,这就产生了冲突。

哈希函数一定会存在冲突,选择随机度好的哈希函数可以减少冲突但是不能消除冲突。

对于顺序存储哈希保留除数法的处理冲突的哈希函数:Hi = (H(key)+di)%m  即:加一个步长。

对于di,线性探查法di = 1,2,3....  二次探查法di = 1^2,-1^2,2^2,-2^2....

对于链式存储哈希保留除数法的处理冲突的方法:将冲突的位置连成一个链表。下一章详细分析。

  • 装填因子:

装填因子α = n/m ,代表总数据个数n,所占总哈希表空间m的值。一般α = 0.7~0.8这代表30%~20%的哈希表空间为空闲状态,用于存储冲突的数据。

  • 举例

例:有8个数据要存,装填因子α=0.8,这8个数据的键值为{0,1,2,3,4,5,6,7,8}。以线性探查法处理冲突设计一个哈希表。

解:哈希表的空间m = n/α = 10。那么哈希函数中的p的值就是不大于10的最大质数,就是7。

        对八个键值求H(key)=key%7得:{0,1,2,3,4,5,6,0,1},因此7,8冲突

        key=7  7%7=0,与0冲突,线性探查法依次为1,2,3,4,5,6,7,位置7不再冲突,因此存放在7处

        key=8  8%7=1,与1冲突,线性探查法依次为2,3,4,5,6,7,8,位置8不再冲突,因此存放在8处

        最终的哈希表数据分布如下:

链式哈希的实现

1、基本内容

链式哈希的构成是:将冲突结点构成一个链表,在哈希表中存放着这个冲突结点的冗余头结点。

具体的链式哈希结构如下:

哈希表及冲突数据结点结构体声明如下:

typedef int keyType;
typedef int data_t;
//数据冲突结点
typedef struct node{
	keyType key;	
	data_t data;
	struct node* pNext;
}listnode,*linklist;
//哈希表
typedef struct hash{
	listnode* pArr;  //存放链表结点指针,该指针为数组指针
	int len;         //哈希表的长度
}hash;

哈希表代码的文件构成:

  • hash.h:数据结构的定义、运算函数接口
  • hash.c:运算函数接口的实现
  • test.c:使用数据结构实现的应用功能代码

2、哈希表代码实现

2.1 哈希表创建

哈希表的创建就是开辟一个空间,初始化全部的元素,使得该冗余头的pNext = NULL

具体代码实现如下:

/*
 * hash_create:创建哈希表
 * param len:哈希表的长度
 * @ret  NULL--err  other--哈希表的指针
 * */
hash* hash_create(int len){
	
	hash* pHash = NULL;
	//1.申请空间
	//1.1 申请哈希结构体空间
	pHash = (hash*)malloc(sizeof(hash));
	if(pHash == NULL){
		printf("hash malloc err\n");
		return NULL;
	}
	//1.2 申请存放链表结点指针的数组空间
	pHash->pArr = (linklist)malloc(sizeof(listnode)*len);
	if(pHash->pArr == NULL){
		printf("pArr malloc err\n");
		free(pHash);
		return NULL;
	}
	//2.初始化
	memset(pHash->pArr,0,sizeof(linklist)*len);
	pHash->len = len;
	return pHash;
}

2.2 冲突数据节点创建

这个创建与普通节点的创建完全一致

具体代码实现如下:

/*
 * hashNode_create:创建哈希结点
 * param key:结点的键值
 * param data:结点的数据
 * @ret  NULL--err  other--结点地址
 * */
linklist hashNode_create(keyType key,data_t data){
	
	linklist pHashNode = NULL;

	//1.申请空间
	pHashNode = (linklist)malloc(sizeof(listnode));
	if(pHashNode == NULL){
		printf("malloc err\n");
		return NULL;
	}
	//2.初始化
	pHashNode->key = key;
	pHashNode->data = data;
	pHashNode->pNext = NULL;
	return pHashNode;
}

2.3 插入哈希表

将数据插入哈希表,先利用哈希函数算出在哈希表的哪个位置,之后以key递增的方式有序插入

具体代码实现如下:

/*
 * hash_insert:在哈希表中插入数据
 * param pHash:哈希表的指针
 * param pHashNode:新数据的指针
 * @ret  -1--err  0--success
 * */
int hash_insert(hash* pHash,linklist pHashNode){
	
	int hash_i;//数据哈希表中的位置
	linklist pHead = NULL;//同一位置的链表头
	linklist pIn = NULL;//插入点
	linklist pAhead = NULL;//插入点前一个结点

	//1.判断参数有效性
	if(pHash == NULL || pHashNode == NULL){
		printf("param err\n");
		return -1;
	}
	//2.获取结点在哈希表中的位置
	hash_i = pHashNode->key % pHash->len;
	pHead = &(pHash->pArr[hash_i]);
	pIn = pHead->pNext;
	pAhead = pHead;
	//3.在指定哈希表位置处插入
	//3.1 指定位置出为空
	if(pHead->pNext == NULL){
		pHead->pNext = pHashNode;
	}
	//3.2 指定位置有数据,键值小的放前面
	else{
		//3.2.1 遍历插入
		while(pIn != NULL){
			if(pHashNode->key < pIn->key){
				//插入到当前结点前面
				pAhead->pNext = pHashNode;
				pHashNode->pNext = pIn;
				break;
			}
			pAhead = pIn;
			pIn = pIn->pNext;
		}
		//3.2.2 遍历之后依旧没插入,将结点尾插
		if(pIn == NULL){
			pAhead->pNext = pHashNode;
		}
	}
	return 0;
}

2.4 查询哈希表

查询哈希表,先利用哈希函数算出所在位置,之后遍历链表找到数据。

具体代码实现如下:

/*
 * hash_search:根据键值查找元素
 * param pHash:哈希表的指针
 * param pHashNode:找到的数据存放的位置
 * param key:键值
 * @ret  -1--err  0--find it
 * */
int hash_search(hash* pHash,linklist* ppHashNode,keyType key){
	
	int hash_i;//数据哈希表中的位置
	linklist pHead = NULL;//同一位置的链表头
	linklist pTmp = NULL;
	//1.判断参数有效性
	if(pHash == NULL || ppHashNode == NULL){
		printf("param err\n");
		return -1;
	}
	//2.获取结点在哈希表中的位置
	hash_i = key % pHash->len;
	pHead = &(pHash->pArr[hash_i]);
	pTmp = pHead->pNext;
	//3.遍历查找
	while(pTmp != NULL){
		if(pTmp->key == key){
			*ppHashNode = pTmp;
			break;
		}
		pTmp = pTmp->pNext;
	}
	if(pTmp == NULL){
		//没找到
		printf("not find\n");
		return -1;
	}else{
		//找到了
		return 0;
	}
}

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

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

相关文章

MySQL 中的锁定粒度:理解与应用

在 MySQL 数据库的使用中&#xff0c;锁定粒度是一个至关重要的概念。它决定了数据库在并发控制中锁定的范围和程度&#xff0c;对数据库的性能和并发能力有着深远的影响。今天&#xff0c;我们就来深入了解一下 MySQL 中的锁定粒度是什么意思&#xff0c;并通过实际案例来更好…

鸿蒙开发之ArkUI 界面篇 十五 交叉轴对其方式

鸿蒙界面有两个容器一个是Colum、一个是Row&#xff0c;Colum主轴是垂直方向&#xff0c;交叉轴是水平方向&#xff0c;Row的主轴是水平方向&#xff0c;交叉轴是垂直方向&#xff0c;对应方向调整子控件的话&#xff0c;justifyContent调整的是主轴方向的子控件距离&#xff0…

论文阅读-《Attention is All You Need》

注意力就是一切 【要点】&#xff1a;论文提出了一种全新的网络架构——Transformer&#xff0c;完全基于注意力机制&#xff0c;无需使用循环和卷积&#xff0c;实现了在机器翻译任务上的性能提升和训练效率的显著提高。 【方法】&#xff1a;通过构建一个仅使用注意力机制的…

【高分系列卫星简介】

高分系列卫星是中国国家高分辨率对地观测系统&#xff08;简称“高分工程”&#xff09;的重要组成部分&#xff0c;旨在提供全球范围内的高分辨率遥感数据&#xff0c;广泛应用于环境监测、灾害应急、城市规划、农业估产等多个领域。以下是对高分系列卫星及其数据、相关参数和…

Java流程控制语句——条件控制语句详解(附有流程图)#Java条件控制语句有哪些?#if-else、switch

在 Java 编程中&#xff0c;条件控制语句用于控制程序的执行路径&#xff0c;决定根据某些条件来选择执行某段代码或跳过某段代码。它们是 Java 编程的重要组成部分&#xff0c;帮助开发者根据不同的输入、状态或数据流来编写更加灵活和动态的代码。在本文中&#xff0c;我们将…

利用git将项目上传到github

采用git而不是在pycharm中共享的原因&#xff1a;可能会出现上图报错 目录 1、创建github仓库2、在 git bash 中初始化Git仓库&#xff0c;添加文件&#xff0c;上传代码 1、创建github仓库 2、在 git bash 中初始化Git仓库&#xff0c;添加文件&#xff0c;上传代码

【C++】STL----list常见用法

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;C从小白到高手 &#x1f339;往期回顾&#x1f339;&#xff1a;[C]vector常见用法 &#x1f516; 流水不争&#xff0c;争的是滔滔不息。 文章目录 一、list的介绍li…

【C++】list容器的基本使用

一、list是什么 list的底层结构是带头双向循环链表。 相较于 vector 的连续线性空间&#xff0c;list 就显得复杂很多&#xff0c;它是由一个个结点构成&#xff0c;每个结点申请的空间并不是连续的&#xff0c;它的好处是每次插入或删除一个数据&#xff0c;就配置或释放一个…

WebServer:log

超时锁的编写 这个问题处于blockqueue.h文件中&#xff0c;内容如下&#xff1a; template<class T> bool BlockDeque<T>::pop(T& item, int timeout) {std::unique_lock<std::mutex> locker(mtx_);while(deq_.empty()) {if(condConsumer_.wait_for(lo…

内存泄漏

文章目录 内存泄漏发现问题topVisualVMArthas 原因分析代码层面并发请求 诊断问题MAT原理 –支配树获取运行时快照 内存泄漏 内存泄漏&#xff08;memory leak&#xff09;&#xff1a;在Java中如果不再使用一个对象&#xff0c;但是该对象依然在GC ROOT的引用链上&#xff0c;…

12.第二阶段x86游戏实战2-CE找基地址

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

全网最全:企业微信用户授权登录对接完整流程

Hello&#xff01;欢迎各位新老朋友来看小弟博客&#xff0c;祝大家事业顺利&#xff0c;财源广进&#xff01;&#xff01; 主题&#xff1a;企业微信用户授权与校验完整对接流程 一&#xff1a;构造第三方应用授权链接 如果第三方应用需要在打开的网页里面携带用户的身份信息…

吸尘器制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

吸尘器制造行业&#xff0c;作为传统制造业的重要组成部分&#xff0c;也在积极探索如何通过先进技术实现生产模式的创新升级。5G智能工厂与物联数字孪生平台的融合应用&#xff0c;为吸尘器制造业的数字化转型铺设了一条高速通道&#xff0c;不仅极大地提升生产效率&#xff0…

华为---代理ARP简介及示例配置

目录 1. 概念 2. 前提条件 3. 使用环境 4. 工作过程 5. 优点 6. 缺点 7. 示例配置 7.1 示例场景 7.2基本配置 7.3 配置端口隔离 7.4 开启代理ARP 7.4.1 VLAN内代理ARP 7.4.2 VLAN间代理ARP 7.4.3路由式ARP代理 1. 概念 代理ARP&#xff08;Proxy ARP&#xff09;&…

GAMES202 作业1

参考&#xff1a;games202作业1 SM 首先是利用shadow map去生成尝试生成硬阴影。根据作业的要求 我们完成光源对物体的mvp矩阵 CalcLightMVP(translate, scale) {let lightMVP mat4.create();let modelMatrix mat4.create();let viewMatrix mat4.create();let projection…

Bigemap GIS Office 2024注册机 全能版地图下载软件

对于需要利用GIS信息进行编辑、设计的用户来说&#xff0c;Bigemap GIS Office占有重要地位。用户可以使用Bigemap GIS Office作为工具进行设计、分析、共享、管理和发布地理信息。Bigemap GIS Office能实现多种数据流转、嵌入、融合以及更多地为用户提供数据的增强处理及多种分…

文心一言 VS 讯飞星火 VS chatgpt (351)-- 算法导论24.1 2题

二、证明推论24.3。推论 24.3 的内容是设 G ( V , E ) G(V,E) G(V,E)是一带权重的源结点为 s s s的有向图&#xff0c;其权重函数为 ω : E → R ω:\boldsymbol{E→R} ω:E→R。假定图 G G G不包含从源结点 s s s可以到达的权重为负值的环路&#xff0c;则对于所有结点 v ∈ …

完美转发、C++11中与线程相关的std::ref

目录 模板中的万能引用 std::forward实现完美转发 C11中与线程相关的std::ref 线程函数参数 用函数指针作为线程函数 用lambda表达式作为线程函数 模板中的万能引用 void Func(int& x) {cout << "左值引用" << endl; } void Func(int&&am…

spark之不同序列化对比

一&#xff0c;spark的rdd的序列话不同介绍 下面是使用不同序列化后的占用资源和数据大小 2&#xff0c;sparksql中序列化的区别 sparksql中使用序列化和不使用差别不大&#xff0c;英文sparksql中默认使用了encode自己实现的序列化方法&#xff0c;加上与不加序列化差别不大…

基于PHP+MySQL组合开发的在线客服源码系统 聊天记录实时保存 带完整的安装代码包以及搭建部署教程

系统概述 随着互联网技术的飞速发展&#xff0c;企业与客户之间的沟通方式日益多样化&#xff0c;在线客服系统作为连接企业与客户的桥梁&#xff0c;其重要性不言而喻。然而&#xff0c;市场上现有的在线客服系统往往存在成本高、定制性差、维护复杂等问题。针对这些痛点&…