From 4030bb1f1f0c35b30ca7009e9ebd06849dd45306 Mon Sep 17 00:00:00 2001 From: ShuNing Date: Mon, 13 Aug 2018 23:31:12 +0800 Subject: [PATCH] Improve the iterate seek to O(logN) (#25) * improve the iterate seek to O(logN) * add benchmark --- btree.go | 21 +++++++++++++++------ btree_test.go | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/btree.go b/btree.go index 7e4551d..6ff062f 100644 --- a/btree.go +++ b/btree.go @@ -500,13 +500,14 @@ const ( // thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a // "greaterThan" or "lessThan" queries. func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit bool, iter ItemIterator) (bool, bool) { - var ok bool + var ok, found bool + var index int switch dir { case ascend: - for i := 0; i < len(n.items); i++ { - if start != nil && n.items[i].Less(start) { - continue - } + if start != nil { + index, _ = n.items.find(start) + } + for i := index; i < len(n.items); i++ { if len(n.children) > 0 { if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok { return hit, false @@ -530,7 +531,15 @@ func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit b } } case descend: - for i := len(n.items) - 1; i >= 0; i-- { + if start != nil { + index, found = n.items.find(start) + if !found { + index = index - 1 + } + } else { + index = len(n.items) - 1 + } + for i := index; i >= 0; i-- { if start != nil && !n.items[i].Less(start) { if !includeStart || hit || start.Less(n.items[i]) { continue diff --git a/btree_test.go b/btree_test.go index 9eeb136..78a90cd 100644 --- a/btree_test.go +++ b/btree_test.go @@ -361,6 +361,21 @@ func BenchmarkInsert(b *testing.B) { } } +func BenchmarkSeek(b *testing.B) { + b.StopTimer() + size := 100000 + insertP := perm(size) + tr := New(*btreeDegree) + for _, item := range insertP { + tr.ReplaceOrInsert(item) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + tr.AscendGreaterOrEqual(Int(i%size), func(i Item) bool { return false }) + } +} + func BenchmarkDeleteInsert(b *testing.B) { b.StopTimer() insertP := perm(benchmarkTreeSize)