实现 PriorityQueue Test Benchmark

This commit is contained in:
eson 2019-04-08 02:11:37 +08:00
parent 09dbba1a88
commit 9e2bdb12dd
9 changed files with 289 additions and 166 deletions

View File

@ -324,13 +324,13 @@ func TestGet(t *testing.T) {
func TestRemoveAll(t *testing.T) { func TestRemoveAll(t *testing.T) {
ALL: ALL:
for c := 0; c < 5000; c++ { for c := 0; c < 50000; c++ {
tree := New(compare.Int) tree := New(compare.Int)
gods := avltree.NewWithIntComparator() gods := avltree.NewWithIntComparator()
var l []int var l []int
m := make(map[int]int) m := make(map[int]int)
for i := 0; len(l) < 100; i++ { for i := 0; len(l) < 50; i++ {
v := randomdata.Number(0, 100000) v := randomdata.Number(0, 100000)
if _, ok := m[v]; !ok { if _, ok := m[v]; !ok {
m[v] = v m[v] = v
@ -340,7 +340,7 @@ ALL:
} }
} }
for i := 0; i < 100; i++ { for i := 0; i < 50; i++ {
tree.Remove(l[i]) tree.Remove(l[i])
gods.Remove(l[i]) gods.Remove(l[i])
s1 := spew.Sprint(tree.Values()) s1 := spew.Sprint(tree.Values())

View File

@ -6,7 +6,6 @@ import (
type PriorityQueue struct { type PriorityQueue struct {
queue *vbTree queue *vbTree
head *tNode
} }
func (pq *PriorityQueue) Iterator() *Iterator { func (pq *PriorityQueue) Iterator() *Iterator {
@ -22,33 +21,41 @@ func (pq *PriorityQueue) Size() int {
} }
func (pq *PriorityQueue) Push(value interface{}) { func (pq *PriorityQueue) Push(value interface{}) {
pq.queue.Put(value)
} }
func (pq *PriorityQueue) Top() (result interface{}, ok bool) { func (pq *PriorityQueue) Top() (result interface{}, ok bool) {
if pq.head != nil { if pq.queue.top != nil {
return pq.head.value, true return pq.queue.top.value, true
} }
return nil, false return nil, false
} }
func (pq *PriorityQueue) Pop() (result interface{}, ok bool) { 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 return nil, false
} }
func (pq *PriorityQueue) Get(idx int) (interface{}, bool) { func (pq *PriorityQueue) Index(idx int) (interface{}, bool) {
return nil, false return pq.queue.Index(idx)
} }
func (pq *PriorityQueue) RemoveWithIndex(idx int) { func (pq *PriorityQueue) Get(key interface{}) (interface{}, bool) {
return pq.queue.Get(key)
} }
func (pq *PriorityQueue) Remove(key interface{}) { func (pq *PriorityQueue) RemoveWithIndex(idx int) bool {
return pq.queue.RemoveIndex(idx)
}
func (pq *PriorityQueue) Remove(key interface{}) bool {
return pq.queue.Remove(key)
} }
func (pq *PriorityQueue) Values() []interface{} { func (pq *PriorityQueue) Values() []interface{} {
return nil return pq.queue.Values()
} }

View File

@ -3,35 +3,178 @@ package pqueue
import ( import (
"testing" "testing"
"github.com/Pallinder/go-randomdata"
"474420502.top/eson/structure/compare" "474420502.top/eson/structure/compare"
) )
func TestPush(t *testing.T) { func TestQueuePush(t *testing.T) {
pq := New(compare.Int) pq := New(compare.Int)
for i := 0; i < 10; i++ { for _, v := range []int{32, 10, 53, 78, 90, 1, 4} {
v := randomdata.Number(0, 100)
pq.Push(v) pq.Push(v)
if v, ok := pq.Top(); ok {
} else {
t.Error(v) t.Error(v)
} }
t.Error(pq.Pop()) }
t.Error(pq.Pop())
t.Error(pq.Pop()) if v, ok := pq.Top(); ok {
t.Error(pq.Pop()) if v != 90 {
t.Error(pq.Pop()) t.Error(v)
}
} else {
t.Error(v)
}
} }
func TestPop(t *testing.T) { func TestQueuePop(t *testing.T) {
pq := New(compare.Int) pq := New(compare.Int)
for i := 0; i < 10; i++ { for _, v := range []int{32, 10, 53, 78, 90, 1, 4} {
v := randomdata.Number(0, 100)
pq.Push(v) pq.Push(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)
}
if v, ok := pq.Get(0); ok {
t.Error(v) t.Error(v)
} }
for i := 0; i < 10; i++ { if v, ok := pq.Get(70); ok {
t.Error(pq.Pop()) 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 TestQueueIndex(t *testing.T) {
pq := New(compare.Int)
for _, v := range []int{32, 10, 53, 78, 90, 1, 4} {
pq.Push(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)
}
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 BenchmarkQueueIndex(b *testing.B) {
l := loadTestData()
pq := New(compare.Int)
for _, v := range l {
pq.Push(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
}
}
} }
} }
@ -61,7 +204,7 @@ func BenchmarkPriorityPop(b *testing.B) {
pq.Push(v) pq.Push(v)
} }
b.N = len(l) / 1000 b.N = len(l)
b.ResetTimer() b.ResetTimer()
b.StartTimer() b.StartTimer()

View File

@ -60,19 +60,6 @@ func (tree *vbTree) Size() int {
func (tree *vbTree) indexNode(idx int) *tNode { func (tree *vbTree) indexNode(idx int) *tNode {
cur := tree.root cur := tree.root
if idx >= 0 { if idx >= 0 {
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]
}
}
} else {
idx = -idx - 1
for cur != nil { for cur != nil {
rs := getSize(cur.children[1]) rs := getSize(cur.children[1])
if idx == rs { if idx == rs {
@ -84,6 +71,19 @@ func (tree *vbTree) indexNode(idx int) *tNode {
cur = cur.children[0] 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 return nil
} }
@ -166,10 +166,15 @@ func (tree *vbTree) RemoveIndex(idx int) bool {
func (tree *vbTree) removeNode(n *tNode) { func (tree *vbTree) removeNode(n *tNode) {
if tree.root.size == 1 { if tree.root.size == 1 {
tree.root = nil tree.root = nil
tree.top = nil
// return n // return n
return return
} }
if tree.top == n {
tree.top = tree.iter.GetPrev(n, 1)
}
ls, rs := getChildrenSize(n) ls, rs := getChildrenSize(n)
if ls == 0 && rs == 0 { if ls == 0 && rs == 0 {
p := n.parent p := n.parent
@ -208,11 +213,12 @@ func (tree *vbTree) removeNode(n *tNode) {
cparent := cur.parent cparent := cur.parent
// 修改为interface 交换 // 修改为interface 交换
n.value, cur.value = cur.value, n.value // n.value, cur.value = cur.value, n.value
tree.replace(n, cur)
// 考虑到刚好替换的节点是 被替换节点的孩子节点的时候, 从自身修复高度 // 考虑到刚好替换的节点是 被替换节点的孩子节点的时候, 从自身修复高度
if cparent == n { if cparent == n {
tree.fixSizeWithRemove(n) tree.fixSizeWithRemove(cur)
} else { } else {
tree.fixSizeWithRemove(cparent) tree.fixSizeWithRemove(cparent)
} }
@ -431,15 +437,21 @@ func (tree *vbTree) Put(key interface{}) {
tNode := &tNode{value: key, size: 1} tNode := &tNode{value: key, size: 1}
if tree.root == nil { if tree.root == nil {
tree.root = tNode tree.root = tNode
tree.top = tNode
return return
} }
if tree.Compare(key, tree.top.value) > 0 {
tree.top = tNode
}
for cur := tree.root; ; { for cur := tree.root; ; {
if cur.size > 8 { if cur.size > 8 {
factor := cur.size / 10 // or factor = 1 factor := cur.size / 10 // or factor = 1
if cur.children[1].size >= cur.children[0].size*2+factor || cur.children[0].size >= cur.children[1].size*2+factor { ls, rs := cur.children[0].size, cur.children[1].size
cur = tree.fixSize(cur) if rs >= ls*2+factor || ls >= rs*2+factor {
cur = tree.fixSize(cur, ls, rs)
} }
} }
@ -457,6 +469,7 @@ func (tree *vbTree) Put(key interface{}) {
tree.rrotate3(cur.parent) tree.rrotate3(cur.parent)
} }
} }
return return
} }
cur = cur.children[0] cur = cur.children[0]
@ -636,6 +649,24 @@ func setChild(cur *tNode, cidx int, child *tNode) {
} }
} }
func (tree *vbTree) replace(old, new *tNode) {
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 *tNode) { func (tree *vbTree) takeParent(token, person *tNode) {
if token.parent == nil { if token.parent == nil {
tree.root = person tree.root = person
@ -739,55 +770,6 @@ func (tree *vbTree) rlrotate(cur *tNode) *tNode {
lrn.size = getChildrenSumSize(lrn) + 1 lrn.size = getChildrenSumSize(lrn) + 1
return lrn return lrn
// movparent := cur.children[l]
// mov := movparent.children[r]
// mov.value, cur.value = cur.value, mov.value //交换值达到, 相对位移
// 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
// movparent.size = getChildrenSumSize(movparent) + 1
// mov.size = getChildrenSumSize(mov) + 1
// cur.size = getChildrenSumSize(cur) + 1
}
func (tree *vbTree) replace(old, new *tNode) {
new.children[0] = old.children[0]
new.children[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
}
}
} }
func (tree *vbTree) rrotate3(cur *tNode) *tNode { func (tree *vbTree) rrotate3(cur *tNode) *tNode {
@ -877,16 +859,17 @@ func (tree *vbTree) fixSizeWithRemove(cur *tNode) {
cur.size-- cur.size--
if cur.size > 8 { if cur.size > 8 {
factor := cur.size / 10 // or factor = 1 factor := cur.size / 10 // or factor = 1
if cur.children[1].size >= cur.children[0].size*2+factor || cur.children[0].size >= cur.children[1].size*2+factor { ls, rs := getChildrenSize(cur)
cur = tree.fixSize(cur) if rs >= ls*2+factor || ls >= rs*2+factor {
cur = tree.fixSize(cur, ls, rs)
} }
} }
cur = cur.parent cur = cur.parent
} }
} }
func (tree *vbTree) fixSize(cur *tNode) *tNode { func (tree *vbTree) fixSize(cur *tNode, ls, rs int) *tNode {
if cur.children[0].size > cur.children[1].size { if ls > rs {
llsize, lrsize := getChildrenSize(cur.children[0]) llsize, lrsize := getChildrenSize(cur.children[0])
if lrsize > llsize { if lrsize > llsize {
return tree.rlrotate(cur) return tree.rlrotate(cur)

View File

@ -194,15 +194,26 @@ func TestPutStable(t *testing.T) {
for i := 0; i < 40; i++ { for i := 0; i < 40; i++ {
v := randomdata.Number(0, 100) v := randomdata.Number(0, 100)
tree.Put(v) tree.Put(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) t.Error(i, v)
t.Error(tree.debugString()) if tree.top != nil {
t.Error(tree.top)
}
} }
} }
func TestPutComparatorRandom(t *testing.T) { func TestPutComparatorRandom(t *testing.T) {
for n := 0; n < 50000; n++ { for n := 0; n < 30000; n++ {
tree := newVBT(compare.Int) tree := newVBT(compare.Int)
godsavl := avltree.NewWithIntComparator() godsavl := avltree.NewWithIntComparator()
@ -330,7 +341,7 @@ func TestTravalsal(t *testing.T) {
func TestRemoveAll(t *testing.T) { func TestRemoveAll(t *testing.T) {
ALL: ALL:
for c := 0; c < 10000; c++ { for c := 0; c < 20000; c++ {
tree := newVBT(compare.Int) tree := newVBT(compare.Int)
gods := avltree.NewWithIntComparator() gods := avltree.NewWithIntComparator()
var l []int var l []int
@ -353,12 +364,10 @@ ALL:
s1 := spew.Sprint(tree.Values()) s1 := spew.Sprint(tree.Values())
s2 := spew.Sprint(gods.Values()) s2 := spew.Sprint(gods.Values())
if s1 != s2 { if s1 != s2 {
// t.Error("avl remove error", "avlsize = ", tree.Size()) t.Error("avl remove error", "avlsize = ", tree.Size())
// t.Error(beforce) t.Error(tree.root, i, l[i])
// t.Error(after) t.Error(s1)
// t.Error(tree.root, i, l[i]) t.Error(s2)
// t.Error(s1)
// t.Error(s2)
break ALL break ALL
} }
} }

View File

@ -436,8 +436,9 @@ func (tree *Tree) Put(key interface{}) {
if cur.size > 8 { if cur.size > 8 {
factor := cur.size / 10 // or factor = 1 factor := cur.size / 10 // or factor = 1
if cur.children[1].size >= cur.children[0].size*2+factor || cur.children[0].size >= cur.children[1].size*2+factor { ls, rs := cur.children[0].size, cur.children[1].size
tree.fixSize(cur) if rs >= ls*2+factor || ls >= rs*2+factor {
tree.fixSize(cur, ls, rs)
} }
} }
@ -866,16 +867,17 @@ func (tree *Tree) fixSizeWithRemove(cur *Node) {
cur.size-- cur.size--
if cur.size > 8 { if cur.size > 8 {
factor := cur.size / 10 // or factor = 1 factor := cur.size / 10 // or factor = 1
if cur.children[1].size >= cur.children[0].size*2+factor || cur.children[0].size >= cur.children[1].size*2+factor { ls, rs := getChildrenSize(cur)
tree.fixSize(cur) if rs >= ls*2+factor || ls >= rs*2+factor {
tree.fixSize(cur, ls, rs)
} }
} }
cur = cur.parent cur = cur.parent
} }
} }
func (tree *Tree) fixSize(cur *Node) { func (tree *Tree) fixSize(cur *Node, ls, rs int) {
if cur.children[0].size > cur.children[1].size { if ls > rs {
llsize, lrsize := getChildrenSize(cur.children[0]) llsize, lrsize := getChildrenSize(cur.children[0])
if lrsize > llsize { if lrsize > llsize {
tree.rlrotate(cur) tree.rlrotate(cur)

View File

@ -319,13 +319,13 @@ func TestTravalsal(t *testing.T) {
func TestRemoveAll(t *testing.T) { func TestRemoveAll(t *testing.T) {
ALL: ALL:
for c := 0; c < 5000; c++ { for c := 0; c < 10000; c++ {
tree := New(compare.Int) tree := New(compare.Int)
gods := avltree.NewWithIntComparator() gods := avltree.NewWithIntComparator()
var l []int var l []int
m := make(map[int]int) m := make(map[int]int)
for i := 0; len(l) < 20; i++ { for i := 0; len(l) < 100; i++ {
v := randomdata.Number(0, 100000) v := randomdata.Number(0, 100000)
if _, ok := m[v]; !ok { if _, ok := m[v]; !ok {
m[v] = v m[v] = v
@ -335,7 +335,7 @@ ALL:
} }
} }
for i := 0; i < 20; i++ { for i := 0; i < 100; i++ {
tree.Remove(l[i]) tree.Remove(l[i])
gods.Remove(l[i]) gods.Remove(l[i])
@ -391,6 +391,23 @@ ALL:
} }
} }
func BenchmarkSkipRemove(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()
for _, v := range l {
sl.Remove(v)
}
}
func BenchmarkSkipListGet(b *testing.B) { func BenchmarkSkipListGet(b *testing.B) {
sl := skiplist.New(skiplist.Int) sl := skiplist.New(skiplist.Int)
l := loadTestData() l := loadTestData()

View File

@ -433,8 +433,9 @@ func (tree *Tree) Put(key, value interface{}) {
if cur.size > 8 { if cur.size > 8 {
factor := cur.size / 10 // or factor = 1 factor := cur.size / 10 // or factor = 1
if cur.children[1].size >= cur.children[0].size*2+factor || cur.children[0].size >= cur.children[1].size*2+factor { ls, rs := cur.children[0].size, cur.children[1].size
tree.fixSize(cur) if rs >= ls*2+factor || ls >= rs*2+factor {
tree.fixSize(cur, ls, rs)
} }
} }
@ -870,56 +871,17 @@ func (tree *Tree) fixSizeWithRemove(cur *Node) {
cur.size-- cur.size--
if cur.size > 8 { if cur.size > 8 {
factor := cur.size / 10 // or factor = 1 factor := cur.size / 10 // or factor = 1
if cur.children[1].size >= cur.children[0].size*2+factor || cur.children[0].size >= cur.children[1].size*2+factor { ls, rs := getChildrenSize(cur)
tree.fixSize(cur) if rs >= ls*2+factor || ls >= rs*2+factor {
tree.fixSize(cur, ls, rs)
} }
} }
cur = cur.parent cur = cur.parent
} }
} }
func (tree *Tree) fix3Size(cur *Node, lefts, rigths int) { func (tree *Tree) fixSize(cur *Node, ls, rs int) {
if lefts > rigths { if ls > rs {
l := cur.children[0]
llsize, lrsize := getChildrenSize(l)
if lrsize > llsize {
tree.rlrotate3(cur)
} else {
tree.rrotate3(cur)
}
} else {
r := cur.children[1]
rlsize, rrsize := getChildrenSize(r)
if rlsize > rrsize {
tree.lrrotate3(cur)
} else {
tree.lrotate3(cur)
}
}
}
func (tree *Tree) fix6Size(cur *Node, lefts, rigths int) {
if lefts > rigths {
l := cur.children[0]
llsize, lrsize := getChildrenSize(l)
if lrsize > llsize {
tree.rlrotate(cur)
} else {
tree.rrotate(cur)
}
} else {
r := cur.children[1]
rlsize, rrsize := getChildrenSize(r)
if rlsize > rrsize {
tree.lrrotate(cur)
} else {
tree.lrotate(cur)
}
}
}
func (tree *Tree) fixSize(cur *Node) {
if cur.children[0].size > cur.children[1].size {
llsize, lrsize := getChildrenSize(cur.children[0]) llsize, lrsize := getChildrenSize(cur.children[0])
if lrsize > llsize { if lrsize > llsize {
tree.rlrotate(cur) tree.rlrotate(cur)

View File

@ -325,7 +325,7 @@ ALL:
var l []int var l []int
m := make(map[int]int) m := make(map[int]int)
for i := 0; len(l) < 20; i++ { for i := 0; len(l) < 50; i++ {
v := randomdata.Number(0, 100000) v := randomdata.Number(0, 100000)
if _, ok := m[v]; !ok { if _, ok := m[v]; !ok {
m[v] = v m[v] = v
@ -335,7 +335,7 @@ ALL:
} }
} }
for i := 0; i < 20; i++ { for i := 0; i < 50; i++ {
tree.Remove(l[i]) tree.Remove(l[i])
gods.Remove(l[i]) gods.Remove(l[i])