192 lines
3.5 KiB
Go
192 lines
3.5 KiB
Go
package hashmap
|
|
|
|
import (
|
|
"474420502.top/eson/structure/compare"
|
|
)
|
|
|
|
type HashCode func(key interface{}) uint
|
|
|
|
type HashMap struct {
|
|
growfactor uint
|
|
slimmingfactor uint
|
|
|
|
table []*avlTree
|
|
|
|
GetHash HashCode
|
|
Compare compare.Compare
|
|
|
|
growsize uint
|
|
size uint
|
|
}
|
|
|
|
type bNode struct {
|
|
Next *bNode
|
|
Key, Value interface{}
|
|
}
|
|
|
|
type Bucket struct {
|
|
size uint
|
|
head *bNode
|
|
}
|
|
|
|
func HashInt(key interface{}) uint {
|
|
thekey := uint(key.(int))
|
|
hbit := thekey & 0xffffffff
|
|
lbit := (thekey & 0xffffffff00000000) >> 32
|
|
return lbit ^ hbit
|
|
}
|
|
|
|
func New(hcode HashCode, comp compare.Compare) *HashMap {
|
|
hm := &HashMap{}
|
|
hm.growfactor = 2
|
|
hm.GetHash = hcode
|
|
hm.Compare = comp
|
|
initcap := uint(8)
|
|
hm.table = make([]*avlTree, initcap, initcap)
|
|
hm.countNextGrow()
|
|
return hm
|
|
}
|
|
|
|
// func (hm *HashMap) grow() {
|
|
// if hm.size >= hm.growsize {
|
|
// newsize := hm.size << 1
|
|
// newtable := make([]*Bucket, newsize, newsize)
|
|
// hm.growsize = newsize - newsize>>2
|
|
|
|
// for _, bucket := range hm.table {
|
|
// if bucket != nil {
|
|
// cur := bucket.head
|
|
// hash := hm.GetHash(cur.Key)
|
|
// index := hash % newsize
|
|
// // var bkt *Bucket
|
|
// bkt := newtable[index]
|
|
|
|
// if bkt == nil {
|
|
// bkt = &Bucket{size: 1}
|
|
// newtable[index] = bkt
|
|
// bkt.head = &bNode{Value: cur.Value, Key: cur.Key}
|
|
|
|
// cur = cur.Next
|
|
// }
|
|
|
|
// for ; cur != nil; cur = cur.Next {
|
|
// bn := &bNode{Value: cur.Value, Key: cur.Key}
|
|
// bkt.size++
|
|
// bn.Next = bkt.head
|
|
// bkt.head = bn
|
|
// }
|
|
|
|
// }
|
|
|
|
// hm.table = newtable
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
func (hm *HashMap) countNextGrow() {
|
|
hm.growsize = uint(len(hm.table)) << 2
|
|
}
|
|
|
|
func (hm *HashMap) grow() {
|
|
if hm.size >= hm.growsize {
|
|
newsize := hm.size << 1
|
|
newtable := make([]*avlTree, newsize, newsize)
|
|
|
|
nodelist := make([]*avlNode, hm.size, hm.size)
|
|
i := 0
|
|
for _, cur := range hm.table {
|
|
if cur != nil {
|
|
cur.Traversal(func(node *avlNode) bool {
|
|
nodelist[i] = node
|
|
i++
|
|
// hash := hm.GetHash(node.key)
|
|
// index := hash % newsize
|
|
// bkt := newtable[index]
|
|
// if bkt == nil {
|
|
// bkt = avlNew(hm.Compare)
|
|
// newtable[index] = bkt
|
|
// }
|
|
//bkt.Put(node.key, node.value)
|
|
return true
|
|
})
|
|
|
|
}
|
|
cur.Clear()
|
|
}
|
|
var hash, index uint
|
|
for _, node := range nodelist {
|
|
hash = hm.GetHash(node.key)
|
|
index = hash % newsize
|
|
bkt := newtable[index]
|
|
if bkt == nil {
|
|
bkt = avlNew(hm.Compare)
|
|
newtable[index] = bkt
|
|
}
|
|
bkt.PutNode(node)
|
|
}
|
|
hm.table = newtable
|
|
hm.countNextGrow()
|
|
}
|
|
}
|
|
|
|
func (hm *HashMap) Put(key, value interface{}) {
|
|
hash := hm.GetHash(key)
|
|
|
|
tlen := uint(len(hm.table))
|
|
index := hash % tlen
|
|
bkt := hm.table[index]
|
|
|
|
if bkt == nil {
|
|
bkt = avlNew(hm.Compare)
|
|
hm.table[index] = bkt
|
|
}
|
|
|
|
if bkt.Put(key, value) {
|
|
hm.size++
|
|
hm.grow()
|
|
}
|
|
|
|
// if bkt == nil {
|
|
// nbucket := &Bucket{size: 1}
|
|
// hm.table[index] = nbucket
|
|
// nbucket.head = &bNode{Value: value, Key: key}
|
|
// hm.size++
|
|
|
|
// hm.grow()
|
|
// return
|
|
// }
|
|
|
|
// cur := bkt.head
|
|
|
|
// for cur.Next != nil {
|
|
// if hm.Compare(key, cur.Key) == 0 {
|
|
// cur.Key = key
|
|
// cur.Value = value
|
|
// return
|
|
// }
|
|
// cur = cur.Next
|
|
// }
|
|
|
|
// bn := &bNode{Value: value, Key: key}
|
|
// hm.size++
|
|
// bkt.size++
|
|
|
|
// bn.Next = bkt.head
|
|
// bkt.head = bn
|
|
|
|
// hm.grow()
|
|
}
|
|
|
|
func (hm *HashMap) Get(key interface{}) (interface{}, bool) {
|
|
hash := hm.GetHash(key)
|
|
|
|
tlen := uint(len(hm.table))
|
|
index := hash % tlen
|
|
bkt := hm.table[index]
|
|
if bkt != nil {
|
|
return bkt.Get(key)
|
|
}
|
|
|
|
return nil, false
|
|
}
|