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

2023-11-09

目录

 1.哈希表原理精讲

​2.哈希链表算法实现

 2.1哈希表数据结构定义

 2.2哈希函数

2.3哈希链表初始化

2.4哈希链表查找函数

2.5哈希链表插入函数

2.6哈希链表删除元素

3.哈希表完整代码


哈希表 — 散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法~

 假设:给24个人依次给予编号,从1到24

编号除6能整除的为第一组:        6     12     18     24

编号除6余数为1的为第二组:      1      7      13     19

编号除6余数为2的为第三组:      2      8      14     20

编号除6余数为3的为第四组:      3      9      15     21

编号除6余数为4的为第五组:      4     10     16     22

编号除6余数为5的为第六组:      5     11      17    23

  这样,当我们给出一个编号时,根据除6的余数,可以直接排除20个数据 ,从而更快速的找到他。

 1.哈希表原理精讲

键(key) : 组员的编号        如,1、5、19.....

值(value):组员的其他信息(包含  性别、年龄、薪水等)

索引: 数组的下标(0,1,2,3,4),用以快速定位和检索数据

哈希桶:  保存索引的数组(链表或数组),数组成员为每一个索引值相同的多个元素

哈希函数:将组员编号映射到索引上,采用除余法,如:组员编号19

2.哈希链表算法实现

 2.1哈希表数据结构定义

#define DEFAULT_SIZE 16   //索引数组范围,或者说哈希桶的个数

typedef struct _ListNode {
	int key;		//键值
	void* data;		//数据
	struct _ListNode* next;
}ListNode;


typedef ListNode* List;
typedef ListNode* Element;

typedef struct _HashTable {
	int TableSize;			///索引数组范围,或者说哈希桶的个数
	List* Thelists;
}HashTable;

 2.2哈希函数

//这里采用求余法做Hash函数
int Hash(int key, int TableSize) {
	return(key % TableSize);
}

2.3哈希链表初始化

//哈希表初始化	TableSize决定哈希桶的数量或者说索引范围
HashTable* InitHash(int TableSize) {
	int i = 0;
	HashTable* hTable = NULL;
	if (TableSize <= 0) {
		TableSize = DEFAULT_SIZE;   //如果传入值小于0,就给予默认值
	}

	hTable = (HashTable*)malloc(sizeof(HashTable));
	if (NULL == hTable) {
		printf("HashTable malloc error\n");
		return NULL;
	}

	hTable->TableSize = TableSize;
	hTable->Thelists = NULL;
	//指针数组,指针的数组需要拿指针的指针接收
	hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);
	if (NULL == hTable) {
		printf("HashTable malloc error\n");
		free(hTable);
		return NULL;
	}
	//为Hash桶对应的指针数组初始换链表节点
	for (int i = 0; i < TableSize; i++) {
		hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
		if (NULL == hTable->Thelists[i]) {
			printf("HashTable malloc error\n");
			free(hTable->Thelists[i]);
			free(hTable);
		}
		else {
			//key赋值为0,值域(void*)和下一个指针赋为空
			memset(hTable->Thelists[i], 0, sizeof(ListNode));
		}
	}
	return hTable;
}

2.4哈希链表查找函数

Element findHash(HashTable** hashTable,const int key)  {
	int index = 0;
	index = Hash(key, (*hashTable)->TableSize);
	List L = NULL;	//	L为对应哈希桶的指针
	L = (*hashTable)->Thelists[index];
	Element e = NULL;
	e = L->next;   //e为对应值指针
	while (e!=NULL&&e->key!=key) {
		e = e->next;
	}
	return e;
}

2.5哈希链表插入函数

void insertHash(HashTable** hashTable, const int key, void* value) {
	Element insertElement = NULL;
	insertElement = findHash(hashTable, key);
	if (insertElement == NULL) {
		Element temp = NULL;
		temp=(Element)malloc(sizeof(ListNode));
		if (temp == NULL) {
			printf("malloc error\n");
			return;
		}
		temp->next = NULL;
		List L = (*hashTable)->Thelists[Hash(key, (*hashTable)->TableSize)];
		temp->data = value;
		temp->key = key;
		temp->next = L->next;
		L->next = temp;
	}
	else {
		printf("The key alerdy exist\n");
	}
}

2.6哈希链表删除元素

void deleteHash(HashTable* &hashtable, int key) {
	int index = Hash(key, hashtable->TableSize);
	List L = NULL;
	L = hashtable->Thelists[index];
	Element last = L;
	Element compareHash = NULL;
	compareHash = L->next;
	while (compareHash != NULL && compareHash->key != key) {
		last = compareHash;
		compareHash = compareHash->next;
	}
	if (compareHash != NULL) {
		last->next = compareHash->next;
		free(compareHash);
	}
}

测试程序:

int main() {
	 char* a1 = (char*)"f张三";
	 char* a2 = (char*)"李四";
	 char* a3 = (char*)"王五";
	 char* a4 = (char*)"赵六";
	 char* arr[] = {a1,a2,a3,a4};
	 HashTable* hashtable;
	 hashtable = InitHash(17);

	insertHash(&hashtable, 1, arr[0]);
	insertHash(&hashtable, 2, arr[1]);
	insertHash(&hashtable, 3, arr[2]);
	insertHash(&hashtable, 4, arr[3]);
	deleteHash(hashtable, 1);

	for (int i = 0; i < 6; i++) {
		Element e = findHash(&hashtable, i);
		if (e) {
			printf("%s\n", (const char*)Retrieve(e));
		}
		else {
			printf("Not found [key:%d]\n", i);
		}
	}
	system("pause");
	return 0;
}

运行结果:

程序图示:

3.哈希表完整代码

#include<iostream>
using namespace std;

#define DEFAULT_SIZE 16   //索引数组范围,或者说哈希桶的个数

typedef struct _ListNode {
	int key;		//键值
	void* data;		//数据
	struct _ListNode* next;
}ListNode;


typedef ListNode* List;
typedef ListNode* Element;

typedef struct _HashTable {
	int TableSize;			///索引数组范围,或者说哈希桶的个数
	List* Thelists;
}HashTable;

//这里采用求余法做Hash函数
int Hash(int key, int TableSize) {
	return(key % TableSize);
}

//哈希表初始化	TableSize决定哈希桶的数量或者说索引范围
HashTable* InitHash(int TableSize) {
	int i = 0;
	HashTable* hTable = NULL;
	if (TableSize <= 0) {
		TableSize = DEFAULT_SIZE;   //如果传入值小于0,就给予默认值
	}

	hTable = (HashTable*)malloc(sizeof(HashTable));
	if (NULL == hTable) {
		printf("HashTable malloc error\n");
		return NULL;
	}

	hTable->TableSize = TableSize;
	hTable->Thelists = NULL;
	//指针数组,指针的数组需要拿指针的指针接收
	hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);
	if (NULL == hTable) {
		printf("HashTable malloc error\n");
		free(hTable);
		return NULL;
	}
	//为Hash桶对应的指针数组初始换链表节点
	for (int i = 0; i < TableSize; i++) {
		hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
		if (NULL == hTable->Thelists[i]) {
			printf("HashTable malloc error\n");
			free(hTable->Thelists[i]);
			free(hTable);
		}
		else {
			//key赋值为0,值域(void*)和下一个指针赋为空
			memset(hTable->Thelists[i], 0, sizeof(ListNode));
		}
	}
	return hTable;
}

Element findHash(HashTable** hashTable,const int key)  {
	int index = 0;
	index = Hash(key, (*hashTable)->TableSize);
	List L = NULL;	//	L为对应哈希桶的指针
	L = (*hashTable)->Thelists[index];
	Element e = NULL;
	e = L->next;   //e为对应值指针
	while (e!=NULL&&e->key!=key) {
		e = e->next;
	}
	return e;
}



void deleteHash(HashTable* &hashtable, int key) {
	int index = Hash(key, hashtable->TableSize);
	List L = NULL;
	L = hashtable->Thelists[index];
	Element last = L;
	Element compareHash = NULL;
	compareHash = L->next;
	while (compareHash != NULL && compareHash->key != key) {
		last = compareHash;
		compareHash = compareHash->next;
	}
	if (compareHash != NULL) {
		last->next = compareHash->next;
		free(compareHash);
	}
}



void insertHash(HashTable** hashTable, const int key, void* value) {
	Element insertElement = NULL;
	insertElement = findHash(hashTable, key);
	if (insertElement == NULL) {
		Element temp = NULL;
		temp=(Element)malloc(sizeof(ListNode));
		if (temp == NULL) {
			printf("malloc error\n");
			return;
		}
		temp->next = NULL;
		List L = (*hashTable)->Thelists[Hash(key, (*hashTable)->TableSize)];
		temp->data = value;
		temp->key = key;
		temp->next = L->next;
		L->next = temp;
	}
	else {
		printf("The key alerdy exist\n");
	}
}

void* Retrieve(Element e) {
	return e ? e->data : NULL;
}
int main() {
	 char* a1 = (char*)"f张三";
	 char* a2 = (char*)"李四";
	 char* a3 = (char*)"王五";
	 char* a4 = (char*)"赵六";
	 char* arr[] = {a1,a2,a3,a4};
	 HashTable* hashtable;
	 hashtable = InitHash(17);

	insertHash(&hashtable, 1, arr[0]);
	insertHash(&hashtable, 2, arr[1]);
	insertHash(&hashtable, 3, arr[2]);
	insertHash(&hashtable, 4, arr[3]);
	deleteHash(hashtable, 1);

	for (int i = 0; i < 6; i++) {
		Element e = findHash(&hashtable, i);
		if (e) {
			printf("%s\n", (const char*)Retrieve(e));
		}
		else {
			printf("Not found [key:%d]\n", i);
		}
	}
	system("pause");
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

哈希表(散列表)——C++数据结构详解 的相关文章

  • MongoDB C# 驱动程序检查身份验证状态和角色

    这是我使用 MongoDB 身份验证机制登录 MongoDB 的代码 try var credential MongoCredential CreateMongoCRCredential test admin 123456 var sett
  • 我可以使用反射更改 C# 中的私有只读字段吗?

    我想知道 由于很多事情都可以使用反射完成 我可以在构造函数完成执行后更改私有只读字段吗 注 只是好奇 public class Foo private readonly int bar public Foo int num bar num
  • 如何调试参数化 SQL 查询

    我使用 C 连接到数据库 然后使用 Ad hoc SQL 来获取数据 这个简单的 SQL 查询非常方便调试 因为我可以记录 SQL 查询字符串 如果我使用参数化 SQL 查询命令 有没有办法记录 sql 查询字符串以进行调试 我想就是这样的
  • LINQ to XML - 如何正确使用 XDocument

    现在我首先要说的是 这确实是一项任务 然而 在我遇到 Linq to XML 语法之前 我几乎已经完成了它 我有 2 个课程 曲目和 CD 现在作为作业的一部分 我创建了一张 CD 然后向其中添加了一些曲目 在搜索了大量完美解释了如何从 x
  • 实体框架代码优先 - 在另一个文件中配置

    使用 Fluent API 将表到实体的映射分开的最佳方法是什么 以便它全部位于单独的类中 而不是内联在 OnModelCreating 方法中 我目前在做什么 public class FooContext DbContext prote
  • 身份未映射异常

    System Security Principal IdentityNotMappedException 无法转换部分或全部身份引用 该错误仅在应用程序注册后出现一次 当 SecurityIdentifier 无法映射时 例如 返回 Ide
  • 如何避免选择项目时 winforms 树视图图标发生变化

    我正在一个小型 C Winforms 应用程序中尝试树视图 我已经以编程方式将 ImageList 分配给树视图 并且所有节点都很好地显示了它们的图标 but当我单击一个节点时 它的图标会发生变化 变为 ImageList 中的第一个图像
  • C中有const吗?

    这个问题可能很幼稚 但是 有没有constC 中的关键字 从哪个版本开始 之间有任何语义和 或句法差异吗const在 C 和 C 中 C 和 C 之间在语法上没有差异const关键字 除了一个相当晦涩的关键字 在 C 中 自 C99 起 您
  • _mm_max_ss 在 clang 和 gcc 之间有不同的行为

    我正在尝试使用 clang 和 gcc 交叉编译一个项目 但在使用时发现一些奇怪的差异 mm max ss e g m128 a mm set ss std numeric limits
  • 为什么以下代码不允许我使用 fgets 获取用户输入但可以使用 scanf?

    这是一个更大程序的简短摘录 但该程序的其余部分无关紧要 因为我认为我能够隔离该问题 我怀疑这与我使用 fgets 的方式有关 我读过 最好使用 fgets 而不是 scanf 但我似乎无法让它在这里正常工作 当我使用以下代码时 程序不会给我
  • 抽象类和接口之间的区别[重复]

    这个问题在这里已经有答案了 可能的重复 接口与基类 https stackoverflow com questions 56867 interface vs base class 我不明白抽象类和接口之间的区别 我什么时候需要使用哪种字体
  • C#:如何使用 SHOpenFolderAndSelectItems [重复]

    这个问题在这里已经有答案了 有人可以举例说明如何使用 shell 函数吗SH打开文件夹并选择项目 http msdn microsoft com en us library bb762232 VS 85 aspx来自 C 我不太明白如何使用
  • C++ Primer 5th Edition 错误 bool 值没有指定最小大小?

    bool 的最小大小不应该是 1 个字节吗 这有点学术性的东西 尽管它们会转换为数字 并且 与其他所有事物一样 它们最终将基本上由计算机内存中的数字表示 但布尔值不是数字 你的bool可以取值true 或值false 即使您确实需要至少 1
  • 在可观察项目生成时对其进行处理

    我有一个IObservable它会生成一次性物品 并且在其生命周期内可能会生成无限数量的物品 因此 我想在每次生成新项目时处理最后一个项目 因此Using http reactivex io documentation operators
  • 使用 Linq 进行异步Where过滤

    我有一个List通过填充的元素async调用 WebService 没问题 我需要过滤该列表以便在应用程序视图上显示某些内容 我试过这个 List
  • 为什么 C 函数不能返回数组类型?

    我是 C 语言新手 想知道 为什么 C 函数不能返回数组类型 我知道数组名是数组第一个值的地址 而数组是 C 中的二等公民 您自己已经回答了这个问题 数组是二等公民 C 按值返回 数组不能按值传递 因此不能返回它们 至于为什么数组不能按值传
  • 用 C# 编写的带有点击移动的 WPF 游戏

    我试图将标签网格移动到鼠标的位置 就像冒险游戏中的移动一样 理想情况下 我会在途中删除并重新绘制它们 但是 现在我只想弄清楚如何将 int 转换为厚度或 pointtoscreen 到目前为止我有 player XMove int Mous
  • 删除对象时指针自动指向空

    假设我有一个对象和其他几个不同类类型的对象中的 10 个指向它的指针 如果对象被删除 这些指针必须设置为空 通常我会将对象的类与具有指向它的指针的类互连 以便它可以通知它们它正在被删除 并且它们可以将它们的指针设置为空 但这也有一个负担 即
  • ASP.NET Core:会话 ID 始终变化

    今天启动了一个全新的 ASP NET Core 网站 按照说明添加会话 我们在索引页上打印出会话 ID 它始终是唯一的 我认为这可能是 cookie 合规性 所以我在 Chrome 的高级设置和调试器中删除了所有 cookie 但横幅不会再
  • 最后从同一类中的其他构造函数调用构造函数

    我在这里读到可以调用另一个构造函数从同一类中的另一个构造函数调用构造函数 https stackoverflow com questions 829870 calling constructor from other constructor

随机推荐

  • 2023年大唐杯仿真部分-5G信令流程仿真实验

    参考视频连接 第十届大唐杯信令流程仿真讲解 哔哩哔哩 bilibili 1 5G系统消息的获取 根据题目要求 UE开机需要获取消息 消息分别是MIB SIB1 SIB2 SIB3 上面为什么选的是SIB1 Systeminformation
  • 如何判断一个指定的经纬度点是否落在一个多边形内

    1 理论支持 如果从需要判断的点出发的一条射线与该多边形的焦点个数为奇数 则该点在此多边形内 否则该点在此多边形外 射线不能与多边形顶点相交 2 编程思路 该程序的思路是从A点出发向左做一条水平射线 平行于x轴 向X轴的反方向 判断与各边是
  • Golang实现一个事务型内存数据库

    内存数据库经我们经常用到 例如Redis 那么如何从零实现一个内存数据库呢 本文旨在介绍如何使用Golang编写一个KV内存数据库MossDB 特性 MossDB是一个纯Golang编写 可嵌入的 键值型内存数据库 包含以下特性 可持久化
  • 【spring】spring 的事务(transaction) 三 try catch对事务的影响

    文章目录 概述 1 非异常用例 1 1 创建工程 1 2 执行 2 内层抛出非check异常 外层进行捕获 3 内层抛出非check异常 外层不进行捕获 相关文章 spring 的事务 transaction 一 基础概念介绍 spring
  • 群晖NAS如何在内网部署HTTPS服务让浏览器信任证书

    前言 最近在折腾内部部署Web服务 通过Vue实现一个H5的内部的管理服务 但在实际部署过程中由于种种原因 必须部署成Https服务 但在部署成Https服务后 由于没有HTTPS证书 每次进入页面都会被浏览器拦截 使用起来非常不便 于是开
  • Pandas 过滤dataframe中包含特定字符串的数据

    假如有一列全是字符串的dataframe 希望提取包含特定字符的所有数据 该如何提取呢 因为之前尝试使用filter 发现行不通 最终找到这个行得通的方法 举例说明 我希望提取所有包含 Mr 的人名 1 首先将他们进行字符串化 并得到其对应
  • 国内iso镜像站点

    http mirrors aliyun com centos
  • vue小项目实战

    项目概念图 devWebpackConfig plugins push new FriendlyErrorsPlugin compilationSuccessInfo messages Your application is running
  • shopify网站如何提高视觉冲击力

    1 首屏使用视频 2 页面引入酷炫动画 3 使用对比强烈的色彩
  • CSS-定位-背景图

    定位 背景图 一 定位 position 1 相对定位 relative 2 绝对定位 absolute 3 固定定位 fixed 4 定位练习 二 背景图 background 1 属性 2 实例一 3 背景图定位 4 雪碧图的使用 三
  • 12款很赞的web前端移动开发框架

    原生移动应用程序运行更快 更顺畅 有更好的用户体验 而同时 前端开发人员总是寻找新的 Web 技术来获得这种性能 利用现有的高质量移动框架来构建移动 Web 应用程序已成为非常容易 但是如何选择合适的框架是比较纠结的 因此在本文中 我们整理
  • 刷简单的题也很吃力怎么办?

    文章目录 一 分享自己相关的经历 1 1 刷简单题目感到吃力的原因 1 2 解决该问题的重要性和目的 二 分析可能存在的问题 三 根据问题进行分解或建立思维导图 四 分享好用的刷题网站并进行介绍 明明自觉学会了不少知识 可真正开始做题时 却
  • POI操作ppt,合并,转图片

    引入POI compile group org apache poi name poi ooxml version 4 1 0 compile group batik name batik bridge version 1 6 1 comp
  • python中if错误-python中的异常处理

    异常 异常就是程序运行时发生错误的信号 在python中 错误触发的异常如下 异常种类 在python中不同的异常可以用不同的类型 python中统一了类与类型 类型即类 去标识 不同的类对象标识不同的异常 一个异常标识一种错误 常见异常
  • Simon ILETS —— Listening

    content I want to say ahead Listening Know the test basic information Four sections Section 1 Key technique Section 2 Se
  • 小程序:调用手机的相册

    1 需求 点击按钮 调用手机相册选择图片上传 2 解决方案 Button 上加 openType chooseAvatar onChooseAvatar 写方法 必须用button 按钮 更改下样式看不出来就行 3 代码 解决方案 1 Bu
  • Linux——文件系统:目录组织结构、文件类型、文件权限等

    在Linux中 所有的设备都是文件 文件的类型是根据文件头字段来判断 而非文件的后缀名 Linux的文件系统 EXT4 索引式的文件系统 以EXT4文件系统格式化磁盘时 将磁盘分成三个区 1 superblock 记录文件系统的整体信息 包
  • 微信小程序 短信验证 功能的实现(附案例代码/前后端/直接用)

    模块效果展示 小程序界面 实现的功能 小程序端 请求获取短信验证码 两次请求之间间隔至少一分钟 填写必填内容后 才能提交表单 手机号合法性检验 后台 接前台请求后 通过阿里云发送短信 生成随机数字验证码 默认6位 收到提交的表单后 对验证码
  • 如何实现IM即时通信系统(一)

    在企业数字化建设过程中 如何与客户保持线上链接是重要的组成部分 而IM通信系统就属于数字化建设的基础设施 那么 如何实现一个符合企业需求的IM系统呢 采购当然是其中需要考虑的方式之一 但就我个人的经验来看 市面上好的IM厂商很稀少 因为IM
  • 哈希表(散列表)——C++数据结构详解

    目录 1 哈希表原理精讲 2 哈希链表算法实现 2 1哈希表数据结构定义 2 2哈希函数 2 3哈希链表初始化 2 4哈希链表查找函数 2 5哈希链表插入函数 2 6哈希链表删除元素 3 哈希表完整代码 哈希表 散列表 它是基于快速存取的角