diff --git a/priority_queuekey/iterator.go b/priority_queuekey/iterator.go new file mode 100644 index 0000000..bee120c --- /dev/null +++ b/priority_queuekey/iterator.go @@ -0,0 +1,230 @@ +package pqueue + +import ( + "474420502.top/eson/structure/lastack" +) + +type Iterator struct { + dir int + up *Node + cur *Node + tstack *lastack.Stack + // curnext *Node +} + +func initIterator(avltree *vbTree) *Iterator { + iter := &Iterator{tstack: lastack.New()} + iter.up = avltree.root + return iter +} + +func NewIterator(n *Node) *Iterator { + iter := &Iterator{tstack: lastack.New()} + iter.up = n + return iter +} + +func NewIteratorWithCap(n *Node, cap int) *Iterator { + iter := &Iterator{tstack: lastack.NewWithCap(cap)} + iter.up = n + return iter +} + +func (iter *Iterator) SeNode(n *Node) { + iter.up = n + iter.dir = 0 + iter.tstack.Clear() +} + +func (iter *Iterator) Value() interface{} { + return iter.cur.value +} + +func (iter *Iterator) Left() bool { + if iter.cur.children[0] != nil { + iter.dir = 0 + iter.cur = iter.cur.children[0] + return true + } + return false +} + +func (iter *Iterator) Right() bool { + if iter.cur.children[1] != nil { + iter.dir = 0 + iter.cur = iter.cur.children[1] + return true + } + return false +} + +func (iter *Iterator) GetNext(cur *Node, idx int) *Node { + + // iter := NewIterator(cur) + iter.SeNode(cur) + iter.curPushNextStack(iter.up) + iter.up = iter.getNextUp(iter.up) + + for i := 0; i < idx; i++ { + + if iter.tstack.Size() == 0 { + if iter.up == nil { + return nil + } + iter.tstack.Push(iter.up) + iter.up = iter.getNextUp(iter.up) + } + + if v, ok := iter.tstack.Pop(); ok { + iter.cur = v.(*Node) + if i == idx-1 { + return iter.cur + } + iter.curPushNextStack(iter.cur) + } else { + return nil + } + } + + return cur +} + +func (iter *Iterator) Next() (result bool) { + + if iter.dir > -1 { + if iter.dir == 1 && iter.cur != nil { + iter.tstack.Clear() + iter.curPushNextStack(iter.cur) + iter.up = iter.getNextUp(iter.cur) + } + iter.dir = -1 + } + + if iter.tstack.Size() == 0 { + if iter.up == nil { + return false + } + iter.tstack.Push(iter.up) + iter.up = iter.getNextUp(iter.up) + } + + if v, ok := iter.tstack.Pop(); ok { + iter.cur = v.(*Node) + iter.curPushNextStack(iter.cur) + return true + } + + return false +} + +func (iter *Iterator) GetPrev(cur *Node, idx int) *Node { + + // iter := NewIterator(cur) + iter.SeNode(cur) + iter.curPushPrevStack(iter.up) + iter.up = iter.getPrevUp(iter.up) + + for i := 0; i < idx; i++ { + + if iter.tstack.Size() == 0 { + if iter.up == nil { + return nil + } + iter.tstack.Push(iter.up) + iter.up = iter.getPrevUp(iter.up) + } + + if v, ok := iter.tstack.Pop(); ok { + iter.cur = v.(*Node) + if i == idx-1 { + return iter.cur + } + iter.curPushPrevStack(iter.cur) + } else { + return nil + } + } + + return cur +} + +func (iter *Iterator) Prev() (result bool) { + + if iter.dir < 1 { // 非 1(next 方向定义 -1 为 prev) + if iter.dir == -1 && iter.cur != nil { // 如果上次为prev方向, 则清空辅助计算的栈 + iter.tstack.Clear() + iter.curPushPrevStack(iter.cur) // 把当前cur计算的逆向回朔 + iter.up = iter.getPrevUp(iter.cur) // cur 寻找下个要计算up + } + iter.dir = 1 + } + + // 如果栈空了, 把up的递归计算入栈, 重新计算 下次的up值 + if iter.tstack.Size() == 0 { + if iter.up == nil { + return false + } + iter.tstack.Push(iter.up) + iter.up = iter.getPrevUp(iter.up) + } + + if v, ok := iter.tstack.Pop(); ok { + iter.cur = v.(*Node) + iter.curPushPrevStack(iter.cur) + return true + } + + // 如果再次计算的栈为空, 则只能返回false + return false +} + +func getRelationship(cur *Node) int { + if cur.parent.children[1] == cur { + return 1 + } + return 0 +} + +func (iter *Iterator) getPrevUp(cur *Node) *Node { + for cur.parent != nil { + if getRelationship(cur) == 1 { // next 在 降序 小值. 如果child在右边, parent 比 child 小, parent才有效, 符合降序 + return cur.parent + } + cur = cur.parent + } + return nil +} + +func (iter *Iterator) curPushPrevStack(cur *Node) { + Prev := cur.children[0] // 当前的左然后向右找, 找到最大, 就是最接近cur 并且小于cur的值 + + if Prev != nil { + iter.tstack.Push(Prev) + for Prev.children[1] != nil { + Prev = Prev.children[1] + iter.tstack.Push(Prev) // 入栈 用于回溯 + } + } +} + +func (iter *Iterator) getNextUp(cur *Node) *Node { + for cur.parent != nil { + if getRelationship(cur) == 0 { // Prev 在 降序 大值. 如果child在左边, parent 比 child 大, parent才有效 , 符合降序 + return cur.parent + } + cur = cur.parent + } + return nil +} + +func (iter *Iterator) curPushNextStack(cur *Node) { + next := cur.children[1] + + if next != nil { + iter.tstack.Push(next) + for next.children[0] != nil { + next = next.children[0] + iter.tstack.Push(next) + } + } +} diff --git a/priority_queuekey/priority_queuekey.go b/priority_queuekey/priority_queuekey.go new file mode 100644 index 0000000..7dd1f10 --- /dev/null +++ b/priority_queuekey/priority_queuekey.go @@ -0,0 +1,80 @@ +package pqueue + +import "474420502.top/eson/structure/compare" + +type PriorityQueue struct { + queue *vbTree +} + +func (pq *PriorityQueue) Iterator() *Iterator { + return NewIterator(pq.queue.top) +} + +func New(Compare compare.Compare) *PriorityQueue { + return &PriorityQueue{queue: newVBT(Compare)} +} + +func (pq *PriorityQueue) Size() int { + return pq.queue.Size() +} + +func (pq *PriorityQueue) Push(key, value interface{}) { + pq.queue.Put(key, value) +} + +func (pq *PriorityQueue) Top() (result interface{}, ok bool) { + if pq.queue.top != nil { + return pq.queue.top.value, true + } + return nil, false +} + +func (pq *PriorityQueue) Pop() (result interface{}, ok bool) { + if pq.queue.top != nil { + result = pq.queue.top.value + pq.queue.removeNode(pq.queue.top) + return result, true + } + return nil, false +} + +func (pq *PriorityQueue) Index(idx int) (interface{}, bool) { + return pq.queue.Index(idx) +} + +func (pq *PriorityQueue) IndexNode(idx int) (*Node, bool) { + n := pq.queue.indexNode(idx) + return n, n != nil +} + +func (pq *PriorityQueue) Get(key interface{}) (interface{}, bool) { + return pq.queue.Get(key) +} + +func (pq *PriorityQueue) GetNode(key interface{}) (*Node, bool) { + return pq.queue.GetNode(key) +} + +func (pq *PriorityQueue) GetAround(key interface{}) [3]interface{} { + return pq.queue.GetAround(key) +} + +func (pq *PriorityQueue) GetAroundNode(key interface{}) [3]*Node { + return pq.queue.getArounNode(key) +} + +func (pq *PriorityQueue) GetRange(k1, k2 interface{}) []interface{} { + return pq.queue.GetRange(k1, k2) +} + +func (pq *PriorityQueue) RemoveIndex(idx int) (interface{}, bool) { + return pq.queue.RemoveIndex(idx) +} + +func (pq *PriorityQueue) Remove(key interface{}) (interface{}, bool) { + return pq.queue.Remove(key) +} + +func (pq *PriorityQueue) Values() []interface{} { + return pq.queue.Values() +} diff --git a/priority_queuekey/priority_queuekey_test.go b/priority_queuekey/priority_queuekey_test.go new file mode 100644 index 0000000..dbe9b97 --- /dev/null +++ b/priority_queuekey/priority_queuekey_test.go @@ -0,0 +1,347 @@ +package pqueue + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + + "474420502.top/eson/structure/compare" +) + +func TestQueuePush(t *testing.T) { + pq := New(compare.Int) + for _, v := range []int{32, 10, 53, 78, 90, 1, 4} { + pq.Push(v, v) + if v, ok := pq.Top(); ok { + } else { + t.Error(v) + } + } + + if v, ok := pq.Top(); ok { + if v != 90 { + t.Error(v) + } + } else { + t.Error(v) + } + +} + +func TestQueuePop(t *testing.T) { + pq := New(compare.Int) + for _, v := range []int{32, 10, 53, 78, 90, 1, 4} { + pq.Push(v, v) + if v, ok := pq.Top(); ok { + } else { + t.Error(v) + } + } + + l := []int{90, 78, 53, 32, 10, 4, 1} + for _, lv := range l { + if v, ok := pq.Pop(); ok { + if v != lv { + t.Error(v) + } + } else { + t.Error(v) + } + } + + if v, ok := pq.Pop(); ok { + t.Error(v) + } +} + +func TestQueueGet(t *testing.T) { + pq := New(compare.Int) + l := []int{32, 10, 53, 78, 90, 1, 4} + for _, v := range l { + pq.Push(v, v) + } + + if v, ok := pq.Get(0); ok { + t.Error(v) + } + + if v, ok := pq.Get(70); ok { + t.Error(v) + } + + for _, v := range l { + if gv, ok := pq.Get(v); ok { + if gv != v { + t.Error("Get value is error, value is", gv) + } + } + } + +} + +func TestQueueGetRange(t *testing.T) { + pq := New(compare.Int) + l := []int{32, 10, 53, 78, 90, 1, 4} + for _, v := range l { + pq.Push(v, v) + } + + var result string + result = spew.Sprint(pq.GetRange(10, 40)) + if result != "[10 32]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetRange(1, 90)) + if result != "[1 4 10 32 53 78 90]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetRange(0, 90)) + if result != "[1 4 10 32 53 78 90]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetRange(1, 100)) + if result != "[1 4 10 32 53 78 90]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetRange(5, 88)) + if result != "[10 32 53 78]" { + t.Error(result) + } +} + +func TestQueueGetAround(t *testing.T) { + pq := New(compare.Int) + l := []int{32, 10, 53, 78, 90, 1, 4} + for _, v := range l { + pq.Push(v, v) + } + + var result string + result = spew.Sprint(pq.GetAround(53)) + if result != "[32 53 78]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetAround(52)) + if result != "[32 53]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetAround(1)) + if result != "[ 1 4]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetAround(90)) + if result != "[78 90 ]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetAround(0)) + if result != "[ 1]" { + t.Error(result) + } + + result = spew.Sprint(pq.GetAround(100)) + if result != "[90 ]" { + t.Error(result) + } +} + +func TestQueueRemove(t *testing.T) { + pq := New(compare.Int) + l := []int{32, 10, 53, 78, 90, 1, 4} + for _, v := range l { + pq.Push(v, v) + } + + content := "" + for _, v := range l { + pq.Remove(v) + content += spew.Sprint(pq.Values()) + } + + if content != "[1 4 10 53 78 90][1 4 53 78 90][1 4 78 90][1 4 90][1 4][4][]" { + t.Error(content) + } +} + +func TestQueueRemoveIndex(t *testing.T) { + pq := New(compare.Int) + l := []int{32, 10, 53, 78, 90, 1, 4} + for _, v := range l { + pq.Push(v, v) + } + + content := "" + for range l { + pq.RemoveIndex(0) + content += spew.Sprint(pq.Values()) + } + + if content != "[1 4 10 32 53 78][1 4 10 32 53][1 4 10 32][1 4 10][1 4][1][]" { + t.Error(content) + } + + if n, ok := pq.RemoveIndex(0); ok { + t.Error("pq is not exist elements", n) + } + +} + +func TestQueueIndex(t *testing.T) { + pq := New(compare.Int) + for _, v := range []int{32, 10, 53, 78, 90, 1, 4} { + pq.Push(v, v) + } + + l := []int{90, 78, 53, 32, 10, 4, 1} + for i, lv := range l { + + if v, ok := pq.Index(len(l) - i - 1); ok { + if v != l[len(l)-i-1] { + t.Error(v) + } + } else { + t.Error(i, "index is not exist") + } + + if v, ok := pq.Index(i); ok { + if v != lv { + t.Error(v) + } + } else { + t.Error(i, "index is not exist") + } + } + + if v, ok := pq.Index(-1); ok { + if v != 1 { + t.Error(v) + } + } else { + t.Error("-1 index is not exist") + } + + if v, ok := pq.Index(pq.Size()); ok { + t.Error("index is exits", pq.Size(), v) + } + + if v, ok := pq.Index(pq.Size() - 1); !ok { + if v != 1 { + t.Error("the last value is 1 not is ", v) + } + } + + if v, ok := pq.Index(-10); ok { + t.Error("-10 index is exits", v) + } +} + +func BenchmarkQueueGet(b *testing.B) { + + l := loadTestData() + + pq := New(compare.Int) + for _, v := range l { + pq.Push(v, v) + } + + execCount := 5 + b.N = len(l) * execCount + + b.ResetTimer() + b.StartTimer() + +ALL: + for i := 0; i < execCount; i++ { + for _, v := range l { + if gv, ok := pq.Get(v); !ok { + b.Error(gv) + break ALL + } + } + } +} + +func BenchmarkQueueRemove(b *testing.B) { + l := loadTestData() + + pq := New(compare.Int) + for _, v := range l { + pq.Push(v, v) + } + + b.N = len(l) + b.ResetTimer() + b.StartTimer() + + for _, v := range l { + pq.Remove(v) + } +} + +func BenchmarkQueueIndex(b *testing.B) { + + l := loadTestData() + + pq := New(compare.Int) + for _, v := range l { + pq.Push(v, v) + } + + execCount := 2 + b.N = len(l) * execCount + + b.ResetTimer() + b.StartTimer() + +ALL: + for i := 0; i < execCount; i++ { + for idx := range l { + if v, ok := pq.Index(idx); !ok { + b.Error(v) + break ALL + } + } + } +} + +func BenchmarkPriorityPush(b *testing.B) { + + l := loadTestData() + execCount := 5 + b.N = len(l) * execCount + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < execCount; i++ { + pq := New(compare.Int) + for _, v := range l { + pq.Push(v, v) + } + } +} + +func BenchmarkPriorityPop(b *testing.B) { + + l := loadTestData() + + pq := New(compare.Int) + for _, v := range l { + pq.Push(v, v) + } + + b.N = len(l) + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + pq.Pop() + } +} diff --git a/priority_queuekey/vbt.go b/priority_queuekey/vbt.go new file mode 100644 index 0000000..2ecd73c --- /dev/null +++ b/priority_queuekey/vbt.go @@ -0,0 +1,967 @@ +package pqueue + +import ( + "474420502.top/eson/structure/compare" + "github.com/davecgh/go-spew/spew" +) + +type Node struct { + children [2]*Node + parent *Node + size int + key, value interface{} +} + +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.size) + ")" +} + +type vbTree struct { + root *Node + Compare compare.Compare + + top *Node + + iter *Iterator +} + +func newVBT(Compare compare.Compare) *vbTree { + return &vbTree{Compare: Compare, iter: NewIteratorWithCap(nil, 16)} +} + +func (tree *vbTree) String() string { + str := "AVLTree\n" + if tree.root == nil { + return str + "nil" + } + output(tree.root, "", true, &str) + return str +} + +func (tree *vbTree) Iterator() *Iterator { + return initIterator(tree) +} + +func (tree *vbTree) Size() int { + if tree.root == nil { + return 0 + } + return tree.root.size +} + +func (tree *vbTree) indexNode(idx int) *Node { + cur := tree.root + if idx >= 0 { + for cur != nil { + rs := getSize(cur.children[1]) + if idx == rs { + return cur + } else if idx < rs { + cur = cur.children[1] + } else { + idx = idx - rs - 1 + cur = cur.children[0] + } + } + } else { + idx = -idx - 1 + for cur != nil { + ls := getSize(cur.children[0]) + if idx == ls { + return cur + } else if idx < ls { + cur = cur.children[0] + } else { + idx = idx - ls - 1 + cur = cur.children[1] + } + } + } + return nil +} + +func (tree *vbTree) Index(idx int) (interface{}, bool) { + n := tree.indexNode(idx) + if n != nil { + return n.value, true + } + return nil, false +} + +func (tree *vbTree) IndexRange(idx1, idx2 int) (result []interface{}, ok bool) { // 0 -1 + + if idx1^idx2 < 0 { + if idx1 < 0 { + idx1 = tree.root.size + idx1 - 1 + } else { + idx2 = tree.root.size + idx2 - 1 + } + } + + if idx1 > idx2 { + ok = true + if idx1 >= tree.root.size { + idx1 = tree.root.size - 1 + ok = false + } + + n := tree.indexNode(idx1) + tree.iter.SeNode(n) + iter := tree.iter + result = make([]interface{}, 0, idx1-idx2) + for i := idx2; i <= idx1; i++ { + if iter.Next() { + result = append(result, iter.Value()) + } else { + ok = false + return + } + } + + return + + } else { + ok = true + if idx2 >= tree.root.size { + idx2 = tree.root.size - 1 + ok = false + } + + if n := tree.indexNode(idx1); n != nil { + tree.iter.SeNode(n) + iter := tree.iter + result = make([]interface{}, 0, idx2-idx1) + for i := idx1; i <= idx2; i++ { + if iter.Prev() { + result = append(result, iter.Value()) + } else { + ok = false + return + } + } + + return + } + + } + + return nil, false +} + +func (tree *vbTree) RemoveIndex(idx int) (interface{}, bool) { + n := tree.indexNode(idx) + if n != nil { + tree.removeNode(n) + return n.value, true + } + return nil, false +} + +func (tree *vbTree) removeNode(n *Node) { + if tree.root.size == 1 { + tree.root = nil + tree.top = nil + // return n + return + } + + if tree.top == n { + tree.top = tree.iter.GetPrev(n, 1) + } + + ls, rs := getChildrenSize(n) + if ls == 0 && rs == 0 { + p := n.parent + p.children[getRelationship(n)] = nil + tree.fixSizeWithRemove(p) + // return n + return + } + + var cur *Node + if ls > rs { + 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 + tree.replace(n, cur) + + // 考虑到刚好替换的节点是 被替换节点的孩子节点的时候, 从自身修复高度 + if cparent == n { + tree.fixSizeWithRemove(cur) + } else { + tree.fixSizeWithRemove(cparent) + } + + // return cur + return +} + +func (tree *vbTree) Remove(key interface{}) (interface{}, bool) { + + if n, ok := tree.GetNode(key); ok { + tree.removeNode(n) + return n.value, true + } + // return nil + return nil, false +} + +// Values 返回先序遍历的值 +func (tree *vbTree) Values() []interface{} { + mszie := 0 + if tree.root != nil { + mszie = tree.root.size + } + result := make([]interface{}, 0, mszie) + tree.Traversal(func(k, v interface{}) bool { + result = append(result, v) + return true + }, LDR) + return result +} + +func (tree *vbTree) GetRange(k1, k2 interface{}) (result []interface{}) { + c := tree.Compare(k2, k1) + switch c { + case 1: + + var min, max *Node + resultmin := tree.getArounNode(k1) + resultmax := tree.getArounNode(k2) + for i := 1; i < 3 && min == nil; i++ { + min = resultmin[i] + } + + for i := 1; i > -1 && max == nil; i-- { + max = resultmax[i] + } + + if max == nil { + return []interface{}{} + } + + result = make([]interface{}, 0, 16) + + // iter := NewIterator(min) + tree.iter.SeNode(min) + iter := tree.iter + for iter.Next() { + result = append(result, iter.Value()) + if iter.cur == max { + break + } + } + case -1: + + var min, max *Node + resultmin := tree.getArounNode(k2) + resultmax := tree.getArounNode(k1) + for i := 1; i < 3 && min == nil; i++ { + min = resultmin[i] + } + for i := 1; i > -1 && max == nil; i-- { + max = resultmax[i] + } + + if min == nil { + return []interface{}{} + } + + result = make([]interface{}, 0, 16) + + // iter := NewIterator(max) + tree.iter.SeNode(max) + iter := tree.iter + for iter.Prev() { + result = append(result, iter.Value()) + if iter.cur == min { + break + } + } + case 0: + if n, ok := tree.GetNode(k1); ok { + return []interface{}{n.value} + } + return []interface{}{} + } + + return +} + +func (tree *vbTree) Get(key interface{}) (interface{}, bool) { + n, ok := tree.GetNode(key) + if ok { + return n.value, true + } + return n, false +} + +func (tree *vbTree) GetAround(key interface{}) (result [3]interface{}) { + an := tree.getArounNode(key) + for i, n := range an { + if n != nil { + result[i] = n.value + } + } + return +} + +func (tree *vbTree) getArounNode(key interface{}) (result [3]*Node) { + var last *Node + var lastc int + + for n := tree.root; n != nil; { + last = n + c := tree.Compare(key, n.key) + switch c { + case -1: + n = n.children[0] + lastc = c + case 1: + n = n.children[1] + lastc = c + case 0: + + tree.iter.SeNode(n) + iter := tree.iter + iter.Prev() + for iter.Prev() { + if tree.Compare(iter.cur.key, n.key) == 0 { + n = iter.cur + } else { + break + } + } + result[1] = n + n = nil + default: + panic("Get Compare only is allowed in -1, 0, 1") + } + } + + switch lastc { + case 1: + + if result[1] != nil { + + result[0] = tree.iter.GetPrev(result[1], 1) + result[2] = tree.iter.GetNext(result[1], 1) + } else { + result[0] = last + result[2] = tree.iter.GetNext(last, 1) + } + + case -1: + + if result[1] != nil { + result[0] = tree.iter.GetPrev(result[1], 1) + result[2] = tree.iter.GetNext(result[1], 1) + } else { + result[2] = last + result[0] = tree.iter.GetPrev(last, 1) + } + + case 0: + + if result[1] == nil { + return + } + result[0] = tree.iter.GetPrev(result[1], 1) + result[2] = tree.iter.GetNext(result[1], 1) + } + return +} + +func (tree *vbTree) GetNode(key interface{}) (*Node, 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: + + tree.iter.SeNode(n) + iter := tree.iter + iter.Prev() + for iter.Prev() { + if tree.Compare(iter.cur.key, n.key) == 0 { + n = iter.cur + } else { + break + } + } + return n, true + default: + panic("Get Compare only is allowed in -1, 0, 1") + } + } + return nil, false +} + +func (tree *vbTree) Put(key, value interface{}) { + + Node := &Node{key: key, value: value, size: 1} + if tree.root == nil { + tree.root = Node + tree.top = Node + return + } + + if tree.Compare(key, tree.top.key) > 0 { + tree.top = Node + } + + for cur := tree.root; ; { + + if cur.size > 8 { + factor := cur.size / 10 // or factor = 1 + ls, rs := cur.children[0].size, cur.children[1].size + if rs >= ls*2+factor || ls >= rs*2+factor { + cur = tree.fixSize(cur, ls, rs) + } + } + + cur.size++ + c := tree.Compare(key, cur.key) + if c < 0 { + if cur.children[0] == nil { + cur.children[0] = Node + Node.parent = cur + + if cur.parent != nil && cur.parent.size == 3 { + if cur.parent.children[0] == nil { + tree.lrrotate3(cur.parent) + } else { + tree.rrotate3(cur.parent) + } + } + + return + } + cur = cur.children[0] + } else { + if cur.children[1] == nil { + cur.children[1] = Node + Node.parent = cur + + if cur.parent != nil && cur.parent.size == 3 { + if cur.parent.children[1] == nil { + tree.rlrotate3(cur.parent) + } else { + tree.lrotate3(cur.parent) + } + } + return + } + cur = cur.children[1] + } + } +} + +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 *vbTree) 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 *Node) bool + traverasl = func(cur *Node) 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 *Node) bool + traverasl = func(cur *Node) 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 *Node) bool + traverasl = func(cur *Node) 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 *Node) bool + traverasl = func(cur *Node) 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 *Node) bool + traverasl = func(cur *Node) 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 *Node) bool + traverasl = func(cur *Node) 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 setChildNotNil(cur *Node, cidx int, child *Node) { + cur.children[cidx] = child + cur.children[cidx].parent = cur +} + +func setChild(cur *Node, cidx int, child *Node) { + cur.children[cidx] = child + if child != nil { + cur.children[cidx].parent = cur + } +} + +func (tree *vbTree) replace(old, new *Node) { + + setChild(new, 0, old.children[0]) + setChild(new, 1, old.children[1]) + + if old.parent == nil { + tree.root = new + } else { + if old.parent.children[1] == old { + old.parent.children[1] = new + } else { + old.parent.children[0] = new + } + } + new.size = old.size + new.parent = old.parent +} + +func (tree *vbTree) takeParent(token, person *Node) { + if token.parent == nil { + tree.root = person + } else { + if token.parent.children[1] == token { + token.parent.children[1] = person + } else { + token.parent.children[0] = person + } + } + person.parent = token.parent +} + +func (tree *vbTree) lrrotate3(cur *Node) *Node { + const l = 1 + const r = 0 + + ln := cur.children[l] + cur.children[l] = nil + + lrn := ln.children[r] + ln.children[r] = nil + + tree.takeParent(cur, lrn) + setChildNotNil(lrn, l, ln) + setChildNotNil(lrn, r, cur) + + lrn.size = 3 + lrn.children[l].size = 1 + lrn.children[r].size = 1 + return lrn +} + +func (tree *vbTree) lrrotate(cur *Node) *Node { + + const l = 1 + const r = 0 + + ln := cur.children[l] + lrn := ln.children[r] + + lrln := lrn.children[l] + lrrn := lrn.children[r] + + tree.takeParent(cur, lrn) + + setChild(ln, r, lrln) + setChild(cur, l, lrrn) + + setChildNotNil(lrn, l, ln) + setChildNotNil(lrn, r, cur) + + ln.size = getChildrenSumSize(ln) + 1 + cur.size = getChildrenSumSize(cur) + 1 + lrn.size = getChildrenSumSize(lrn) + 1 + + return lrn +} + +func (tree *vbTree) rlrotate3(cur *Node) *Node { + const l = 0 + const r = 1 + + ln := cur.children[l] + cur.children[l] = nil + + lrn := ln.children[r] + ln.children[r] = nil + + tree.takeParent(cur, lrn) + setChildNotNil(lrn, l, ln) + setChildNotNil(lrn, r, cur) + + lrn.size = 3 + lrn.children[l].size = 1 + lrn.children[r].size = 1 + return lrn +} + +func (tree *vbTree) rlrotate(cur *Node) *Node { + + const l = 0 + const r = 1 + + ln := cur.children[l] + lrn := ln.children[r] + + lrln := lrn.children[l] + lrrn := lrn.children[r] + + tree.takeParent(cur, lrn) + + setChild(ln, r, lrln) + setChild(cur, l, lrrn) + + setChildNotNil(lrn, l, ln) + setChildNotNil(lrn, r, cur) + + ln.size = getChildrenSumSize(ln) + 1 + cur.size = getChildrenSumSize(cur) + 1 + lrn.size = getChildrenSumSize(lrn) + 1 + + return lrn +} + +func (tree *vbTree) rrotate3(cur *Node) *Node { + const l = 0 + const r = 1 + // 1 right 0 left + mov := cur.children[l] + cur.children[l] = nil + + tree.takeParent(cur, mov) + setChildNotNil(mov, r, cur) + + mov.size = 3 + cur.size = 1 + return mov +} + +func (tree *vbTree) rrotate(cur *Node) *Node { + const l = 0 + const r = 1 + // 1 right 0 left + ln := cur.children[l] + lrn := ln.children[r] + + tree.takeParent(cur, ln) + setChild(cur, l, lrn) + setChildNotNil(ln, r, cur) + + cur.size = getChildrenSumSize(cur) + 1 + ln.size = getChildrenSumSize(ln) + 1 + + return ln +} + +func (tree *vbTree) lrotate3(cur *Node) *Node { + const l = 1 + const r = 0 + + // 1 right 0 left + mov := cur.children[l] + cur.children[l] = nil + + tree.takeParent(cur, mov) + setChildNotNil(mov, r, cur) + + mov.size = 3 + cur.size = 1 + return mov +} + +func (tree *vbTree) lrotate(cur *Node) *Node { + + const l = 1 + const r = 0 + + // 1 right 0 left + ln := cur.children[l] + lrn := ln.children[r] + + tree.takeParent(cur, ln) + setChild(cur, l, lrn) + setChildNotNil(ln, r, cur) + + cur.size = getChildrenSumSize(cur) + 1 + ln.size = getChildrenSumSize(ln) + 1 + + return ln +} + +func getChildrenSumSize(cur *Node) int { + return getSize(cur.children[0]) + getSize(cur.children[1]) +} + +func getChildrenSize(cur *Node) (int, int) { + return getSize(cur.children[0]), getSize(cur.children[1]) +} + +func getSize(cur *Node) int { + if cur == nil { + return 0 + } + return cur.size +} + +func (tree *vbTree) fixSizeWithRemove(cur *Node) { + for cur != nil { + cur.size-- + if cur.size > 8 { + factor := cur.size / 10 // or factor = 1 + ls, rs := getChildrenSize(cur) + if rs >= ls*2+factor || ls >= rs*2+factor { + cur = tree.fixSize(cur, ls, rs) + } + } + cur = cur.parent + } +} + +func (tree *vbTree) fixSize(cur *Node, ls, rs int) *Node { + if ls > rs { + llsize, lrsize := getChildrenSize(cur.children[0]) + if lrsize > llsize { + return tree.rlrotate(cur) + } + return tree.rrotate(cur) + + } else { + rlsize, rrsize := getChildrenSize(cur.children[1]) + if rlsize > rrsize { + return tree.lrrotate(cur) + } + return tree.lrotate(cur) + } +} + +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.size) + ")" + *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 *vbTree) debugString() string { + str := "AVLTree\n" + if tree.root == nil { + return str + "nil" + } + outputfordebug(tree.root, "", true, &str) + return str +} diff --git a/priority_queuekey/vbt_test.go b/priority_queuekey/vbt_test.go new file mode 100644 index 0000000..4900584 --- /dev/null +++ b/priority_queuekey/vbt_test.go @@ -0,0 +1,656 @@ +package pqueue + +import ( + "bytes" + "encoding/gob" + "io/ioutil" + "log" + "testing" + + "474420502.top/eson/structure/compare" + "github.com/huandu/skiplist" + + "github.com/Pallinder/go-randomdata" + "github.com/davecgh/go-spew/spew" + "github.com/emirpasic/gods/trees/avltree" + "github.com/emirpasic/gods/trees/redblacktree" +) + +func loadTestData() []int { + data, err := ioutil.ReadFile("../l.log") + if err != nil { + log.Println(err) + } + var l []int + decoder := gob.NewDecoder(bytes.NewReader(data)) + decoder.Decode(&l) + return l +} + +func TestIndexRange(t *testing.T) { + tree := newVBT(compare.Int) + l := []int{7, 14, 14, 14, 16, 17, 20, 30, 21, 40, 50, 3, 40, 40, 40, 15} + for _, v := range l { + tree.Put(v, v) + } + // [3 7 14 14 14 15 16 17 20 21 30 40 40 40 40 50] + // t.Error(tree.Values(), tree.Size()) + + var result string + result = spew.Sprint(tree.IndexRange(0, 5)) + if result != "[50 40 40 40 40 30] true" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(2, 5)) + if result != "[40 40 40 30] true" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(10, 100)) + if result != "[15 14 14 14 7 3] false" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(15, 0)) // size = 16, index max = 15 + if result != "[3 7 14 14 14 15 16 17 20 21 30 40 40 40 40 50] true" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(16, 0)) // size = 16, index max = 15 + if result != "[3 7 14 14 14 15 16 17 20 21 30 40 40 40 40 50] false" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(5, 1)) // size = 16, index max = 15 + if result != "[30 40 40 40 40] true" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(-1, -5)) // size = 16, index max = 15 + if result != "[3 7 14 14 14] true" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(-1, -16)) // size = 16, index max = 0 - 15 (-1,-16) + if result != "[3 7 14 14 14 15 16 17 20 21 30 40 40 40 40 50] true" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(-1, -17)) // size = 16, index max = 0 - 15 (-1,-16) + if result != "[3 7 14 14 14 15 16 17 20 21 30 40 40 40 40 50] false" { + t.Error(result) + } + + result = spew.Sprint(tree.IndexRange(-5, -1)) // size = 16, index max = 0 - 15 (-1,-16) + if result != "[14 14 14 7 3] true" { + t.Error(result) + } +} + +func TestGetAround(t *testing.T) { + tree := newVBT(compare.Int) + for _, v := range []int{7, 14, 14, 14, 16, 17, 20, 30, 21, 40, 50, 3, 40, 40, 40, 15} { + tree.Put(v, v) + } + + var Result string + + Result = spew.Sprint(tree.GetAround(17)) + if Result != "[16 17 20]" { + t.Error(tree.Values()) + t.Error("17 is root, tree.GetAround(17)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(3)) + if Result != "[ 3 7]" { + t.Error(tree.Values()) + t.Error("tree.GetAround(3)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(40)) + if Result != "[30 40 40]" { + t.Error(tree.Values()) + t.Error("tree.GetAround(40)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(50)) + if Result != "[40 50 ]" { + t.Error(tree.Values()) + t.Error("tree.GetAround(50)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(18)) + if Result != "[17 20]" { + t.Error(tree.Values()) + t.Error("18 is not in list, tree.GetAround(18)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(5)) + if Result != "[3 7]" { + t.Error(tree.Values()) + t.Error("5 is not in list, tree.GetAround(5)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(2)) + if Result != "[ 3]" { + t.Error(tree.Values()) + t.Error("2 is not in list, tree.GetAround(2)) is error", Result) + t.Error(tree.debugString()) + } + + Result = spew.Sprint(tree.GetAround(100)) + if Result != "[50 ]" { + t.Error(tree.Values()) + t.Error("50 is not in list, tree.GetAround(50)) is error", Result) + t.Error(tree.debugString()) + } + +} + +// // for test error case + +func TestPutStable(t *testing.T) { + // tree := newVBT(compare.Int) + // for i := 0; i < 40; i++ { + // v := randomdata.Number(0, 100) + // tree.Put(v,v) + + // t.Error(tree.top, v) + // // t.Error(i, v) + // // t.Error(tree.debugString()) + // } + + // for i := 0; i < 40; i++ { + // v, _ := tree.Index(0) + // tree.RemoveIndex(0) + // t.Error(i, v) + // if tree.top != nil { + // t.Error(tree.top) + // } + // } + +} + +func TestPutComparatorRandom(t *testing.T) { + + for n := 0; n < 30000; n++ { + tree := newVBT(compare.Int) + godsavl := avltree.NewWithIntComparator() + + content := "" + m := make(map[int]int) + for i := 0; len(m) < 50; i++ { + v := randomdata.Number(0, 65535) + if _, ok := m[v]; !ok { + m[v] = v + content += spew.Sprint(v) + "," + tree.Put(v, v) + godsavl.Put(v, v) + } + } + + s1 := spew.Sprint(tree.Values()) + s2 := spew.Sprint(godsavl.Values()) + + if s1 != s2 { + t.Error(godsavl.String()) + t.Error(tree.debugString()) + t.Error(content, n) + break + } + } +} + +func TestGet(t *testing.T) { + tree := newVBT(compare.Int) + for _, v := range []int{2383, 7666, 3055, 39016, 57092, 27897, 36513, 1562, 22574, 23202} { + tree.Put(v, v) + } + + for _, v := range []int{2383, 7666, 3055, 39016, 57092, 27897, 36513, 1562, 22574, 23202} { + v, ok := tree.Get(v) + if !ok { + t.Error("the val not found ", v) + } + } + + if v, ok := tree.Get(10000); ok { + t.Error("the val(1000) is not in tree, but is found", v) + } +} + +func TestGetRange(t *testing.T) { + tree := newVBT(compare.Int) + for _, v := range []int{5, 6, 8, 10, 13, 17, 1, 2, 40, 30} { + tree.Put(v, v) + } + + // t.Error(tree.debugString()) + // t.Error(tree.getArountNode(20)) + // t.Error(tree.Values()) + + result := tree.GetRange(0, 20) + if spew.Sprint(result) != "[1 2 5 6 8 10 13 17]" { + t.Error(result) + } + + result = tree.GetRange(-5, -1) + if spew.Sprint(result) != "[]" { + t.Error(result) + } + + result = tree.GetRange(7, 20) + if spew.Sprint(result) != "[8 10 13 17]" { + t.Error(result) + } + + result = tree.GetRange(30, 40) + if spew.Sprint(result) != "[30 40]" { + t.Error(result) + } + + result = tree.GetRange(30, 60) + if spew.Sprint(result) != "[30 40]" { + t.Error(result) + } + + result = tree.GetRange(40, 40) + if spew.Sprint(result) != "[40]" { + t.Error(result) + } + + result = tree.GetRange(50, 60) + if spew.Sprint(result) != "[]" { + t.Error(result) + } + + result = tree.GetRange(50, 1) + if spew.Sprint(result) != "[40 30 17 13 10 8 6 5 2 1]" { + t.Error(result) + } + + result = tree.GetRange(30, 20) + if spew.Sprint(result) != "[30]" { + t.Error(result) + } + +} + +func TestTravalsal(t *testing.T) { + tree := newVBT(compare.Int) + for _, v := range []int{5, 6, 8, 10, 13, 17, 1, 2, 40, 30} { + tree.Put(v, v) + } + + i := 0 + var result []interface{} + tree.Traversal(func(k, v interface{}) bool { + result = append(result, v) + i++ + if i >= 10 { + return false + } + return true + }) + + if spew.Sprint(result) != "[1 2 5 6 8 10 13 17 30 40]" { + t.Error(result) + } + +} + +func TestRemoveAll(t *testing.T) { +ALL: + for c := 0; c < 20000; c++ { + tree := newVBT(compare.Int) + gods := avltree.NewWithIntComparator() + var l []int + m := make(map[int]int) + + for i := 0; len(l) < 50; i++ { + v := randomdata.Number(0, 65535) + if _, ok := m[v]; !ok { + m[v] = v + l = append(l, v) + tree.Put(v, v) + gods.Put(v, v) + } + } + + for i := 0; i < 50; i++ { + tree.Remove(l[i]) + gods.Remove(l[i]) + + s1 := spew.Sprint(tree.Values()) + s2 := spew.Sprint(gods.Values()) + if s1 != s2 { + t.Error("avl remove error", "avlsize = ", tree.Size()) + t.Error(tree.root, i, l[i]) + t.Error(s1) + t.Error(s2) + break ALL + } + } + } +} + +func TestRemove(t *testing.T) { + +ALL: + for N := 0; N < 5000; N++ { + tree := newVBT(compare.Int) + gods := avltree.NewWithIntComparator() + + var l []int + m := make(map[int]int) + + for i := 0; len(l) < 20; i++ { + v := randomdata.Number(0, 100) + if _, ok := m[v]; !ok { + l = append(l, v) + m[v] = v + tree.Put(v, v) + gods.Put(v, v) + } + } + + src1 := tree.String() + src2 := gods.String() + + for i := 0; i < 20; i++ { + tree.Remove(l[i]) + gods.Remove(l[i]) + if tree.root != nil && spew.Sprint(gods.Values()) != spew.Sprint(tree.Values()) { + t.Error(src1) + t.Error(src2) + t.Error(tree.debugString()) + t.Error(gods.String()) + t.Error(l[i]) + break ALL + } + } + } +} + +func BenchmarkSkipListGet(b *testing.B) { + sl := skiplist.New(skiplist.Int) + l := loadTestData() + b.N = len(l) + + for _, v := range l { + sl.Set(v, v) + } + + b.ResetTimer() + b.StartTimer() + + execCount := 5 + b.N = len(l) * execCount + + for i := 0; i < execCount; i++ { + for _, v := range l { + e := sl.Get(v) + var result [50]interface{} + for i := 0; i < 50 && e != nil; i++ { + result[i] = e.Value + e = e.Next() + } + } + } +} + +func BenchmarkGetRange(b *testing.B) { + +} + +func BenchmarkIndexRange(b *testing.B) { + tree := newVBT(compare.Int) + l := loadTestData() + b.N = len(l) + + for _, v := range l { + tree.Put(v, v) + } + + b.ResetTimer() + b.StartTimer() + + execCount := 5 + b.N = len(l) * execCount + + for i := 0; i < execCount; i++ { + for range l { + tree.IndexRange(i, i+49) + } + } +} + +func BenchmarkSkipListSet(b *testing.B) { + + l := loadTestData() + + execCount := 1 + b.N = len(l) * execCount + + for i := 0; i < execCount; i++ { + sl := skiplist.New(skiplist.Int) + for _, v := range l { + sl.Set(v, v) + } + } +} + +func BenchmarkIterator(b *testing.B) { + tree := newVBT(compare.Int) + + l := loadTestData() + b.N = len(l) + + for _, v := range l { + tree.Put(v, v) + } + + b.ResetTimer() + b.StartTimer() + iter := tree.Iterator() + b.N = 0 + for iter.Next() { + b.N++ + } + for iter.Prev() { + b.N++ + } + for iter.Next() { + b.N++ + } + b.Log(b.N, len(l)) +} + +func BenchmarkRemove(b *testing.B) { + tree := newVBT(compare.Int) + + l := loadTestData() + + b.N = len(l) + for _, v := range l { + tree.Put(v, v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < len(l); i++ { + tree.Remove(l[i]) + } +} + +func BenchmarkGodsRemove(b *testing.B) { + tree := avltree.NewWithIntComparator() + + l := loadTestData() + + b.N = len(l) + for _, v := range l { + tree.Put(v, v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < len(l); i++ { + tree.Remove(l[i]) + } +} + +func BenchmarkGodsRBRemove(b *testing.B) { + tree := redblacktree.NewWithIntComparator() + + l := loadTestData() + + b.N = len(l) + for _, v := range l { + tree.Put(v, v) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < len(l); i++ { + tree.Remove(l[i]) + } +} + +func BenchmarkGet(b *testing.B) { + + tree := newVBT(compare.Int) + + l := loadTestData() + b.N = len(l) + for i := 0; i < b.N; i++ { + tree.Put(l[i], l[i]) + } + + b.ResetTimer() + b.StartTimer() + + execCount := 5 + b.N = len(l) * execCount + + for i := 0; i < execCount; i++ { + for _, v := range l { + tree.Get(v) + } + } +} + +func BenchmarkGodsRBGet(b *testing.B) { + tree := redblacktree.NewWithIntComparator() + + l := loadTestData() + b.N = len(l) + for i := 0; i < b.N; i++ { + tree.Put(l[i], i) + } + + b.ResetTimer() + b.StartTimer() + + execCount := 10 + b.N = len(l) * execCount + + for i := 0; i < execCount; i++ { + for _, v := range l { + tree.Get(v) + } + } +} + +func BenchmarkGodsAvlGet(b *testing.B) { + tree := avltree.NewWithIntComparator() + + l := loadTestData() + b.N = len(l) + for i := 0; i < b.N; i++ { + tree.Put(l[i], i) + } + + b.ResetTimer() + b.StartTimer() + + execCount := 10 + b.N = len(l) * execCount + + for i := 0; i < execCount; i++ { + for _, v := range l { + tree.Get(v) + } + } +} + +func BenchmarkPut(b *testing.B) { + l := loadTestData() + + b.ResetTimer() + b.StartTimer() + + execCount := 50 + b.N = len(l) * execCount + for i := 0; i < execCount; i++ { + tree := newVBT(compare.Int) + for _, v := range l { + tree.Put(v, v) + } + } +} + +func BenchmarkIndex(b *testing.B) { + tree := newVBT(compare.Int) + + l := loadTestData() + b.N = len(l) + for i := 0; i < b.N; i++ { + tree.Put(l[i], l[i]) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + tree.Index(i) + } +} + +func BenchmarkGodsRBPut(b *testing.B) { + tree := redblacktree.NewWithIntComparator() + + l := loadTestData() + + b.ResetTimer() + b.StartTimer() + + b.N = len(l) + for _, v := range l { + tree.Put(v, v) + } +} + +func BenchmarkGodsPut(b *testing.B) { + tree := avltree.NewWithIntComparator() + + l := loadTestData() + + b.ResetTimer() + b.StartTimer() + + b.N = len(l) + for _, v := range l { + tree.Put(v, v) + } +}