哈希表

哈希表算法(闭散列表操作,开散列表操作)创建,查找,插入,删除 #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 { ... 阅读详情

大佬讲哈希表
由浅到深,入门Go语言Map实现原理

自我实践

从上面的内容可知,golang中的map是通过拉链法来实现的

在这里我们也通过拉链表法实现一个简易的哈希表,暂不支持自动扩容,数组长度为8,链表长度最大为4

首先我们需要先实现一个可以同时存储key和value的单向链表和相关的方法,代码如下:

链表实现

一般单向链表的实现可参照数组和链表的第二部分

type Linklist interface {
	IsEmpty() bool                              //是否为空
	Length() int                                //获取链表长度
	Add(key string, value uint32)               //在头部添加元素
	Append(key string, value uint32)            //在尾部添加元素
	Insert(index int, key string, value uint32) //在指定位置添加元素
	Delete(key string)                          //删除元素
	forEachLink()                               //循环打印元素
	IsExist(key string) bool                    //是否存在该元素
	GET(key string) *LinkNode                   //查找元素存在的节点,不存在则返回nil
}

// 链表
type LinkList struct {
	HeadNode *LinkNode
}

//单向链表节点
type LinkNode struct {
	Key   string    // 链表上的KEY
	Value uint32    // 链表上的Value
	Next  *LinkNode // 指针指向下一个数据
}

// 判断链表是否为空,只需要判断第一个元素是否是 nil
func (self *LinkList) IsEmpty() bool {
	if self.HeadNode == nil {
		return true
	} else {
		return false
	}
}

// 获取链表的长度,从头部循环链表,直到元素是 nil 即可
func (self *LinkList) Length() int {
	count := 0
	node := self.HeadNode
	for node != nil {
		count += 1
		node = node.Next
	}
	return count
}

// 在头部添加数据,把原来的头部替换掉,还需要把现在的元素指向原来的头部
func (self *LinkList) Add(key string, value uint32) {
	node := &LinkNode{Key: key, Value: value}
	node.Next = self.HeadNode
	self.HeadNode = node
}

// 在尾部添加数据,需要从头部开始遍历,直到nil
func (self *LinkList) Append(key string, value uint32) {
	newNode := &LinkNode{Key: key, Value: value}
	node := self.HeadNode
	// 首部是空
	if node == nil {
		self.HeadNode = newNode
	} else {
		for node.Next != nil {
			node = node.Next
		}
		// 已经得到最后的元素
		node.Next = newNode
	}
}

// 在指定位置insert
func (self *LinkList) Insert(index int, key string, value uint32) {
	newNode := &LinkNode{Key: key, Value: value}
	node := self.HeadNode
	if index < 0 {
		// index 小于 0 就放在首部吧
		self.Add(key, value)
	} else if index > self.Length() {
		// index 大于 长度 就放在尾部部吧
		self.Append(key, value)
	} else {
		count := 0
		// 找到 index 之前的元素
		for count < (index - 1) {
			node = node.Next
			count += 1
		}
		// 已经找到index之前的元素
		newNode.Next = node.Next
		node.Next = newNode
	}
}

// 删除指定元素,从首部遍历,找到该元素删除,并且需要维护指针
func (self *LinkList) Delete(key string) {
	node := self.HeadNode
	// 如果是首部
	if node.Key == key {
		self.HeadNode = node.Next
	} else {
		for node.Next != nil {
			// 找到了,改指针
			if node.Next.Key == key {
				node.Next = node.Next.Next
			} else {
				node = node.Next
			}
		}
	}
}

// 循环链表输出元素
func (self *LinkList) forEachLink() {
	node := self.HeadNode
	for node != nil {
		fmt.Printf("key: %v, value: %v\n", node.Key, node.Value)
		node = node.Next
	}
}

//查看该元素是否存在
func (self *LinkList) IsExist(key string) bool {
	node := self.HeadNode
	for node != nil {
		if node.Key == key {
			return true
		}
		node = node.Next
	}
	return false
}

//返回在元素所在的节点
func (self *LinkList) GET(key string) *LinkNode {
	node := self.HeadNode
	for node != nil {
		if node.Key == key {
			return node
		}
	}
	return nil
}

func NewLinkList() *LinkList {
	linkList := &LinkList{HeadNode:nil}
	return linkList
}

哈希表实现

type Map interface {
	hash(key string) int                 //哈希函数
	add(key string, value uint32) bool   //添加元素
	delete(key string) bool              //删除元素
	update(key string, value uint32) bool //修改元素
	get(key string) (uint32, bool)        //获取元素
	forEach()                            //遍历打印所有的key和value
	len() int                            //元素个数

}

type HashMap struct {
	arr  []*LinkList
	size int
}

func (hm *HashMap) hash(key string) int {
	return len(key) % 8
}

func NewHashMap() *HashMap {
	HashMap := HashMap{
		arr: make([]*LinkList, 8),
	}
	for i:=0;i<=7;i++{
		Linklist:=NewLinkList()
		HashMap.arr[i]=Linklist
	}
	return &HashMap
}

func (hm *HashMap) add(key string, value uint32) bool {
	index := hm.hash(key)
	Linklist := hm.arr[index]
	if Linklist.Length() > 4 {
		fmt.Printf("bucket[%v] out of lenth\n", index)
		return false
	}
	ok := Linklist.IsExist(key)
	if ok {
		fmt.Printf("key is in map[%+v]", hm)
		return false
	}
	Linklist.Append(key, value)
	hm.size++
	return true
}

func (hm *HashMap) delete(key string) bool {
	index := hm.hash(key)
	Linklist := hm.arr[index]
	ok := Linklist.IsExist(key)
	if !ok {
		fmt.Printf("key is not in map[%+v]", hm)
		return false
	}
	Linklist.Delete(key)
	hm.size--
	return true
}

func (hm *HashMap) update(key string, value uint32) bool {
	index := hm.hash(key)
	Linklist := hm.arr[index]
	linkNode := Linklist.GET(key)
	if linkNode == nil {
		fmt.Printf("key is not in map[%+v]", hm)
		return false
	}
	linkNode.Value = value
	return true
}

func (hm *HashMap) get(key string) (uint32, bool) {
	index := hm.hash(key)
	Linklist := hm.arr[index]
	linkNode := Linklist.GET(key)
	if linkNode == nil {
		fmt.Printf("key is not in map[%+v]", hm)
		return 0, false
	}
	return linkNode.Value, false
}

func (hm *HashMap) forEach() {
	for _, linkList := range hm.arr {
		linkList.forEachLink()
	}
	return
}

func (hm *HashMap) len() int {
	//return hm.size
	count := 0
	for _, linkList := range hm.arr {
		count += linkList.Length()
	}
	return count
}

func main() {
	hashmap := NewHashMap()
	hashmap.forEach()
	hashmap.add("erwerwe",87)
	hashmap.forEach()
	hashmap.update("erwerwe",877)
	hashmap.forEach()

}

结尾

将两部分合在一起便是完整版简易哈希表的全部实现

相关文章:
为何golang中的map遍历结果是无序的

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

相关推荐

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

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

守望的博客-编程珠玑 3556

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

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

Ycy的博客 1万+

一款用Matlab开发的拓扑优化软件。它支持以密度或水平集作为设计变量来解决 2D 和 3D 拓扑优化问题。该工具箱可用于结构优化、材料设计和多尺度问题 不能运行.rar

一款用Matlab开发的拓扑优化软件。它支持以密度或水平集作为设计变量来解决 2D 和 3D 拓扑优化问题。该工具箱可用于结构优化、材料设计和多尺度问题 不能运行.rar

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

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

m0_61705102的博客 1万+

哈希表(散列表)详解

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

不能再留遗憾了的博客 2204

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

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

Philosophy7的博客 2364

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

哈希表知识总结

m0_57105290的博客 6492

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

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

ROBOT_a的博客 2615

散列表(哈希表

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

2302_77530416的博客 950

手机端子裁切落料弯折CCD检测入包自动包装机.rar

手机端子裁切落料弯折CCD检测入包自动包装机.rar

ASP.NET毕业设计含文档和代码ASP+ACCESS教师档案管理系统(源代码+论文)

ASP.NET毕业设计含文档和代码ASP+ACCESS教师档案管理系统(源代码+论文)

切割机的进料机构.rar

切割机的进料机构.rar

全自动绕线扎线机.rar

全自动绕线扎线机.rar

实用的封口机.rar

实用的封口机.rar

QYR-18900-2026-2032全球与中国油净化机市场现状及未来发展趋势 DHJ.docx

QYR-18900-2026-2032全球与中国油净化机市场现状及未来发展趋势 DHJ.docx

全自动继电器组装设备.rar

全自动继电器组装设备.rar

上一篇: 二叉树(二)--遍历
下一篇: 栈和队列
月守护
博客等级 码龄7年 210粉丝 160原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值