哈希表

哈希表算法(闭散列表操作,开散列表操作)创建,查找,插入,删除 #include <stdio.h> #include <malloc.h> #include "stdlib.h" #include <math.h> typedef int Status; typedef int KEYTYPE; typedef struct { KEYTYPE key; }ElemType; typedef struct { ... 阅读详情

哈希表的结构是这样的


//HashTable.h

#ifndef _HASHTABLE_H_
#define _HASHTABLE_H_

#include <stdlib.h>
#include <stdbool.h>

#define BUCKET_SIZE		5					//基桶与溢出桶大小,此处的值表示可容纳5个元素
#define HASHTABLE_SIZE	17					//哈希表中基桶个数,为了使得出的哈希因子在所有可得的值中得出任一值的概率相同,所以使用素数作为基桶个数
#define INVALID_VALUE	-11111				//无效标记

typedef int EleType;
typedef int KeyType;

struct _ElementNode_						//元素节点类型,键值对
{
	KeyType Key;
	EleType Val;
};	

//存储键值对,Hash与之前的平衡二叉树都应该是键值对,如果只有值,查找函数返回值的地址,如果使用地址修改了值,会发生令人不愉快的事情。
typedef struct _HashBucket_
{
	_ElementNode_ Data[BUCKET_SIZE];   
	struct _HashBucket_ *Bucket;			//解决冲突的方式是链地址法
}HashBucket;								//桶节点类型

typedef HashBucket* HashTable;

bool HashTableInit(HashTable *Hash);									//初始化哈希表
bool HashTableInsert(HashTable Hash, KeyType Key, EleType Data);		//插入键值对
EleType *HashTableFind(HashTable Hash, KeyType Key);					//根据键查找值
bool HashTableDelete(HashTable Hash, KeyType Key);						//删除键值对
void HashTableDestroy(HashTable *Hash);									//摧毁哈希表


#endif //_HASHTABLE_H_



//HashTable.c

#include "HashTable.h"

static int HashFunc(KeyType Key)
{
	return Key % HASHTABLE_SIZE;				//除留取余法
}

static _ElementNode_ *HashTableFind_(HashTable Hash, KeyType Key)		
{
	int pos = 0, i = 0;
	HashBucket *p = NULL;

	if( NULL == Hash )
		return NULL;

	pos = HashFunc(Key);						//求Key所对应的基桶
	p = Hash + pos;								//指向该基桶

	for (i = 0; i < BUCKET_SIZE; ++i)			//在基桶内寻找位置
	{
		if( Key == p->Data[i].Key )
			return p->Data + i;					//返回找到的位置
	}
	//不在基桶中
	while (NULL != p->Bucket)					//到溢出桶中查找
	{	
		p = p->Bucket;
		for (i = 0; i < BUCKET_SIZE; ++i)
		{
			if( Key == p->Data[i].Key )
				return p->Data + i;			
		}
	}
	//也不在溢出桶中
	return NULL;
}

//更新一个桶内的元素,如果是以存在元素则用新值更新,如果是不存在元素则找空位置插入
static bool UpdataBucket(HashBucket *p, KeyType Key, EleType Data)
{
	int i = 0;
	for (i = 0; i < BUCKET_SIZE; ++i)			//遍历该基桶中的每个位置,查找是否有空位,或者是否可以更新现有元素
	{
		if (Key == p->Data[i].Key)				//Key已存在则更新Val,相当于是对已存在元素进行修改
		{
			p->Data[i].Val = Data;
			return true;
		}
		if (INVALID_VALUE == p->Data[i].Key)	//Key不存在则增加元素记录,即将新元素存入哈希表
		{
			p->Data[i].Key = Key;
			p->Data[i].Val = Data;
			return true;
		}
	}
	return false;
}

//创建一张含有HASHTABLE_SIZE个基桶的哈希表
bool HashTableInit(HashTable *Hash)
{
	int i = 0, j = 0;
	HashBucket * p = (HashBucket *)malloc(sizeof(HashBucket) * HASHTABLE_SIZE);
	if( NULL == p )
	{
		*Hash = NULL;
		return false;
	}
	for (i = 0; i < HASHTABLE_SIZE; ++i)		//初始化全部基桶
	{
		for (j = 0; j < BUCKET_SIZE; ++j)		//初始化桶内每个位置
		{
			p[i].Data[j].Key = INVALID_VALUE;
			p[i].Data[j].Val = INVALID_VALUE;
		}
		p[i].Bucket = NULL;							
	}

	*Hash = p;
	return true;
}

//插入操作函数,当Key已存在时,更新元素,否则在空位置中插入元素
bool HashTableInsert(HashTable Hash, KeyType Key, EleType Data)
{
	int pos = 0, i = 0;
	HashBucket *p = NULL, *s = NULL;
	if( NULL == Hash )
		return false;

	pos = HashFunc(Key);						//求Key所对应的基桶
	p = Hash + pos;								//指向该基桶

	if( true == UpdataBucket(p, Key, Data) )	//桶内元素更新成功
		return true;

	//基桶内已没有空位置
	while (NULL != p->Bucket)					//在溢出桶内寻找位置
	{
		p = p->Bucket;
		if (true == UpdataBucket(p, Key, Data))	//桶内元素更新成功
			return true;
	}

	//在已查找过的桶内都未能找到合适的位置,创建一个新的溢出桶来存储元素
	s = (HashBucket *)malloc(sizeof(HashBucket));
	if( NULL == s )
		return false;
	for (i = 0; i < BUCKET_SIZE; ++i)			//初始化桶
	{
		s->Data[i].Key = INVALID_VALUE;		
		s->Data[i].Val = INVALID_VALUE;
	}
	s->Bucket = NULL;							//初始化桶

	s->Data[0].Key = Key;						//将Key值对存储在溢出桶首位置中
	s->Data[0].Val = Data;
	p->Bucket = s;								//将新桶挂接上去

	return true;
}


EleType *HashTableFind(HashTable Hash, KeyType Key)
{
	_ElementNode_ *p = HashTableFind_(Hash, Key);

	if( NULL != p )
		return &(p->Val);						//查找到元素,返回元素的值成员地址
	
	return NULL;
}

bool HashTableDelete(HashTable Hash, KeyType Key)
{
	_ElementNode_ *p = HashTableFind_(Hash, Key);

	if( NULL != p )
	{
		p->Key = INVALID_VALUE;					//查找、插入都是根据Key值来的,因此只需覆盖Key即可
		return true;
	}
	else
		return false;
}

void HashTableDestroy(HashTable *Hash)
{
	HashBucket *p = NULL, *q = NULL, *s = NULL;
	int i = 0;
	if( NULL == Hash )
		return ;
	
	p = *Hash;									//指向首个基桶
	for (i = 0; i < HASHTABLE_SIZE; ++i)		//释放全部基桶
	{
		q = p->Bucket;							//指向某个基桶的溢出桶所构成的链表
		while (NULL != q)						//释放溢出桶所构成的链表
		{
			s = q->Bucket;						
			p->Bucket = s;
			free(q);							
			q = s;
		}
		++p;
	}
	free(*Hash);								//释放全部基桶
	*Hash = NULL;
}



//main.c

#include "HashTable.h"
#include <stdio.h>

int main(int argc, char **argv)
{
	HashTable hash = NULL;
	EleType *e = NULL;
//	KeyType KeyArray[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//	EleType EleArray[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
	KeyType KeyArray[] ={ 1, 18, 35, 52, 69, 86, 103, 120, 137, 171, 171, 188, 205, 222,  239, 255, 273 };
	EleType EleArray[] ={ 10, 180, 350, 520, 690, 860, 1030, 1200, 1370, 1710, 0, 1880, 2050, 2220, 2390, 2550, 2730 };
	int size = sizeof(KeyArray) / sizeof(KeyType);
	int i = 0;
	bool ret = true;
	KeyType key = 0;

	HashTableInit(&hash);

	for (i = 0; i < size && ret; ++i)
		ret = HashTableInsert(hash, KeyArray[i], EleArray[i]);

	key = 156;
	e = HashTableFind(hash, key);
	if( NULL != e )
	{
		printf("值为%d\n", *e);
		*e = 123;

		printf("修改后\n");

		e = HashTableFind(hash, key);
		if (NULL != e)
			printf("值为%d\n", *e);
	}
	else
		printf("键%d不存在\n", key);

	key = 171;
	ret = HashTableDelete(hash, key);
	if( true == ret )
	{
		printf("键值对%d删除成功\n", key);
		e = HashTableFind(hash, key);
		if (NULL != e)
			printf("值为%d\n", *e);
		else
			printf("键%d不存在\n", key);
	}
	else
		printf("键%d不存在\n", key);

	HashTableDestroy(&hash);


	return 0;
}





哈希表与散列表的原理及C++实现 哈希表(Hash Table)是一种高效的数据结构,用于存储键值对(Key-Value Pairs)。它通过哈希函数(Hash Function)将键(Key)映射到一个固定大小的数组(称为散列表)中的某个位置,从而实现快速的插入、查找和删除操作。哈希表的核心思想是通过哈希函数将键转换为数组的索引,从而直接访问对应的值。理想情况下,哈希表的插入、查找和删除操作的时间复杂度都是O(1)。哈希表是一种高效的数据结构,通过哈希函数将键映射到数组索引,从而实现快速的插入、查找和删除操作。 阅读详情

相关推荐

什么是散列表(哈希表)?

本文文末有福利,不要错过奥! 前言 假设你们班级100个同学每个人的学号是由院系-年级-班级和编号组成,例如学号为01100168表示是1系,10级1班的68号。为了快速查找到68号的成绩信息,可以建立一张表,但是不能用学号作为下标,学号的数值实在太大。因此将学号除以1100100取余,即得到编号作为该表的下标,那么,要查找学号为01100168的成绩的时候,只要直接访问表下标为68的数据即可...

守望的博客-编程珠玑 3568

Hashtable(完整实现)

请支持原创作者, 转载请说明出处! #ifndef _HASHTABLE_H#define _HASHTABLE_Hstruct hashtable;struct hashtable*  hashtable_create(unsigned long size, unsigned long(*hash_func)(const void *key),                    

aishen944(陈永强)的专栏 4137

HashSet和HashMap的底层实现——哈希表、散列表

java.lang  类 Object java.lang.Object int hashCode()            返回该对象的哈希码值。 boolean equals(Object obj)           指示某个其他对象是否与此对象“相等”。 一、概述 java最基本的两种数据结构

lpp1234567的专栏 7370

[Linux]学习笔记系列 -- lib/hashtable.h & include/linux/hash.h 哈希表与哈希函数(Hash Table & Hash Functions) 内核中快速数

本文介绍了Linux内核中哈希表与哈希函数的核心实现及其应用。哈希表作为高效的数据查找基础设施,通过拉链法解决冲突,平均时间复杂度接近O(1),广泛应用于进程管理、文件系统、网络等领域。文章详细分析了哈希表的历史演进、核心原理、优势与局限性,并与链表、红黑树等数据结构进行了对比。内核通过通用哈希框架(lib/hashtable.h)和多种哈希函数(include/linux/hash.h)优化性能,同时指出其不适用于有序数据、范围查询等场景。

wdfk-prog.space 1178

Linux:Hashlist/hashtable: [积木]

文章目录DEFINE_HASHTABLE使用实例 DEFINE_HASHTABLE struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; #define HLIST_HEAD_INIT { .first = NULL } #define DEFINE_HASHTABLE(name, bits) \ 定义一个hash表,名称,以及

mzhan017的博客 875

手把手教你用Kali+字典爆破WiFi密码:从抓包到破解的完整流程

本文提供了一份详尽的无线网络渗透测试实战指南,重点讲解如何使用Kali Linux和Aircrack-ng套件进行WiFi安全评估。内容涵盖从硬件选型(如RTL8812AU网卡)、驱动配置、监听模式设置,到使用airodump-ng扫描抓包、捕获WPA握手包,以及利用字典进行离线破解的完整流程。同时强调了在授权环境下进行安全测试的重要性,并给出了相应的网络加固建议。

weixin_28568819的博客 1675

数据结构:哈希表(除留取余法--线性探测法)

#include #include using namespace std; #define SUCCESS 1 #define UNSUCCESS 0 #define HASHSIZE 12 #define NULLKEY 0xffffffff/2 typedef struct { int *elem; int count; }HashTable; typedef int Sta

憧憬,思考,奋斗,飞翔 8955

学习STM32的无人机控制

下面是一个基于STM32的无人机控制的简单示例代码,包括四旋翼的PID控制、遥控器信号解析和电机控制。本示例以STM32F103系列为例,使用Keil C编译器进行开发。

qq_67153941的博客 706

数据结构-HashTable(哈希表/散列表)

哈希函数其实就是我们常说的哈希算法,主要应用在以下这几个方面:文件校验、数字签名、鉴权协议。常用的哈希算法有以下这些。MD5:MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。MD5是输入不定长度信息,输出固定长度128bits的算法。SHA-1:常用于HTTPS传输和软件签名。SHA-2:SHA-224/SHA-256/SHA-384/SHA-512并成为SHA-2。

hello,world! 470

QT入门开发一个时钟

本文讲述了时钟开发的具体过程以及代码。 涉及到一下几个知识点: 1. 定时器使用 2. 本地时间获取 3. resource资源读取 4. 图片绘制 5. 图片按照中心旋转 6. sin或者cos角度计算。

啊渊的专栏 5145

9.16华为OD机试真题 新系统 - 统计特殊数字 (Java/Py/C/C++/Js/Go)

9.16华为OD机试真题 新系统 - 统计特殊数字 (Java/Py/C/C++/Js/Go)

算法大师! 758

哈希表(散列表)C/C++代码实现

哈希表(散列表): 1,构造散列函数 最常用的方法是除留余数法: H(key) = key%p 这个方法的关键是选取适当的p, 一般情况下,可以选p为小于表长的最大质数。例如表长m=100, 可取p=97。 2,处理冲突 选择一个 “好” 的散列函数可以在一定程度上减少冲突,但在实际应用中,很难完全避免发生冲突 1,开放地址法 (1)线性勘测法 (2)二次探测法 (3)伪随机探测法 线性探测法的优点是:只要散列表未填满,总能 找到一个不发生冲突的地址。缺点是:会产生 ”二次聚集“ 现象。而二次探测法和伪随机

Ycy的博客 1万+

在 Android Studio 中接入 DeepSeek:加速 Android 开发进程

通过在 Android Studio 中接入 DeepSeek,Android 开发者能够充分利用人工智能技术带来的强大优势,显著提升开发效率和代码质量。从前期的安装准备,到具体的接入步骤,再到使用过程中的技巧和注意事项,每一个环节都为打造高效、智能的开发环境提供了有力支持。希望本文能帮助你顺利将 DeepSeek 融入到 Android Studio 的开发工作流程中,让你在 Android 开发的道路上更加得心应手,创造出更优质的 Android 应用。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 4174

数据结构——哈希表(散列表)

文章目录一,哈希表(散列表)概念二,哈希(散列)函数的构造哈希(散列)函数的构造原则构造方法平方取中法折叠法保留余数法三,冲突处理散列冲突的方法开放定址法1.线性探测法2.二次探测法3.随机探测法再散列函数法公共溢出区法链地址法四,代码实现1.哈希函数2.链表和哈希表的创建3.哈希表初始化3.从哈希表中根据key查找元素4.哈希表插入元素5.元素删除6.哈希表销毁 一,哈希表(散列表)概念 大话数据结构里面是这样介绍的: 散列表,又称为哈希表(Hash table),采用散列技术将记录存储在一块连续的存储空

m0_61705102的博客 1万+

IgH EtherCAT 从入门到精通:第 30 章 实战:高可用 EtherCAT 系统设计

摘要:构建高可用EtherCAT系统的关键技术 本章详细介绍了工业级EtherCAT系统的高可用性设计方法,主要包括: 冗余链路架构:采用双网卡环形拓扑设计,主备网卡同时工作,通过IgH Master的冗余配置实现线缆故障自动切换。 状态监控机制:提供专用API实时监控主备链路状态,包括从站响应数、链路状态和冗余激活标志,形成完整的故障判断矩阵。 自动恢复功能:系统内置FSM架构支持热插拔自动检测和重配置,从站断线/重连时可自动完成状态恢复,同时允许应用层实施安全措施。 这些技术共同构成了生产环境下Ethe

从事嵌入式linux android驱动开发,拥有全栈能力 243

YOLOv11 改进 - 注意力机制 | LS-YOLO MSFE 多尺度特征提取模块:并行分支结构增强多尺度感知,优化遥感与小目标检测

本文介绍了一种用于滑坡检测的模型LS-YOLO及其在YOLOv11中的结合应用。LS-YOLO首先构建多尺度滑坡数据集MSLD,为模型训练提供丰富数据。设计了基于高效通道注意力、平均池化和空间可分离卷积的多尺度特征提取模块MSFE,充分提取滑坡特征信息。在解耦头中采用膨胀卷积增加模型感受野。我们将MSFE模块集成进YOLOv11,替换部分原有模块。实验表明,改进后的YOLOv11在数据集中表现出色 。

魔改工程师的博客 870

哈希表(散列表)详解

深入理解哈希表,哈希函数的构造和解决哈希冲突的方法

不能再留遗憾了的博客 2302

历年安徽省省赛AHOI初中组考点分类汇总考点分类汇总

持续更新中.....

weixin_42358969的博客 818

[一篇详解哈希表]数据结构之哈希表(散列表)

✅作者简介:大家好,我是Philosophy7?让我们一起共同进步吧!🏆 📃个人主页:Philosophy7的csdn博客 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博>主哦🤞 文章目录散列表简介:为什么需要散列表?哈希函数的实现哈希表的代码 散列表 简介: 散列表又可以叫做哈希表,那什么是散列表呢? 现在就让我们深入研究一下吧 是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把.

Philosophy7的博客 2403

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

散列表(哈希表)知识详解

哈希表知识总结

m0_57105290的博客 6514

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

数据结构 | 散列表(哈希表)

​ 散列表(Hash Table),也称为哈希表,是一种根据关键码值(Key value)而直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,从而加快查找速度。这个映射函数称为散列函数,存放记录的数组称为散列表。

ROBOT_a的博客 2704

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

散列表(哈希表)

散列表(hash table,又称哈希表),是一种数据集,其中数据项的存储方式尤其有利于将来快速的查找定位。散列表的基本思想是,首先在关键字key和存储位置p之间建立一个对应关系H,使得p = H(key),H称为哈希函数,p称为散列地址。当创建哈希表时,把关键字key的记录直接存入地址为H(key)的地址单元中;以后查找关键字为key的元素时,再利用哈希函数p = H(key)计算出该元素的散列地址p,从而达到直接存取记录的目的。

2302_77530416的博客 963

C++数据结构——散列表(哈希表)

一:散列表的概念 定义:散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希函数。 基本概念: 若关键字为k,则其值存放在f(k)的存储位置上。由此,不需比较便可直

eyes++的博客 2785

散列表 分布式散列表(DHT)哈希表 是什么

  (如果你自认为是一个熟练的程序员,请直接略过“预备知识”这个章节,看下一章节)   (注:在本文中,凡是提及“散列”或“哈希”或“hash”,均表示相同含义)   关于 hash 的概念,俺曾经写过一篇相关的扫盲教程《扫盲文件完整性校验——关于散列值和数字签名》,不了解此概念的同学,可以先看看。   老实说,如果你还没有搞明白 hash 的概念,就不要浪费时间看本文的后续部分啦。   “散列表/哈希表”是用来存储“键值对”的一种容器。“键值对”洋文称之为“key/value pairs”,简称“

软件工程小施同学 的专栏 2565

哈希表(散列表)

除留余数法用关键字除以p得到的余数作为关键字的存储位置.(p是一个整数) 那么关键是怎么取到合适的除数p?技巧:设表长为m,取p<=m且为质数例如{15,23,27,38,53,61,70},散列函数Hash(key)=key%7,那么哈希表为:查找的时候同样用这个哈希函数,比如我们要查找70.用10除以7余数为0,直接去0号位置查找.以上就是我们常用的散列表的构造方法:直接定址法和除留余数法.非同义词不会冲突,无”聚集”现象;链表上节点空间动态申请,更适合于表长不确定的情况.

weixin_75188368的博客 1391

面试八股之集合篇6.1——散列表——散列表(哈希表)HashTable概述

🔥本篇概览:详细讲解了散列表(哈希表)的性质

做一个善良的人,做好自己的事,如果愿意,再发一份光。 971
上一篇: 二叉查找树、平衡二叉树、红黑树、B-/B+树性能对比
下一篇: 跳表(skiplist)的代码实现
早起的虫儿灬
博客等级 码龄10年 54粉丝 114原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值