From dd6309456f1547689170b83b48df51b98a26a04d Mon Sep 17 00:00:00 2001 From: eson <474420502@qq.com> Date: Mon, 22 Apr 2019 14:06:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=80=BC=E4=B8=8D=E5=AD=98=E5=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hashmap/hashmap.go | 131 +++++++--------------------------------- hashmap/hashmap_test.go | 4 +- hashmap/table.go | 31 +++++++--- 3 files changed, 48 insertions(+), 118 deletions(-) diff --git a/hashmap/hashmap.go b/hashmap/hashmap.go index d6df96a..317ccec 100644 --- a/hashmap/hashmap.go +++ b/hashmap/hashmap.go @@ -10,7 +10,7 @@ type HashMap struct { growfactor uint slimmingfactor uint - table []*avlTree + table *Table GetHash HashCode Compare compare.Compare @@ -19,16 +19,6 @@ type HashMap struct { 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 @@ -41,90 +31,45 @@ func New(hcode HashCode, comp compare.Compare) *HashMap { hm.growfactor = 2 hm.GetHash = hcode hm.Compare = comp - initcap := uint(8) - hm.table = make([]*avlTree, initcap, initcap) + // initcap := uint(8) + hm.table = newTable() 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 + hm.growsize = hm.table.Cap() << 2 } func (hm *HashMap) grow() { if hm.size >= hm.growsize { newsize := hm.size << 1 - newtable := make([]*avlTree, newsize, newsize) - + // newtable := make([]*avlTree, newsize, newsize) + hm.table.Grow(int(newsize - hm.size)) nodelist := make([]*avlNode, hm.size, hm.size) i := 0 - for _, cur := range hm.table { + hm.table.Traversal(func(cur *avlTree) { 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() } - 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 := newtable[index] + bkt := hm.table.GetWithNilSet(index, func(xdata *[4]*avlTree, xindex uint) { + (*xdata)[xindex] = avlNew(hm.Compare) + }) bkt.PutNode(node) } - hm.table = newtable + hm.countNextGrow() } } @@ -132,60 +77,28 @@ func (hm *HashMap) grow() { func (hm *HashMap) Put(key, value interface{}) { hash := hm.GetHash(key) - tlen := uint(len(hm.table)) + tlen := hm.table.Cap() index := hash % tlen - bkt := hm.table[index] - if bkt == nil { - bkt = avlNew(hm.Compare) - hm.table[index] = bkt - } + bkt := hm.table.GetWithNilSet(index, func(xdata *[4]*avlTree, xindex uint) { + (*xdata)[xindex] = avlNew(hm.Compare) + }) 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)) + tlen := hm.table.Cap() index := hash % tlen - bkt := hm.table[index] + + bkt := hm.table.Get(index) if bkt != nil { return bkt.Get(key) } - return nil, false } diff --git a/hashmap/hashmap_test.go b/hashmap/hashmap_test.go index b1e770e..53b7291 100644 --- a/hashmap/hashmap_test.go +++ b/hashmap/hashmap_test.go @@ -11,9 +11,11 @@ import ( func TestCount(t *testing.T) { hm := New(HashInt, compare.Int) - for i := 0; i < 1000; i++ { + for i := 0; i < 10; i++ { hm.Put(i, i) } + + t.Error(hm.Get(4)) } func PrintMemUsage() { diff --git a/hashmap/table.go b/hashmap/table.go index 76d6040..9b04370 100644 --- a/hashmap/table.go +++ b/hashmap/table.go @@ -89,6 +89,16 @@ func (t *Table) Cap() uint { return t.cap } +func (t *Table) Traversal(every func(node *avlTree)) { + for _, z := range t.data { + for _, y := range z { + for _, x := range y { + every(x) + } + } + } +} + func (t *Table) Grow(size int) { zsize := len(t.data) + size temp := make([][4][4]*avlTree, zsize, zsize) @@ -97,20 +107,25 @@ func (t *Table) Grow(size int) { t.countCap() } -func (t *Table) GetWithNilSet(idx int, DoSetValue func([4]*avlTree, int)) *avlTree { +func (t *Table) Get(idx uint) *avlTree { + zindex := idx / 16 + nidx := (idx % 16) + yindex := nidx / 4 + xindex := nidx % 4 + return t.data[zindex][yindex][xindex] +} + +func (t *Table) GetWithNilSet(idx uint, DoSetValue func(*[4]*avlTree, uint)) *avlTree { zindex := idx / 16 nidx := (idx % 16) yindex := nidx / 4 xindex := nidx % 4 - ydata := t.data[zindex] - xdata := ydata[yindex] - - v := xdata[xindex] - if v == nil { - DoSetValue(xdata, xindex) + xdata := t.data[zindex][yindex] + if xdata[xindex] == nil { + DoSetValue(&xdata, xindex) } - return v + return xdata[xindex] } // func (arr *Table) Get(idx int) (interface{}, bool) {