diff --git a/for_test.go b/for_test.go index 388c1e8..5d0cfcb 100644 --- a/for_test.go +++ b/for_test.go @@ -16,7 +16,7 @@ const NumberMax = 50000000 func TestSave(t *testing.T) { - f, err := os.OpenFile("../l.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + f, err := os.OpenFile("l.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if err != nil { log.Println(err) } diff --git a/hashmap/hashmap.go b/hashmap/hashmap.go index 38f396a..51f0efa 100644 --- a/hashmap/hashmap.go +++ b/hashmap/hashmap.go @@ -2,19 +2,21 @@ package hashmap import ( "474420502.top/eson/structure/compare" - - "474420502.top/eson/structure/sparse_array/array3" ) type HashCode func(key interface{}) uint type HashMap struct { - growfactor uint - table *array3.Array3 + growfactor uint + slimmingfactor uint + + table []interface{} GetHash HashCode Compare compare.Compare - size uint + + growsize uint + size uint } type bNode struct { @@ -39,47 +41,126 @@ func New(hcode HashCode, comp compare.Compare) *HashMap { hm.growfactor = 2 hm.GetHash = hcode hm.Compare = comp - hm.table = array3.NewWithCap(hm.growfactor<<2, hm.growfactor<<2, hm.growfactor<<2) + initcap := uint(8) + hm.table = make([]interface{}, initcap, initcap) + hm.growsize = initcap - initcap>>2 return hm } +func (hm *HashMap) grow() { + if hm.size >= hm.growsize { + newsize := hm.size << 1 + newtable := make([]interface{}, newsize, newsize) + hm.growsize = newsize - newsize>>2 + hm.size = 0 + + for _, v := range hm.table { + if v != nil { + bucket := v.(*Bucket) + cur := bucket.head + hash := hm.GetHash(cur.Key) + index := hash % newsize + var bkt *Bucket + n := newtable[index] + + if n == nil { + bkt = &Bucket{size: 1} + newtable[index] = bkt + bkt.head = &bNode{Value: cur.Value, Key: cur.Key} + hm.size++ + cur = cur.Next + } else { + bkt = n.(*Bucket) + } + + for ; cur != nil; cur = cur.Next { + bn := &bNode{Value: cur.Value, Key: cur.Key} + hm.size++ + bkt.size++ + bn.Next = bkt.head + bkt.head = bn + } + + } + + hm.table = newtable + } + } +} + func (hm *HashMap) Put(key, value interface{}) { hash := hm.GetHash(key) - // log.Println(hm.table.Cap()) - index := hash % hm.table.Cap() - n, _ := hm.table.GetOrSet(index, func(data []interface{}, index uint) { - data[index] = avlNew(hm.Compare) - // data[index] = &Bucket{} - }) - // bucket := n.(*Bucket) - // cur := bucket.head + tlen := uint(len(hm.table)) + index := hash % tlen + n := hm.table[index] - // if cur != nil { - // for cur.Next != nil { - // if hm.Compare(key, cur.Key) == 0 { - // cur.Key = key - // cur.Value = value - // return - // } - // cur = cur.Next - // } - // } else { - // bucket.head = &bNode{Value: value, Key: key} - // bucket.size++ - // hm.size++ - // return + // if n == nil { + // n = avlNew(hm.Compare) + // hm.table[index] = n // } - // bn := &bNode{Value: value, Key: key} - // hm.size++ - // bucket.size++ + // bucket := n.(*avlTree) + // if bucket.Put(key, value) { + // hm.size++ - // bn.Next = bucket.head - // bucket.head = bn + // if hm.size >= hm.growsize { + // newsize := hm.size << 1 + // newtable := make([]interface{}, newsize, newsize) + // hm.growsize = newsize - newsize>>2 - bucket := n.(*avlTree) - if bucket.Put(key, value) { + // for _, v := range hm.table { + // if v != nil { + // cur := v.(*avlTree) + // cur.Traversal(func(k, v interface{}) bool { + // hash := hm.GetHash(k) + // index := hash % newsize + // n := newtable[index] + // if n == nil { + // n = avlNew(hm.Compare) + // newtable[index] = n + // } + // bucket := n.(*avlTree) + // bucket.Put(k, v) + // return true + // }) + + // } + // } + + // hm.table = newtable + + // } + // } + + if n == nil { + nbucket := &Bucket{size: 1} + hm.table[index] = nbucket + nbucket.head = &bNode{Value: value, Key: key} hm.size++ + + hm.grow() + return } + + bkt := n.(*Bucket) + 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() } diff --git a/hashmap/hashmap_test.go b/hashmap/hashmap_test.go index 427cb5a..b91cebb 100644 --- a/hashmap/hashmap_test.go +++ b/hashmap/hashmap_test.go @@ -11,7 +11,7 @@ import ( func TestCount(t *testing.T) { hm := New(HashInt, compare.Int) - for i := 0; i < 1000000; i++ { + for i := 0; i < 1000; i++ { hm.Put(i, i) } } @@ -32,18 +32,18 @@ func bToMb(b uint64) uint64 { func BenchmarkCount(b *testing.B) { hm := New(HashInt, compare.Int) - b.N = 10000 + b.N = 100000 for i := 0; i < b.N; i++ { hm.Put(i, i) } - b.Log(hm.table.Cap(), hm.size) + b.Log(len(hm.table), hm.size) PrintMemUsage() } func BenchmarkGoCount(b *testing.B) { m := make(map[int]int) - b.N = 10000 + b.N = 100000 for i := 0; i < b.N; i++ { m[i] = i }