diff --git a/hashmap/avlkeydup.go b/hashmap/avlkeydup.go index 835416a..2489fb5 100644 --- a/hashmap/avlkeydup.go +++ b/hashmap/avlkeydup.go @@ -116,6 +116,52 @@ func (tree *avlTree) GetNode(key interface{}) (*avlNode, bool) { return nil, false } +func (tree *avlTree) PutNode(pnode *avlNode) bool { + + pnode.height = 0 + pnode.children[0] = nil + pnode.children[1] = nil + // pnode.parent = nil + + if tree.size == 0 { + tree.size++ + tree.root = pnode + pnode.parent = nil + return true + } + + for cur, c := tree.root, 0; ; { + c = tree.Compare(pnode.key, cur.key) + if c == -1 { + if cur.children[0] == nil { + tree.size++ + cur.children[0] = pnode + cur.children[0].parent = cur + if cur.height == 0 { + tree.fixPutHeight(cur) + } + return true + } + cur = cur.children[0] + } else if c == 1 { + if cur.children[1] == nil { + tree.size++ + cur.children[1] = pnode + cur.children[1].parent = cur + if cur.height == 0 { + tree.fixPutHeight(cur) + } + return true + } + cur = cur.children[1] + } else { + cur.key = pnode.key + cur.value = pnode.value + return false + } + } +} + func (tree *avlTree) Put(key, value interface{}) bool { if tree.size == 0 { diff --git a/hashmap/hashmap.go b/hashmap/hashmap.go index 51f0efa..2124206 100644 --- a/hashmap/hashmap.go +++ b/hashmap/hashmap.go @@ -10,7 +10,7 @@ type HashMap struct { growfactor uint slimmingfactor uint - table []interface{} + table []*avlTree GetHash HashCode Compare compare.Compare @@ -42,49 +42,74 @@ func New(hcode HashCode, comp compare.Compare) *HashMap { hm.GetHash = hcode hm.Compare = comp initcap := uint(8) - hm.table = make([]interface{}, initcap, initcap) - hm.growsize = initcap - initcap>>2 + 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([]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 - } + newtable := make([]*avlTree, newsize, newsize) + for _, cur := range hm.table { + if cur != nil { + cur.Traversal(func(k, v interface{}) bool { + hash := hm.GetHash(k) + index := hash % newsize + bkt := newtable[index] + if bkt == nil { + bkt = avlNew(hm.Compare) + newtable[index] = bkt + } + bkt.Put(k, v) + return true + }) } - - hm.table = newtable } + + hm.table = newtable + hm.countNextGrow() } } @@ -93,74 +118,58 @@ func (hm *HashMap) Put(key, value interface{}) { tlen := uint(len(hm.table)) index := hash % tlen - n := hm.table[index] + bkt := hm.table[index] - // if n == nil { - // n = avlNew(hm.Compare) - // hm.table[index] = n - // } + if bkt == nil { + bkt = avlNew(hm.Compare) + hm.table[index] = bkt + } - // bucket := n.(*avlTree) - // if bucket.Put(key, value) { + 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++ - // if hm.size >= hm.growsize { - // newsize := hm.size << 1 - // newtable := make([]interface{}, newsize, newsize) - // hm.growsize = newsize - newsize>>2 - - // 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 - - // } + // hm.grow() + // return // } - if n == nil { - nbucket := &Bucket{size: 1} - hm.table[index] = nbucket - nbucket.head = &bNode{Value: value, Key: key} - hm.size++ + // cur := bkt.head - hm.grow() - return - } + // for cur.Next != nil { + // if hm.Compare(key, cur.Key) == 0 { + // cur.Key = key + // cur.Value = value + // return + // } + // cur = cur.Next + // } - bkt := n.(*Bucket) - cur := bkt.head + // bn := &bNode{Value: value, Key: key} + // hm.size++ + // bkt.size++ - for cur.Next != nil { - if hm.Compare(key, cur.Key) == 0 { - cur.Key = key - cur.Value = value - return - } - cur = cur.Next - } + // bn.Next = bkt.head + // bkt.head = bn - bn := &bNode{Value: value, Key: key} - hm.size++ - bkt.size++ - - bn.Next = bkt.head - bkt.head = bn - - hm.grow() + // 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 } diff --git a/hashmap/hashmap_test.go b/hashmap/hashmap_test.go index b91cebb..b1e770e 100644 --- a/hashmap/hashmap_test.go +++ b/hashmap/hashmap_test.go @@ -30,23 +30,61 @@ func bToMb(b uint64) uint64 { return b / 1024 / 1024 } -func BenchmarkCount(b *testing.B) { +func BenchmarkPut(b *testing.B) { hm := New(HashInt, compare.Int) b.N = 100000 for i := 0; i < b.N; i++ { hm.Put(i, i) } - b.Log(len(hm.table), hm.size) - PrintMemUsage() + //b.Log(len(hm.table), hm.size) + //PrintMemUsage() } -func BenchmarkGoCount(b *testing.B) { +func BenchmarkGet(b *testing.B) { + b.StopTimer() + hm := New(HashInt, compare.Int) + b.N = 100000 + for i := 0; i < b.N; i++ { + hm.Put(i, i) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + hm.Get(i) + } + + //b.Log(len(hm.table), hm.size) + //PrintMemUsage() +} + +func BenchmarkGoPut(b *testing.B) { m := make(map[int]int) b.N = 100000 for i := 0; i < b.N; i++ { m[i] = i } - b.Log(len(m)) - PrintMemUsage() + //b.Log(len(m)) + //PrintMemUsage() +} + +func BenchmarkGoGet(b *testing.B) { + b.StopTimer() + m := make(map[int]int) + b.N = 100000 + for i := 0; i < b.N; i++ { + m[i] = i + } + for i := 0; i < b.N; i++ { + if _, ok := m[i]; !ok { + + } + } + b.StartTimer() + for i := 0; i < b.N; i++ { + if _, ok := m[i]; !ok { + + } + } + //b.Log(len(m)) + //PrintMemUsage() } diff --git a/hashmap/table.go b/hashmap/table.go new file mode 100644 index 0000000..76d6040 --- /dev/null +++ b/hashmap/table.go @@ -0,0 +1,202 @@ +package hashmap + +type Table struct { + // ysizes []int + // xsizes [][]int + // xyproduct int + + size uint + growsize uint + + data [][4][4]*avlTree + cap uint +} + +func newTable() *Table { + table := &Table{} + table.data = make([][4][4]*avlTree, 4, 4) + table.countCap() + return table +} + +func (t *Table) countCap() { + t.cap = uint(len(t.data)) << 4 // * (4 * 4) +} + +// func (t *Table) countNextGrow() { +// t.growsize = uint(len(t.data)) << 6 // +4 * (4 * 4) +// } + +// func (arr *Table) debugValues() []interface{} { +// var result []interface{} +// for _, z := range arr.data { +// if z != nil { +// for _, y := range z { +// if y == nil { +// for i := 0; i < arr.xsize; i++ { +// result = append(result, nil) +// } +// } else { +// for _, x := range y { +// if x == nil { +// result = append(result, struct{}{}) +// } else { +// result = append(result, x) +// } +// } +// } +// } +// } else { +// for i := 0; i < arr.ysize*arr.xsize; i++ { +// result = append(result, nil) +// } +// } +// } +// return result +// } + +// func (arr *Table) Values() []interface{} { +// var result []interface{} +// for _, z := range arr.data { +// if z != nil { + +// for _, y := range z { +// if y == nil { +// for i := 0; i < arr.xsize; i++ { +// result = append(result, nil) +// } +// } else { +// for _, x := range y { +// if x == nil { +// result = append(result, nil) +// } else { +// result = append(result, x) +// } +// } +// } +// } +// } else { +// for i := 0; i < arr.ysize*arr.xsize; i++ { +// result = append(result, nil) +// } +// } +// } + +// return result +// } + +func (t *Table) Cap() uint { + return t.cap +} + +func (t *Table) Grow(size int) { + zsize := len(t.data) + size + temp := make([][4][4]*avlTree, zsize, zsize) + copy(temp, t.data) + t.data = temp + t.countCap() +} + +func (t *Table) GetWithNilSet(idx int, DoSetValue func([4]*avlTree, int)) *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) + } + return v +} + +// func (arr *Table) Get(idx int) (interface{}, bool) { +// zindex := idx / arr.xyproduct +// nextsize := (idx % arr.xyproduct) +// yindex := nextsize / arr.xsize +// xindex := nextsize % arr.xsize + +// ydata := arr.data[zindex] +// if ydata == nil { +// return nil, false +// } + +// xdata := ydata[yindex] +// if xdata == nil { +// return nil, false +// } + +// v := xdata[xindex] +// return v, v != nil +// } + +// func (arr *Table) GetOrSet(idx int, DoSetValue func([]interface{}, int)) (result interface{}, isSet bool) { +// zindex := idx / arr.xyproduct +// nidx := (idx % arr.xyproduct) +// yindex := nidx / arr.xsize +// xindex := nidx % arr.xsize + +// ydata := arr.data[zindex] +// if ydata == nil { +// ydata = make([][]interface{}, arr.ysize, arr.ysize) +// arr.data[zindex] = ydata +// } + +// xdata := ydata[yindex] +// if xdata == nil { +// xdata = make([]interface{}, arr.xsize, arr.xsize) +// ydata[yindex] = xdata +// arr.ysizes[zindex]++ +// } + +// result = xdata[xindex] +// if result == nil { +// DoSetValue(xdata, xindex) +// result = xdata[xindex] +// if result == nil { +// panic("DoSetValue Not Set Value") +// } +// arr.xsizes[zindex][yindex]++ +// return result, false +// } +// return result, true +// } + +// func (arr *Table) Del(idx int) (interface{}, bool) { +// zindex := idx / arr.xyproduct +// nextsize := (idx % arr.xyproduct) +// yindex := nextsize / arr.xsize +// xindex := nextsize % arr.xsize + +// ydata := arr.data[zindex] +// if ydata == nil { +// return nil, false +// } + +// xdata := ydata[yindex] +// if xdata == nil { +// return nil, false +// } + +// v := xdata[xindex] +// xdata[xindex] = nil + +// isnotnil := v != nil + +// if isnotnil { +// arr.xsizes[zindex][yindex]-- +// if arr.xsizes[zindex][yindex] == 0 { +// arr.data[zindex][yindex] = nil + +// arr.ysizes[zindex]-- +// if arr.ysizes[zindex] == 0 { +// arr.data[zindex] = nil +// } +// } +// } + +// return v, isnotnil +// }