当前位置: 首页 > news >正文

HashMap哈希表练习

一、练习要求

使用顺序表和单链表通过C语言实现一个HashMap的数据结构,实现以下功能:

1、PHashMap createHashMap(int size);

2、int putValue(PHashMap map, int key, EleType value);

3、EleType getValue(PHashMap map, int key);

4、printHashMap(PHashMap map);

5、int destroyHashMap(PHashMap map);

6、int hashCode(PHashMap map, int key);

二、关键结构体的定义

hash.h

typedef struct{int id;//学号char name[20];//姓名float score;//分数
}Stu, *PStu;typedef struct n{Stu stu;struct n *next;
}Node, *PNode;typedef struct{PNode* pTable;//指针数组int tableSize;//顺序表的大小int len;//元素数量
}HashMap, *PHashMap;PHashMap createHashMap(int tableSize);
int putValue(PHashMap map, int id, Stu stu);
int hashCode(int id, int tableSize);//计算hashcode
void printHashMap(PHashMap map);
void getValue(PHashMap map,int id);
void destroyHashMap(PHashMap map);

三、函数的实现

hash.c

#include "hash.h"PHashMap createHashMap(int tableSize){PHashMap map=(PHashMap)malloc(sizeof(HashMap));map->len=0;map->tableSize=tableSize;//PNode *p=(PNode*)malloc(sizeof(PNode)*tableSize);map->pTable=p;//清空新分配的数组空间for(int i=0;i<tableSize;i++){*(p+i)=NULL;}printf("HashMap创建成功\n");return map;
}int putValue(PHashMap map, int id, Stu stu){int index = hashCode(id, map->tableSize);//单链表头插法map->pTable[index];//PNode p=(PNode)malloc(sizeof(Node));memcpy(&p->stu, &stu, sizeof(stu));p->next=map->pTable[index];map->pTable[index]=p;map->len++;printf("[%d]数据存储成功,hashcode=[%d]\n", p->stu.id, index);return 1;
}int hashCode(int id, int tableSize){return id%tableSize;
}void printHashMap(PHashMap map){PNode *table=map->pTable;for(int i=0;i<map->tableSize;i++){printf("第[%d]行:\n", i);if(table[i] == NULL){printf("\tNULL:\n");continue;}//遍历单链表PNode p=table[i];while(p){printf("\tid=[%d],name=[%s],score=[%.1f]\n",p->stu.id, p->stu.name, p->stu.score);p=p->next;}}
}void getValue(PHashMap map, int id){int hashcode = hashCode(id, map->tableSize);	PNode p = map->pTable[hashcode];while(p){if(p->stu.id == id){printf("SUCCESS:找到了元素:id=[%d],name=[%s],score=[%.1f]\n",p->stu.id,p->stu.name,p->stu.score);return;}p=p->next;}printf("ERROR:没有找到id为[%d]的元素\n", id);
}void destroyHashMap(PHashMap map){//先销毁链表for(int i=0;i<map->tableSize;i++){PNode p = map->pTable[i];while(p){PNode temp=p;p=p->next;free(temp);}}//再销毁顺序表free(map);printf("销毁成功!\n");}

四、测试代码

main.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "hash.h"int main(int argc, const char *argv[])
{Stu a[]={{1,"aaa",1.1},{2,"bbb",2.2},{3,"ccc",3.3},{4,"ddd",4.4},{5,"eee",5.5},{6,"fff",6.6},{7,"ggg",7.7},{8,"hhh",8.8},{9,"iii",9.9},{10,"jjj",10.1}};int len=sizeof(a)/sizeof(Stu);//tableSize故意设置小一点,让hashcode碰撞printf(">>创建HashMap:\n");PHashMap map = createHashMap(5);//通过put往map里面存值printf(">>putValue:\n");for(int i=0;i<len;i++){putValue(map, a[i].id, a[i]);}//打印printf(">>打印HashMap:\n");printHashMap(map);//执行查找操作printf("\n>>执行查找id为8的元素\n");getValue(map, 8);printf("\n>>执行查找id为100的元素\n");getValue(map, 100);//销毁hashMapprintf("\n>>执行HashMap销毁\n");destroyHashMap(map);return 0;
}

五、运行结果

>>创建HashMap:
HashMap创建成功
>>putValue:
[1]数据存储成功,hashcode=[1]
[2]数据存储成功,hashcode=[2]
[3]数据存储成功,hashcode=[3]
[4]数据存储成功,hashcode=[4]
[5]数据存储成功,hashcode=[0]
[6]数据存储成功,hashcode=[1]
[7]数据存储成功,hashcode=[2]
[8]数据存储成功,hashcode=[3]
[9]数据存储成功,hashcode=[4]
[10]数据存储成功,hashcode=[0]
>>打印HashMap:
第[0]行:id=[10],name=[jjj],score=[10.1]id=[5],name=[eee],score=[5.5]
第[1]行:id=[6],name=[fff],score=[6.6]id=[1],name=[aaa],score=[1.1]
第[2]行:id=[7],name=[ggg],score=[7.7]id=[2],name=[bbb],score=[2.2]
第[3]行:id=[8],name=[hhh],score=[8.8]id=[3],name=[ccc],score=[3.3]
第[4]行:id=[9],name=[iii],score=[9.9]id=[4],name=[ddd],score=[4.4]>>执行查找id为8的元素
SUCCESS:找到了元素:id=[8],name=[hhh],score=[8.8]>>执行查找id为100的元素
ERROR:没有找到id为[100]的元素>>执行HashMap销毁
销毁成功!

六、需要继续研究的问题

1、hashcode的算法有哪些, 如果key是字符串如何预算,对比java里的hashcode的实现。

2、hashcode在代码中,对应的指针数组的下标,实际的应用中也是如此吗,我怎么记得java语言中的hashcode得到的是一个很长的字符串;

3、解决hashcode碰撞的常用方法有哪些,代码中运用到的是链表的方法;

4、当数据量不断地提升,hashmap本身怎么做动态的扩展;

5、在某些高级应用中,如果能预知或者通过统计知道某些key的查询率特别高,在发生hashcode碰撞的时候,如何把这些元素节点放在离根节点更近的地方,这样也可以提升查询效率。

也欢迎感兴趣的朋友一起讨论呀。

http://www.lryc.cn/news/446623.html

相关文章:

  • 字节豆包C++一面-面经总结
  • 极狐GitLab 17.4 重点功能解读【三】
  • 【unity进阶知识4】封装unity协程工具,避免 GC(垃圾回收)
  • Source insight安装使用笔记
  • golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
  • Netty源码解析-锁机制
  • 【C/C++】initializer_list
  • 不要再混淆啦!一文带你学会原型链继承、构造函数继承、寄生组合继承、ES6继承
  • 828华为云征文|华为云Flexus X实例Windows Server 2019安装护卫神防火墙——为企业运维安全发挥重要作用!!!
  • 最新的iOS 18版本和Android 15版本系统分别升级了哪些功能?
  • window系统DockerDesktop 部署windows容器
  • CSDN文章导出md并迁移至博客园
  • 计算机组成原理(笔记5原码和补码的乘法以及直接补码阵列乘法器 )
  • 【hot100-java】【括号生成】
  • k8s_资源管理介绍
  • 操作简单 地检编码器 武汉正向科技售后优质
  • 2024中国新能源汽车零部件交易会,开源网安展示了什么?
  • Java解析嵌套jar中class文件
  • 【含文档】基于Springboot+Vue的高校竞赛管理系统(含源码+数据库+lw)
  • 在大模型应用层面区分对比检索增强生成RAG技术和知识库技术
  • 云和恩墨携手华为,发布zCloud数据库备份管理一体机并宣布共建数据保护生态...
  • Linux系统备份Gitee等云git所有仓库与所有分支的数字资产
  • JavaScript 条件循环语句
  • LeetCode2207解题思路
  • opencv图像增强十四:opencv两种白平衡介绍及实现
  • Linux标准IO(四)-格式化I/O输入
  • 分布式安装LNMP
  • TFTP协议
  • FPGA随记-二进制转格雷码
  • Android常用C++特性之std::unique_lock