学习golang(3) 初探:编写一个链式hash map

简介: 学习golang(3) 初探:编写一个链式hash map

我们昨天看了一下哈希表的几种常见的方式,以及如何解决hash冲突,最后我们看了一下go map的基本操作,今天我们来写一个demo,该demo是完成了一个简单的拉链式hash




什么是hash链式存储


哈希冲突

昨天已经讲过了该结构,我们再来看下,为什么有hash链式存储这个东西,其实hash本质是我们通过一个叫做哈希函数的东西来计算其存储点。

image.png


若多个key都被计算到同一个点,这个就称之为hash冲突

image.png



拉链式解决hash冲突

我们解决hash冲突的方法中,其中有一个就是拉链式存储。所谓拉链式存储,就是将数据使用链表给串起来。

image.png

这样在操作的时候,当定位到了下标后,就变为了链表的操作,这样,即解决了存储的问题,也解决了冲突的问题。



代码编写及逻辑


理想效果呈现


如上所述

我们可以将hash map其抽象为如下结构,该结构中,若遇到hash冲突,则将其值放入到链表中。

image.png

若我们将hash数组抽象一下,可能会得到如下效果

image.png

结构体定义


如上,我们将代码编写为 每一个hash map我们定义一个maps

maps又键值个数(count)、hash map数组长度 和 包含n个键值块(Node)

而每一个键值块(Node)又包含了一个键名(key)、一个键值(value) 以及 指向下一个键值块的指针(nextNode)

代码如下:

image.png




初始化hash map


初始化函数我们获取一个形参i,我们判断下i是否小于等于0,因为小于等于0,初始化无意义,所以我们判断若小于等于0,我们就默认给长度为10。


我们申请一个maps,并且将其count置为0,length为我们传入的值,然后再申请lengthNode指针,最后将maps给返回回去。


代码如下

image.png



定义哈希函数


hash存储中,最重要的就是hash函数,通过hash函数,我们就可以直接定位到存储点,hash函数设计得当与否直接影响到hash冲突的概率。


这里我们简单化了,若传入的keyint或则string时,我们计算其值,并且将对maps.length取余,其他类型直接存储数组0中,并且返回存储的下标。

image.png


新增数据

hash map中,key应当唯一才是,否则会影响hash map的正确性,所以在拿到要存储的keyvalue时,我们需要判断一下,如果该hash map中存在该值,则直接修改其值,或则是返回错误,这里定义为若key冲突,则为直接修改该值。


对于存储的逻辑,我们首先需要获取其数组存储的下标,在获取后,我们需要申请一个键值块(Node) ,然后将keyvalue赋值进该键值块中。

image.png


我们在进行存储的时候,相当于插入链表数据,而插入链表,我们又可以区分为3种情况

  • 该链表为空
  • 该链表只有一个节点
  • 该链表大于一个节点

当该链表为空时,我们直接将 键值块(Node) 放入数组中即可


原始链表

image.png

插入之后数据

image.png

当只有一个链表数据时,我们直接将 键值块(Node) 插入到第一个节点之后即可

原始链表

image.png

插入后链表

image.png


当链表超过2个节点时,我们将新节点插入第一个节点后,并且将新节点的下一个节点指向第一个节点的下一个节点

原始节点

image.png

插入后节点

image.png



我们整理为代码如下:

image.png

链表插入完毕后,我们使其count增加1



获取数据

其中对于获取数据,我们还是需要哈希函数key传入,获取其下标,然后就是对链表进行查询了

如果能够查询到该key,我们直接返回该键值块(Node)的地址,若查询不到,直接返回nil即可


image.png




删除数据


对于删除数据,和获取数据一样,我们需要找到数据,然后再进行链表的删除

对于找到数据,我们编写如下

若找到该数据,我们将其foundok赋值为true,并且定义currNodelastNode来获取当前节点指针和上一个节点指针

image.png


在找到数据后,我们又有三种删除逻辑


  • 尾节点
  • 头结点
  • 中间节点

当需要删除的节点是尾节点时

我们直接将上一个节点的指向赋值为nil即可

当需要删除的节点是头结点时

直接将数组赋值给头结点的下一个节点即可

当需要删除的节点是中间节点时

我们只需要将上一个节点的nextNode指针指向当前节点的下一个节点即可。


删除前

image.png

删除后

image.png


修改数据

修改数据如上新增数据逻辑



demo运行效果

我们编写主程序

image.png


编译测试

image.png


完美,赞



总结


hash表虽然很简单,但是用的非常多,其主要优点为,查询速度非常的块,哎,昨天看了一下go map底层实现,感觉非常复杂,我暂时还看不懂,所以先自己写了最简单的hash实现,争取我这个运维小学生有一天,能够看到go map实现代码吧。 哦,对了,上述代码我放在了giteegitee.com/pdudo/golea…


加油,加油。



相关文章
|
1月前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
38 1
|
1月前
|
安全 Java Go
【Golang入门】简介与基本语法学习
Golang语言入门教程,介绍了Go语言的简介、基本语法、程序结构、变量和常量、控制结构、函数、并发编程、接口和类型、导入包、作用域以及错误处理等关键概念,为初学者提供了一个全面的学习起点。
25 0
|
2月前
|
Go
Golang语言之映射(map)快速入门篇
这篇文章是关于Go语言中映射(map)的快速入门教程,涵盖了map的定义、创建方式、基本操作如增删改查、遍历、嵌套map的使用以及相关练习题。
38 5
|
3月前
|
机器学习/深度学习 存储 人工智能
Golang bytes 包学习
Golang bytes 包学习
25 3
|
4月前
|
编译器 Go C语言
通过例子学习在golang中调试程序
【7月更文挑战第4天】Go语言支持使用cgo进行汇编调试,官方文档在golang.org/doc/asm。注意,调试Go运行时可能遇到变量不可用或行号错误,需谨慎使用step命令。
74 1
通过例子学习在golang中调试程序
|
3月前
|
Java Serverless Go
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决
|
4月前
|
存储 C++ 索引
|
5月前
|
Go
GOLANG MAP 查找
GOLANG MAP 查找
|
5月前
|
存储 Go 索引
GOLANG MAP 底层实现
GOLANG MAP 底层实现
|
6月前
|
存储 Java
【JAVA学习之路 | 进阶篇】Map接口及其实现类及常用方法
【JAVA学习之路 | 进阶篇】Map接口及其实现类及常用方法
下一篇
无影云桌面