search——哈希表,哈希碰撞,拉链法,链表

本文介绍了一个使用Go语言实现的哈希表数据结构,包括插入、删除、查找等基本操作,并支持负载因子触发的自动扩容机制。该哈希表采用链地址法解决冲突,通过对键进行JSON序列化并哈希来确定存储位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

负载因子3,2倍扩容

package main

import (
	"encoding/json"
	"fmt"
)

type node struct {
	next  *node
	Key   any
	Value any
}

type list struct {
	head *node
}

func NewList() *list {
	return &list{&node{}} // 头结点不存值
}

func (l *list) insert(key, value any) { // 头插法
	n := &node{Key: key, Value: value}
	n.next = l.head.next
	l.head.next = n
}

func (l *list) delete(key any) (exist bool) {
	head := l.head
	//for head != nil { // 头结点存储值时
	//	if head. != key {
	//		break
	//	}
	//	head = head.next
	//}

	prev, cur := head, head
	for cur != nil {
		if cur.Key == key {
			prev.next = cur.next
			exist = true
		} else {
			prev = cur
		}
		cur = cur.next
	}
	return exist
}

func (l *list) search(key any) (node *node, exist bool) {
	for cur := l.head; cur != nil; cur = cur.next {
		if cur.Key == key {
			return cur, true
		}
	}
	return nil, false
}

type entity struct {
	Key   any
	Value any
}

type b struct {
	len  int
	root *list
}

type HashMap struct {
	Bucket []*b
	Cap    int
	Len    int
	factor int
}

func NewHashMap(cap int) *HashMap {
	if cap <= 0 {
		cap = 100
	}
	return &HashMap{make([]*b, cap), cap, 0, 3}
}

func (h *HashMap) Set(key interface{}, value any) {
	bs, _ := json.Marshal(key)
	index := hash(string(bs)) % uint64(h.Cap)
	if h.Bucket[index] == nil {
		h.Bucket[index] = &b{
			len:  0,
			root: NewList(),
		}
	}
	if node, ok := h.Bucket[index].root.search(key); ok {
		node.Value = value
	} else {
		h.Bucket[index].root.insert(key, value)
		h.Bucket[index].len++
		h.Len++
		if h.Bucket[index].len >= h.factor { // 扩容
			entities := h.RangeCopy()
			h.Cap *= 2
			h.Len = 0
			h.Bucket = make([]*b, h.Cap, h.Cap)
			for i := 0; i < len(entities); i++ {
				h.Set(entities[i].Key, entities[i].Value)
			}
		}
	}
}

func (h *HashMap) Get(key interface{}) (value interface{}, exist bool) {
	bs, _ := json.Marshal(key)
	index := hash(string(bs)) % uint64(h.Cap)
	if h.Bucket[index] == nil {
		return nil, false
	}

	root := h.Bucket[index].root
	if node, ok := root.search(key); ok {
		return node.Value, true
	}
	return nil, false
}

func (h *HashMap) Delete(key interface{}) {
	bs, _ := json.Marshal(key)
	index := hash(string(bs)) % uint64(h.Cap)
	if h.Bucket[index].root.delete(key) {
		h.Bucket[index].len--
		h.Len--
	}
}

func (h *HashMap) RangeCopy() (res []entity) {
	res = make([]entity, 0, h.Len)
	for i := 0; i < h.Cap; i++ {
		if h.Bucket[i] != nil {
			for head := h.Bucket[i].root.head; head != nil; head = head.next {
				if head.Key != nil && head.Value != nil { // 去头节点
					res = append(res, entity{head.Key, head.Value})
				}
			}
		}
	}
	return res
}

func main() {
	mp := NewHashMap(1)
	mp.Set("你好", "你好呀")
	//fmt.Println(mp.Set("hello", "hhhh"))

	mp.Set("hello", "world")
	mp.Set("hello1", "world1")
	mp.Set("hello2", "world2")
	mp.Set("hello3", "world3")
	mp.Set("hello4", "world4")
	mp.Set("hello5", "world5")
	mp.Set("hello6", "world6")

	mp.Delete("hello6")
	//mp.Delete("hello5")
	fmt.Println(mp.Get("hello6"))
	fmt.Println(mp.Get("hello5"))
	//mp.SetWithGrow("hello5", "-----")
	fmt.Println(mp.Get("hello5"))
	fmt.Println(mp.Get("hello3"))

	fmt.Println(mp.RangeCopy())
	fmt.Println(mp.Len)
	fmt.Println(mp.Cap)

	fmt.Println(mp)
}

func pow(x, n int) int {
	if n == 0 {
		return 1
	} else {
		for (n & 1) == 0 {
			n, x = n>>1, x*x
		}
	}
	result := x
	n >>= 1
	for n != 0 {
		x *= x
		if n&1 == 1 {
			result *= x
		}
		n >>= 1
	}
	return result
}

func hash(str string) (res uint64) {
	factor := ")k+,p-m~90$#2(*&6q}ev73541]n{fl['?|c"
	str = str + factor[:16-(len(str)%16)]
	for start, end := 0, len(str)/16; end > 0; start, end = start+16, end-1 {
		h0 := uint64(0)
		for i := 15; i >= 0; i-- {
			h0 += uint64(str[start+i]-byte(i))*uint64(pow(36, i)) ^ uint64(factor[(i+start)%36])
		}
		h0 *= 0x12345
		res += (res >> 30) ^ h0<<34
		res += (res >> 32) | (h0 << 32) ^ uint64(start*start*start) ^ uint64(factor[start%36])
		res += (res>>16)&(h0<<48) ^ uint64(factor[35-start%36]) ^ uint64(start-end*end)
		res += (res >> 17) | (h0 << 47) ^ uint64(start*start)
	}
	res += 235791113<<32 | 1719232931>>32
	return res
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值