From 745f2ec3c37de633c0d1707b9cf45d72f1d5c2f9 Mon Sep 17 00:00:00 2001 From: huangsimin Date: Tue, 12 Mar 2019 19:18:42 +0800 Subject: [PATCH] =?UTF-8?q?TODO:=20Iterator=20=E9=A1=BA=E5=BA=8F=E9=81=8D?= =?UTF-8?q?=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- avl/avl.go | 631 ++++++++++++++++++ avl/avl_test.go | 343 ++++++++++ avl/iterator.go | 66 ++ avltree/avltree.go => avldup/avldup.go | 2 +- .../avltree_test.go => avldup/avldup_test.go | 0 5 files changed, 1041 insertions(+), 1 deletion(-) create mode 100644 avl/avl.go create mode 100644 avl/avl_test.go create mode 100644 avl/iterator.go rename avltree/avltree.go => avldup/avldup.go (99%) rename avltree/avltree_test.go => avldup/avldup_test.go (100%) diff --git a/avl/avl.go b/avl/avl.go new file mode 100644 index 0000000..f009479 --- /dev/null +++ b/avl/avl.go @@ -0,0 +1,631 @@ +package avl + +import ( + "github.com/davecgh/go-spew/spew" + + "github.com/emirpasic/gods/utils" +) + +type Node struct { + children [2]*Node + parent *Node + height int + child int + value interface{} +} + +// func (n *Node) String() string { +// if n == nil { +// return "nil" +// } +// return spew.Sprint(n.value) +// } + +func (n *Node) String() string { + if n == nil { + return "nil" + } + + p := "nil" + if n.parent != nil { + p = spew.Sprint(n.parent.value) + } + return spew.Sprint(n.value) + "(" + p + "-" + spew.Sprint(n.child) + "|" + spew.Sprint(n.height) + ")" +} + +type AVL struct { + root *Node + size int + comparator utils.Comparator +} + +func New(comparator utils.Comparator) *AVL { + return &AVL{comparator: comparator} +} + +func (avl *AVL) String() string { + if avl.size == 0 { + return "" + } + str := "AVL" + "\n" + output(avl.root, "", true, &str) + + return str +} + +func (avl *AVL) Iterator() *Iterator { + return initIterator(avl) +} + +func (avl *AVL) Remove(v interface{}) *Node { + + if n, ok := avl.GetNode(v); ok { + + avl.size-- + if avl.size == 0 { + avl.root = nil + return n + } + + left := getHeight(n.children[0]) + right := getHeight(n.children[1]) + + if left == -1 && right == -1 { + p := n.parent + p.children[n.child] = nil + avl.fixRemoveHeight(p) + return n + } + + var cur *Node + if left > right { + cur = n.children[0] + for cur.children[1] != nil { + cur = cur.children[1] + } + + cleft := cur.children[0] + cur.parent.children[cur.child] = cleft + if cleft != nil { + cleft.child = cur.child + 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[cur.child] = cright + if cright != nil { + cright.child = cur.child + cright.parent = cur.parent + } + } + + cparent := cur.parent + avl.replace(n, cur) + // 考虑到刚好替换的节点是 被替换节点的孩子节点的时候, 从自身修复高度 + if cparent == n { + avl.fixRemoveHeight(cur) + } else { + avl.fixRemoveHeight(cparent) + } + + return n + } + + return nil +} + +func (avl *AVL) Get(v interface{}) (interface{}, bool) { + n, ok := avl.GetNode(v) + if ok { + return n.value, true + } + return n, false +} + +func (avl *AVL) GetAround(v interface{}) (result [3]interface{}) { + an := avl.GetAroundNode(v) + for i, n := range an { + if n.value != nil { + result[i] = n.value + } + } + return +} + +func (avl *AVL) GetAroundNode(v interface{}) (result [3]*Node) { + n := avl.root + + for { + + if n == nil { + return + } + + lastc := 0 + switch c := avl.comparator(v, n.value); c { + case -1: + if c != -lastc { + result[0] = n + } + lastc = c + n = n.children[0] + case 1: + if c != -lastc { + result[2] = n + } + lastc = c + n = n.children[1] + case 0: + + switch lastc { + case -1: + if n.children[1] != nil { + result[0] = n.children[1] + } + case 1: + if n.children[0] != nil { + result[2] = n.children[0] + } + case 0: + + if n.children[1] != nil { + result[0] = n.children[1] + } + if n.children[0] != nil { + result[2] = n.children[0] + } + + result[1] = n + return + } + + default: + panic("Get comparator only is allowed in -1, 0, 1") + } + + } +} +func (avl *AVL) GetNode(v interface{}) (*Node, bool) { + + n := avl.root + for n != nil { + switch c := avl.comparator(v, n.value); c { + case -1: + n = n.children[0] + case 1: + n = n.children[1] + case 0: + return n, true + default: + panic("Get comparator only is allowed in -1, 0, 1") + } + } + + return nil, false +} + +func (avl *AVL) Put(v interface{}) { + avl.size++ + node := &Node{value: v} + if avl.size == 1 { + avl.root = node + return + } + + cur := avl.root + parent := cur.parent + child := -1 + + for { + + if cur == nil { + parent.children[child] = node + node.parent = parent + node.child = child + + if node.parent.height == 0 { + avl.fixPutHeight(node.parent) + } + return + } + + parent = cur + c := avl.comparator(node.value, cur.value) + if c > -1 { // right + child = 1 + cur = cur.children[child] + } else { + child = 0 + cur = cur.children[child] + } + } + +} + +func (avl *AVL) replace(old *Node, newN *Node) { + + if old.parent == nil { + setChild(newN, 0, old.children[0]) + setChild(newN, 1, old.children[1]) + + newN.parent = nil + newN.child = -1 + newN.height = old.height + + avl.root = newN + } else { + + setChild(newN, 0, old.children[0]) + setChild(newN, 1, old.children[1]) + + newN.parent = old.parent + newN.child = old.child + newN.height = old.height + old.parent.children[old.child] = newN + } +} + +func setChild(p *Node, child int, node *Node) { + p.children[child] = node + if node != nil { + node.child = child + node.parent = p + } +} + +func setChildNotNil(p *Node, child int, node *Node) { + p.children[child] = node + node.child = child + node.parent = p +} + +func (avl *AVL) debugString() string { + if avl.size == 0 { + return "" + } + str := "AVL" + "\n" + outputfordebug(avl.root, "", true, &str) + return str +} + +func (avl *AVL) TraversalBreadth() (result []interface{}) { + var traverasl func(cur *Node) + traverasl = func(cur *Node) { + if cur == nil { + return + } + result = append(result, cur.value) + traverasl(cur.children[0]) + traverasl(cur.children[1]) + } + traverasl(avl.root) + return +} + +func (avl *AVL) TraversalDepth(leftright int) (result []interface{}) { + + if leftright < 0 { + var traverasl func(cur *Node) + traverasl = func(cur *Node) { + if cur == nil { + return + } + traverasl(cur.children[0]) + result = append(result, cur.value) + traverasl(cur.children[1]) + } + traverasl(avl.root) + } else { + var traverasl func(cur *Node) + traverasl = func(cur *Node) { + if cur == nil { + return + } + traverasl(cur.children[1]) + result = append(result, cur.value) + traverasl(cur.children[0]) + } + traverasl(avl.root) + } + + return +} + +func (avl *AVL) lrrotate(cur *Node) *Node { + + r := cur.children[1] + rl := r.children[0] + if cur.parent == nil { + avl.root = rl + rl.parent = nil + } else { + setChildNotNil(cur.parent, cur.child, rl) + } + + rll := rl.children[0] + rlr := rl.children[1] + + setChild(cur, 1, rll) + setChild(r, 0, rlr) + + setChildNotNil(rl, 0, cur) + setChildNotNil(rl, 1, r) + + cur.height = getMaxChildrenHeight(cur) + 1 + r.height = getMaxChildrenHeight(r) + 1 + rl.height = getMaxChildrenHeight(rl) + 1 + + return rl +} + +func (avl *AVL) rlrotate(cur *Node) *Node { + + l := cur.children[0] + lr := l.children[1] + if cur.parent == nil { + avl.root = lr + lr.parent = nil + } else { + setChildNotNil(cur.parent, cur.child, lr) + } + + lrr := lr.children[1] + lrl := lr.children[0] + + setChild(cur, 0, lrr) + setChild(l, 1, lrl) + setChildNotNil(lr, 1, cur) + setChildNotNil(lr, 0, l) + + cur.height = getMaxChildrenHeight(cur) + 1 + l.height = getMaxChildrenHeight(l) + 1 + lr.height = getMaxChildrenHeight(lr) + 1 + + return lr +} + +func (avl *AVL) rrotate(cur *Node) *Node { + + l := cur.children[0] + + setChild(cur, 0, l.children[1]) + + l.parent = cur.parent + if cur.parent == nil { + avl.root = l + } else { + cur.parent.children[cur.child] = l + } + l.child = cur.child + + setChildNotNil(l, 1, cur) + // l.children[1] = cur + // cur.child = 1 + // cur.parent = l + + cur.height = getMaxChildrenHeight(cur) + 1 + l.height = getMaxChildrenHeight(l) + 1 + + return l // 返回前 替换为cur节点的节点, 有利余修复高度 +} + +func (avl *AVL) lrotate(cur *Node) *Node { + + r := cur.children[1] + + // 右左节点 链接 当前的右节点 + setChild(cur, 1, r.children[0]) + + // 设置 需要旋转的节点到当前节点的 链条 + r.parent = cur.parent + if cur.parent == nil { + avl.root = r + } else { + cur.parent.children[cur.child] = r + } + r.child = cur.child + + // 当前节点旋转到 左边的 链条 + setChildNotNil(r, 0, cur) + // r.children[0] = cur + // cur.child = 0 + // cur.parent = r + + // 修复改动过的节点高度 先从低开始到高 + cur.height = getMaxChildrenHeight(cur) + 1 + r.height = getMaxChildrenHeight(r) + 1 + + return r +} + +func getMaxAndChildrenHeight(cur *Node) (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 *Node) int { + h1 := getHeight(cur.children[0]) + h2 := getHeight(cur.children[1]) + if h1 > h2 { + return h1 + } + return h2 +} + +func getHeight(cur *Node) int { + if cur == nil { + return -1 + } + return cur.height +} + +func (avl *AVL) fixRemoveHeight(cur *Node) { + + for { + + lefth, rigthh, lrmax := getMaxAndChildrenHeight(cur) + + // 判断当前节点是否有变化, 如果没变化的时候, 不需要往上修复 + isBreak := false + if cur.height == lrmax+1 { + isBreak = true + } else { + cur.height = lrmax + 1 + } + + // 计算高度的差值 绝对值大于2的时候需要旋转 + diff := lefth - rigthh + if diff < -1 { + r := cur.children[1] // 根据左旋转的右边节点的子节点 左右高度选择旋转的方式 + if getHeight(r.children[0]) > getHeight(r.children[1]) { + cur = avl.lrrotate(cur) + } else { + cur = avl.lrotate(cur) + } + } else if diff > 1 { + l := cur.children[0] + if getHeight(l.children[1]) > getHeight(l.children[0]) { + cur = avl.rlrotate(cur) + } else { + cur = avl.rrotate(cur) + } + } else { + + if isBreak { + return + } + + } + + if cur.parent == nil { + return + } + + cur = cur.parent + } + +} + +func (avl *AVL) fixPutHeight(cur *Node) { + + 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]) { + cur = avl.lrrotate(cur) + } else { + cur = avl.lrotate(cur) + } + + } else if diff > 1 { + l := cur.children[0] + if getHeight(l.children[1]) > getHeight(l.children[0]) { + cur = avl.rlrotate(cur) + } else { + cur = avl.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 output(node *Node, 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 *Node, 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.child) + "|" + 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) + } +} diff --git a/avl/avl_test.go b/avl/avl_test.go new file mode 100644 index 0000000..a3df98a --- /dev/null +++ b/avl/avl_test.go @@ -0,0 +1,343 @@ +package avl + +import ( + "testing" + + "github.com/emirpasic/gods/trees/redblacktree" + + "github.com/emirpasic/gods/trees/avltree" + + "github.com/davecgh/go-spew/spew" + + "github.com/Pallinder/go-randomdata" + + "github.com/emirpasic/gods/utils" +) + +func TestRotate(t *testing.T) { + avl := New(utils.IntComparator) + + content := "" + for i := 0; i < 10; i++ { + v := randomdata.Number(0, 1000) + content += spew.Sprint(v) + " " + avl.Put(v) + } + + t.Error(content) + src := avl.String() + t.Error(src) + + lsrc := avl.String() + t.Error(lsrc) + // rrotate(&avl.root) + rsrc := avl.String() + t.Error(rsrc) + + if src == rsrc { + t.Error("src == rsrc") + } +} + +func TestIterator(t *testing.T) { + avl := New(utils.IntComparator) + for _, v := range []int{1, 2, 7, 4, 5, 6, 7, 14, 15, 20, 30, 21, 3} { + t.Error(v) + avl.Put(v) + t.Error(avl.debugString()) + } + t.Error(avl.TraversalDepth(1)) + iter := avl.Iterator() + for iter.Next() { + t.Error(iter.Value()) + } + t.Error("next == false", iter.Value()) +} + +func TestGetAround(t *testing.T) { + avl := New(utils.IntComparator) + for _, v := range []int{7, 14, 15, 20, 30, 21, 40, 40, 50, 3, 40, 40, 40} { + t.Error(v) + avl.Put(v) + t.Error(avl.debugString()) + } + t.Error(avl.TraversalDepth(1)) + t.Error(avl.GetAroundNode(40)) + t.Error(avl.GetAround(40)) +} + +func TestPutStable(t *testing.T) { + avl := New(utils.IntComparator) + for _, v := range []int{7, 14, 15, 20, 30, 21} { + t.Error(v) + avl.Put(v) + t.Error(avl.debugString()) + } + // avl = New(utils.IntComparator) + // for _, v := range []int{88, 77, 80} { + // avl.Put(v) + // t.Error(avl.String()) + // } +} + +func TestDiffPutRandom(t *testing.T) { + avl := New(utils.IntComparator) + godsavl := avltree.NewWithIntComparator() + + content := "" + m := make(map[int]int) + for i := 0; len(m) < 10; i++ { + v := randomdata.Number(0, 10000) + if _, ok := m[v]; !ok { + m[v] = v + content += spew.Sprint(v) + " " + t.Error(v) + avl.Put(v) + t.Error(avl.String()) + godsavl.Put(v, v) + } + } + t.Error(godsavl.String()) +} + +func TestPutComparatorRandom(t *testing.T) { + + for n := 0; n < 1000000; n++ { + avl := New(utils.IntComparator) + godsavl := avltree.NewWithIntComparator() + + content := "" + m := make(map[int]int) + for i := 0; len(m) < 10; i++ { + v := randomdata.Number(0, 65535) + if _, ok := m[v]; !ok { + m[v] = v + content += spew.Sprint(v) + " " + // t.Error(v) + avl.Put(v) + // t.Error(avl.String()) + godsavl.Put(v, v) + } + } + + if avl.String() != godsavl.String() { + t.Error(content) + break + } + } + + // t.Error(content) + // t.Error(avl.String()) + // t.Error(godsavl.String()) + // t.Error(avl.String() == godsavl.String()) + +} + +func TestGet(t *testing.T) { + avl := New(utils.IntComparator) + for i := 0; i < 15; i++ { + avl.Put(randomdata.Number(0, 1000)) + } + t.Error(avl.String()) + t.Error(avl.Get(500)) +} + +func TestRemoveAll(t *testing.T) { + + for c := 0; c < 10000; c++ { + // f, _ := os.OpenFile("./out.log", os.O_TRUNC|os.O_CREATE|os.O_RDWR, 0666) + // log.SetOutput(f) + + avl := New(utils.IntComparator) + var l []int + for i := 0; i < 100; i++ { + v := randomdata.Number(0, 100000) + l = append(l, v) + avl.Put(v) + } + // defer func() { + // if err := recover(); err != nil { + // panic(avl.String()) + // } + // }() + // log.Println(avl.TraversalBreadth()) + for i := 0; i < 100; i++ { + // log.Println(l[i]) + // log.Println(avl.debugString()) + avl.Remove(l[i]) + } + } +} + +func TestRemove(t *testing.T) { + + // avl := New(utils.IntComparator) + + // var l []int + // for _, v := range []int{86, 97, 9, 61, 37, 45, 97, 43, 95, 8} { + // l = append(l, v) + // avl.Put(v) + // } + + // for i := 0; i < len(l); i++ { + // // log.Println(i) + // log.Println("begin", l[i], avl.debugString()) + // avl.Remove(l[i]) + // log.Println("end", l[i], avl.debugString()) + // } + +ALL: + for N := 0; N < 500000; N++ { + avl := New(utils.IntComparator) + gods := avltree.NewWithIntComparator() + + var l []int + m := make(map[int]int) + + for i := 0; len(l) < 10; i++ { + v := randomdata.Number(0, 100) + if _, ok := m[v]; !ok { + l = append(l, v) + m[v] = v + avl.Put(v) + gods.Put(v, v) + } + } + + src1 := avl.String() + src2 := gods.String() + + for i := 0; i < 10; i++ { + avl.Remove(l[i]) + gods.Remove(l[i]) + if spew.Sprint(gods.Values()) != spew.Sprint(avl.TraversalDepth(-1)) && avl.size != 0 { + // if gods.String() != avl.String() && gods.Size() != 0 && avl.size != 0 { + t.Error(src1) + t.Error(src2) + t.Error(avl.debugString()) + t.Error(gods.String()) + t.Error(l[i]) + // t.Error(avl.TraversalDepth(-1)) + // t.Error(gods.Values()) + break ALL + + } + } + } +} + +const PutCompartorSize = 300000 +const NumberMax = 60000000 + +func BenchmarkRemove(b *testing.B) { + + avl := New(utils.IntComparator) + b.N = PutCompartorSize + + var l []int + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, NumberMax) + l = append(l, v) + avl.Put(v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + avl.Remove(l[i]) + } +} + +func BenchmarkGodsRemove(b *testing.B) { + avl := avltree.NewWithIntComparator() + b.N = PutCompartorSize + + var l []int + for i := 0; i < b.N; i++ { + v := randomdata.Number(0, NumberMax) + l = append(l, v) + avl.Put(v, v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + avl.Remove(l[i]) + } +} + +func BenchmarkGet(b *testing.B) { + avl := New(utils.IntComparator) + + b.N = PutCompartorSize + for i := 0; i < b.N/2; i++ { + avl.Put(randomdata.Number(0, NumberMax)) + } + + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + avl.Get(randomdata.Number(0, NumberMax)) + } +} + +func BenchmarkGodsRBGet(b *testing.B) { + rb := redblacktree.NewWithIntComparator() + + b.N = PutCompartorSize + for i := 0; i < b.N/2; i++ { + rb.Put(randomdata.Number(0, NumberMax), i) + } + + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + rb.Get(randomdata.Number(0, NumberMax)) + } +} + +func BenchmarkGodsAvlGet(b *testing.B) { + rb := avltree.NewWithIntComparator() + + b.N = PutCompartorSize + for i := 0; i < b.N/2; i++ { + rb.Put(randomdata.Number(0, NumberMax), i) + } + + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + rb.Get(randomdata.Number(0, NumberMax)) + } +} + +func BenchmarkPut(b *testing.B) { + avl := New(utils.IntComparator) + + b.N = PutCompartorSize + for i := 0; i < b.N; i++ { + avl.Put(randomdata.Number(0, NumberMax)) + } + +} + +func BenchmarkGodsRBPut(b *testing.B) { + rb := redblacktree.NewWithIntComparator() + + b.N = PutCompartorSize + for i := 0; i < b.N; i++ { + rb.Put(randomdata.Number(0, NumberMax), i) + } + +} + +func BenchmarkGodsPut(b *testing.B) { + avl := avltree.NewWithIntComparator() + + b.N = PutCompartorSize + for i := 0; i < b.N; i++ { + avl.Put(randomdata.Number(0, NumberMax), i) + } +} diff --git a/avl/iterator.go b/avl/iterator.go new file mode 100644 index 0000000..69a1a40 --- /dev/null +++ b/avl/iterator.go @@ -0,0 +1,66 @@ +package avl + +import ( + "log" + + "github.com/emirpasic/gods/stacks/arraystack" +) + +type Iterator struct { + op *AVL + + cur *Node + prevstack *arraystack.Stack + nextstack *arraystack.Stack + // curnext *Node +} + +func initIterator(avltree *AVL) *Iterator { + iter := &Iterator{op: avltree, prevstack: arraystack.New(), nextstack: arraystack.New()} + iter.cur = avltree.root + // iter.nextstack.Push(avltree.root) + return iter +} + +func (iter *Iterator) Value() interface{} { + return iter.cur.value +} + +func (iter *Iterator) Next() (result bool) { + + if iter.nextstack.Size() == 0 { + iter.nextstack.Push(iter.cur) + } + + if v, ok := iter.nextstack.Pop(); ok { + iter.cur = v.(*Node) + iter.curPushNextStack(iter.cur) + log.Println(iter.nextstack.Size()) + return true + } + + return false +} + +func (iter *Iterator) curPushNextStack(cur *Node) { + next := cur.children[0] + + if next != nil { + iter.nextstack.Push(next) + for next.children[1] != nil { + next = next.children[1] + iter.nextstack.Push(next) + } + } +} + +func (iter *Iterator) Prev() (result bool) { + + if v, ok := iter.nextstack.Pop(); ok { + iter.cur = v.(*Node) + iter.curPushNextStack(iter.cur) + return true + } + + return false +} diff --git a/avltree/avltree.go b/avldup/avldup.go similarity index 99% rename from avltree/avltree.go rename to avldup/avldup.go index c2e1ff7..ec550e9 100644 --- a/avltree/avltree.go +++ b/avldup/avldup.go @@ -338,7 +338,7 @@ func (avl *AVLTree) rrotate(cur *Node) *Node { cur.height = getMaxChildrenHeight(cur) + 1 l.height = getMaxChildrenHeight(l) + 1 - return l + return l // 返回前 替换为cur节点的节点, 有利余修复高度 } func (avl *AVLTree) lrotate(cur *Node) *Node { diff --git a/avltree/avltree_test.go b/avldup/avldup_test.go similarity index 100% rename from avltree/avltree_test.go rename to avldup/avldup_test.go