哈希表

大佬讲哈希表
由浅到深,入门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遍历结果是无序的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值