diff --git a/hashmap/avlkeydup.go b/hashmap/avlkeydup.go new file mode 100644 index 0000000..835416a --- /dev/null +++ b/hashmap/avlkeydup.go @@ -0,0 +1,642 @@ +package hashmap + +import ( + "474420502.top/eson/structure/compare" + "github.com/davecgh/go-spew/spew" +) + +type avlNode struct { + children [2]*avlNode + parent *avlNode + height int + key, value interface{} +} + +type avlTree struct { + root *avlNode + size int + Compare compare.Compare +} + +func avlNew(Compare compare.Compare) *avlTree { + return &avlTree{Compare: Compare} +} + +func (tree *avlTree) Size() int { + return tree.size +} + +func (tree *avlTree) Remove(key interface{}) (interface{}, bool) { + + if n, ok := tree.GetNode(key); ok { + + tree.size-- + if tree.size == 0 { + tree.root = nil + return n.value, true + } + + left := getHeight(n.children[0]) + right := getHeight(n.children[1]) + + if left == -1 && right == -1 { + p := n.parent + p.children[getRelationship(n)] = nil + tree.fixRemoveHeight(p) + return n.value, true + } + + var cur *avlNode + if left > right { + cur = n.children[0] + for cur.children[1] != nil { + cur = cur.children[1] + } + + cleft := cur.children[0] + cur.parent.children[getRelationship(cur)] = cleft + if cleft != nil { + cleft.parent = cur.parent + } + + } else { + cur = n.children[1] + for cur.children[0] != nil { + cur = cur.children[0] + } + + cright := cur.children[1] + cur.parent.children[getRelationship(cur)] = cright + + if cright != nil { + cright.parent = cur.parent + } + } + + cparent := cur.parent + // 修改为interface 交换 + n.value, cur.value = cur.value, n.value + n.key, cur.key = cur.key, n.key + + // 考虑到刚好替换的节点是 被替换节点的孩子节点的时候, 从自身修复高度 + if cparent == n { + tree.fixRemoveHeight(n) + } else { + tree.fixRemoveHeight(cparent) + } + + return cur.value, true + } + + return nil, false +} + +func (tree *avlTree) Get(key interface{}) (interface{}, bool) { + n, ok := tree.GetNode(key) + if ok { + return n.value, true + } + return n, false +} + +func (tree *avlTree) GetNode(key interface{}) (*avlNode, bool) { + + for n := tree.root; n != nil; { + switch c := tree.Compare(key, n.key); c { + case -1: + n = n.children[0] + case 1: + n = n.children[1] + case 0: + return n, true + default: + panic("Get Compare only is allowed in -1, 0, 1") + } + } + return nil, false +} + +func (tree *avlTree) Put(key, value interface{}) bool { + + if tree.size == 0 { + tree.size++ + tree.root = &avlNode{key: key, value: value} + return true + } + + for cur, c := tree.root, 0; ; { + c = tree.Compare(key, cur.key) + if c == -1 { + if cur.children[0] == nil { + tree.size++ + cur.children[0] = &avlNode{key: key, value: value} + 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] = &avlNode{key: key, value: value} + cur.children[1].parent = cur + if cur.height == 0 { + tree.fixPutHeight(cur) + } + return true + } + cur = cur.children[1] + } else { + cur.key = key + cur.value = value + return false + } + } +} + +type TraversalMethod int + +const ( + // L = left R = right D = Value(dest) + _ TraversalMethod = iota + //DLR 先值 然后左递归 右递归 下面同理 + DLR + //LDR 先从左边有序访问到右边 从小到大 + LDR + // LRD 同理 + LRD + // DRL 同理 + DRL + // RDL 先从右边有序访问到左边 从大到小 + RDL + // RLD 同理 + RLD +) + +// Traversal 遍历的方法 默认是LDR 从小到大 Compare 为 l < r +func (tree *avlTree) Traversal(every func(k, v interface{}) bool, traversalMethod ...interface{}) { + if tree.root == nil { + return + } + + method := LDR + if len(traversalMethod) != 0 { + method = traversalMethod[0].(TraversalMethod) + } + + switch method { + case DLR: + var traverasl func(cur *avlNode) bool + traverasl = func(cur *avlNode) bool { + if cur == nil { + return true + } + if !every(cur.key, cur.value) { + return false + } + if !traverasl(cur.children[0]) { + return false + } + if !traverasl(cur.children[1]) { + return false + } + return true + } + traverasl(tree.root) + case LDR: + var traverasl func(cur *avlNode) bool + traverasl = func(cur *avlNode) bool { + if cur == nil { + return true + } + if !traverasl(cur.children[0]) { + return false + } + if !every(cur.key, cur.value) { + return false + } + if !traverasl(cur.children[1]) { + return false + } + return true + } + traverasl(tree.root) + case LRD: + var traverasl func(cur *avlNode) bool + traverasl = func(cur *avlNode) bool { + if cur == nil { + return true + } + if !traverasl(cur.children[0]) { + return false + } + if !traverasl(cur.children[1]) { + return false + } + if !every(cur.key, cur.value) { + return false + } + return true + } + traverasl(tree.root) + case DRL: + var traverasl func(cur *avlNode) bool + traverasl = func(cur *avlNode) bool { + if cur == nil { + return true + } + if !every(cur.key, cur.value) { + return false + } + if !traverasl(cur.children[0]) { + return false + } + if !traverasl(cur.children[1]) { + return false + } + return true + } + traverasl(tree.root) + case RDL: + var traverasl func(cur *avlNode) bool + traverasl = func(cur *avlNode) bool { + if cur == nil { + return true + } + if !traverasl(cur.children[1]) { + return false + } + if !every(cur.key, cur.value) { + return false + } + if !traverasl(cur.children[0]) { + return false + } + return true + } + traverasl(tree.root) + case RLD: + var traverasl func(cur *avlNode) bool + traverasl = func(cur *avlNode) bool { + if cur == nil { + return true + } + if !traverasl(cur.children[1]) { + return false + } + if !traverasl(cur.children[0]) { + return false + } + if !every(cur.key, cur.value) { + return false + } + return true + } + traverasl(tree.root) + } +} + +func (tree *avlTree) lrrotate(cur *avlNode) { + + const l = 1 + const r = 0 + + movparent := cur.children[l] + mov := movparent.children[r] + + mov.value, cur.value = cur.value, mov.value //交换值达到, 相对位移 + mov.key, cur.key = cur.key, mov.key + + if mov.children[l] != nil { + movparent.children[r] = mov.children[l] + movparent.children[r].parent = movparent + //movparent.children[r].child = l + } else { + movparent.children[r] = nil + } + + if mov.children[r] != nil { + mov.children[l] = mov.children[r] + //mov.children[l].child = l + } else { + mov.children[l] = nil + } + + if cur.children[r] != nil { + mov.children[r] = cur.children[r] + mov.children[r].parent = mov + } else { + mov.children[r] = nil + } + + cur.children[r] = mov + mov.parent = cur + + mov.height = getMaxChildrenHeight(mov) + 1 + movparent.height = getMaxChildrenHeight(movparent) + 1 + cur.height = getMaxChildrenHeight(cur) + 1 +} + +func (tree *avlTree) rlrotate(cur *avlNode) { + + const l = 0 + const r = 1 + + movparent := cur.children[l] + mov := movparent.children[r] + + mov.value, cur.value = cur.value, mov.value //交换值达到, 相对位移 + mov.key, cur.key = cur.key, mov.key + + if mov.children[l] != nil { + movparent.children[r] = mov.children[l] + movparent.children[r].parent = movparent + } else { + movparent.children[r] = nil + } + + if mov.children[r] != nil { + mov.children[l] = mov.children[r] + } else { + mov.children[l] = nil + } + + if cur.children[r] != nil { + mov.children[r] = cur.children[r] + mov.children[r].parent = mov + } else { + mov.children[r] = nil + } + + cur.children[r] = mov + mov.parent = cur + + mov.height = getMaxChildrenHeight(mov) + 1 + movparent.height = getMaxChildrenHeight(movparent) + 1 + cur.height = getMaxChildrenHeight(cur) + 1 +} + +func (tree *avlTree) rrotate(cur *avlNode) { + + const l = 0 + const r = 1 + // 1 right 0 left + mov := cur.children[l] + + mov.value, cur.value = cur.value, mov.value //交换值达到, 相对位移 + mov.key, cur.key = cur.key, mov.key + + // mov.children[l]不可能为nil + mov.children[l].parent = cur + cur.children[l] = mov.children[l] + + // 解决mov节点孩子转移的问题 + if mov.children[r] != nil { + mov.children[l] = mov.children[r] + } else { + mov.children[l] = nil + } + + if cur.children[r] != nil { + mov.children[r] = cur.children[r] + mov.children[r].parent = mov + } else { + mov.children[r] = nil + } + + // 连接转移后的节点 由于mov只是与cur交换值,parent不变 + cur.children[r] = mov + + mov.height = getMaxChildrenHeight(mov) + 1 + cur.height = getMaxChildrenHeight(cur) + 1 +} + +func (tree *avlTree) lrotate(cur *avlNode) { + + const l = 1 + const r = 0 + + mov := cur.children[l] + + mov.value, cur.value = cur.value, mov.value //交换值达到, 相对位移 + mov.key, cur.key = cur.key, mov.key + + // 不可能为nil + mov.children[l].parent = cur + cur.children[l] = mov.children[l] + + if mov.children[r] != nil { + mov.children[l] = mov.children[r] + } else { + mov.children[l] = nil + } + + if cur.children[r] != nil { + mov.children[r] = cur.children[r] + mov.children[r].parent = mov + } else { + mov.children[r] = nil + } + + cur.children[r] = mov + + mov.height = getMaxChildrenHeight(mov) + 1 + cur.height = getMaxChildrenHeight(cur) + 1 +} + +func getMaxAndChildrenHeight(cur *avlNode) (h1, h2, maxh int) { + h1 = getHeight(cur.children[0]) + h2 = getHeight(cur.children[1]) + if h1 > h2 { + maxh = h1 + } else { + maxh = h2 + } + + return +} + +func getMaxChildrenHeight(cur *avlNode) int { + h1 := getHeight(cur.children[0]) + h2 := getHeight(cur.children[1]) + if h1 > h2 { + return h1 + } + return h2 +} + +func getHeight(cur *avlNode) int { + if cur == nil { + return -1 + } + return cur.height +} + +func (tree *avlTree) fixRemoveHeight(cur *avlNode) { + for { + + lefth, rigthh, lrmax := getMaxAndChildrenHeight(cur) + + // 判断当前节点是否有变化, 如果没变化的时候, 不需要往上修复 + curheight := lrmax + 1 + cur.height = curheight + + // 计算高度的差值 绝对值大于2的时候需要旋转 + diff := lefth - rigthh + if diff < -1 { + r := cur.children[1] // 根据左旋转的右边节点的子节点 左右高度选择旋转的方式 + if getHeight(r.children[0]) > getHeight(r.children[1]) { + tree.lrrotate(cur) + } else { + tree.lrotate(cur) + } + } else if diff > 1 { + l := cur.children[0] + if getHeight(l.children[1]) > getHeight(l.children[0]) { + tree.rlrotate(cur) + } else { + tree.rrotate(cur) + } + } else { + if cur.height == curheight { + return + } + } + + if cur.parent == nil { + return + } + + cur = cur.parent + } + +} + +func (tree *avlTree) fixPutHeight(cur *avlNode) { + + for { + + lefth := getHeight(cur.children[0]) + rigthh := getHeight(cur.children[1]) + + // 计算高度的差值 绝对值大于2的时候需要旋转 + diff := lefth - rigthh + if diff < -1 { + r := cur.children[1] // 根据左旋转的右边节点的子节点 左右高度选择旋转的方式 + if getHeight(r.children[0]) > getHeight(r.children[1]) { + tree.lrrotate(cur) + } else { + tree.lrotate(cur) + } + } else if diff > 1 { + l := cur.children[0] + if getHeight(l.children[1]) > getHeight(l.children[0]) { + tree.rlrotate(cur) + } else { + tree.rrotate(cur) + } + + } else { + // 选择一个child的最大高度 + 1为 高度 + if lefth > rigthh { + cur.height = lefth + 1 + } else { + cur.height = rigthh + 1 + } + } + + if cur.parent == nil || cur.height < cur.parent.height { + return + } + cur = cur.parent + } +} + +func getRelationship(cur *avlNode) int { + if cur.parent.children[1] == cur { + return 1 + } + return 0 +} + +func output(node *avlNode, prefix string, isTail bool, str *string) { + + if node.children[1] != nil { + newPrefix := prefix + if isTail { + newPrefix += "│ " + } else { + newPrefix += " " + } + output(node.children[1], newPrefix, false, str) + } + *str += prefix + if isTail { + *str += "└── " + } else { + *str += "┌── " + } + + *str += spew.Sprint(node.value) + "\n" + + if node.children[0] != nil { + newPrefix := prefix + if isTail { + newPrefix += " " + } else { + newPrefix += "│ " + } + output(node.children[0], newPrefix, true, str) + } + +} + +func outputfordebug(node *avlNode, prefix string, isTail bool, str *string) { + + if node.children[1] != nil { + newPrefix := prefix + if isTail { + newPrefix += "│ " + } else { + newPrefix += " " + } + outputfordebug(node.children[1], newPrefix, false, str) + } + *str += prefix + if isTail { + *str += "└── " + } else { + *str += "┌── " + } + + suffix := "(" + parentv := "" + if node.parent == nil { + parentv = "nil" + } else { + parentv = spew.Sprint(node.parent.value) + } + suffix += parentv + "|" + spew.Sprint(node.height) + ")" + *str += spew.Sprint(node.value) + suffix + "\n" + + if node.children[0] != nil { + newPrefix := prefix + if isTail { + newPrefix += " " + } else { + newPrefix += "│ " + } + outputfordebug(node.children[0], newPrefix, true, str) + } +} + +func (tree *avlTree) debugString() string { + if tree.size == 0 { + return "" + } + str := "AVLTree\n" + outputfordebug(tree.root, "", true, &str) + return str +} diff --git a/hashmap/hashmap.go b/hashmap/hashmap.go index 26ee198..38f396a 100644 --- a/hashmap/hashmap.go +++ b/hashmap/hashmap.go @@ -1,42 +1,85 @@ package hashmap import ( + "474420502.top/eson/structure/compare" + "474420502.top/eson/structure/sparse_array/array3" ) -type HashCode func(key interface{}) int -type EqualsCode func(k1, k2 interface{}) int +type HashCode func(key interface{}) uint type HashMap struct { - growfactor int + growfactor uint table *array3.Array3 - GetHash HashCode - IsEquals EqualsCode + GetHash HashCode + Compare compare.Compare + 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 - // log.Println(hbit) - // log.Println(lbit) - // log.Println() return lbit ^ hbit } -func New() *HashMap { +func New(hcode HashCode, comp compare.Compare) *HashMap { hm := &HashMap{} hm.growfactor = 2 - hm.table = array3.NewWithCap(hm.growfactor*2, hm.growfactor, hm.growfactor) + hm.GetHash = hcode + hm.Compare = comp + hm.table = array3.NewWithCap(hm.growfactor<<2, hm.growfactor<<2, hm.growfactor<<2) return hm } func (hm *HashMap) Put(key, value interface{}) { hash := hm.GetHash(key) + // log.Println(hm.table.Cap()) index := hash % hm.table.Cap() - hm.table.Set(index, value) + n, _ := hm.table.GetOrSet(index, func(data []interface{}, index uint) { + data[index] = avlNew(hm.Compare) + // data[index] = &Bucket{} + }) + + // bucket := n.(*Bucket) + // cur := bucket.head + + // 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 + // } + + // bn := &bNode{Value: value, Key: key} + // hm.size++ + // bucket.size++ + + // bn.Next = bucket.head + // bucket.head = bn + + bucket := n.(*avlTree) + if bucket.Put(key, value) { + hm.size++ + } } diff --git a/hashmap/hashmap_test.go b/hashmap/hashmap_test.go index 76935df..427cb5a 100644 --- a/hashmap/hashmap_test.go +++ b/hashmap/hashmap_test.go @@ -1,7 +1,52 @@ package hashmap -import "testing" +import ( + "fmt" + "runtime" + "testing" + + "474420502.top/eson/structure/compare" +) func TestCount(t *testing.T) { - HashInt(123123131221) + hm := New(HashInt, compare.Int) + + for i := 0; i < 1000000; i++ { + hm.Put(i, i) + } +} + +func PrintMemUsage() { + var m runtime.MemStats + runtime.ReadMemStats(&m) + // For info on each, see: https://golang.org/pkg/runtime/#MemStats + fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc)) + fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc)) + fmt.Printf("\tSys = %v MiB", bToMb(m.Sys)) + fmt.Printf("\tNumGC = %v\n", m.NumGC) +} + +func bToMb(b uint64) uint64 { + return b / 1024 / 1024 +} + +func BenchmarkCount(b *testing.B) { + hm := New(HashInt, compare.Int) + b.N = 10000 + for i := 0; i < b.N; i++ { + hm.Put(i, i) + } + + b.Log(hm.table.Cap(), hm.size) + PrintMemUsage() +} + +func BenchmarkGoCount(b *testing.B) { + m := make(map[int]int) + b.N = 10000 + for i := 0; i < b.N; i++ { + m[i] = i + } + b.Log(len(m)) + PrintMemUsage() }