自我实践
从上面的内容可知,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遍历结果是无序的