├── .gitignore ├── History.md ├── LICENSE ├── Readme.md └── stree ├── multi ├── mtree.go └── mtree_test.go ├── serial.go ├── stree.go └── stree_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .directory 3 | .npmignore 4 | *.sublime* -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.1.0 / 25.04.2012 3 | ================== 4 | 5 | * initial release 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Thomas Oberndörfer. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Thomas Oberndörfer nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # go-stree 2 | 3 | go-stree is a package for Go that can be used to process a large number of intervals. 4 | The main purpose of this module is to solve the following problem: given a set of intervals, how to find all overlapping intervals at a certain point or within a certain range. 5 | 6 | It offers three different algorithms: 7 | - **stree**: implemented as segment tree 8 | - **serial**: simple sequential algorithm, mainly for testing purposes 9 | - **mtree**: implemented as segment tree with parallel processing 10 | 11 | All three algorithms implement the following interface: 12 | ```go 13 | // Main interface to access tree 14 | type Tree interface { 15 | // Push new interval to stack 16 | Push(from, to int) 17 | // Push array of intervals to stack 18 | PushArray(from, to []int) 19 | // Clear the interval stack 20 | Clear() 21 | // Build segment tree out of interval stack 22 | BuildTree() 23 | // Print tree recursively to stdout 24 | Print() 25 | // Transform tree to array 26 | Tree2Array() []SegmentOverlap 27 | // Query interval 28 | Query(from, to int) []Interval 29 | // Query interval array 30 | QueryArray(from, to []int) []Interval 31 | } 32 | ``` 33 | 34 | ## Installation 35 | 36 | go get github.com/toberndo/go-stree/stree 37 | 38 | ## Example 39 | 40 | ```go 41 | import ( 42 | "fmt" 43 | "github.com/toberndo/go-stree/stree" 44 | ) 45 | 46 | func main() { 47 | tree := stree.NewTree() 48 | tree.Push(1, 1) 49 | tree.Push(2, 3) 50 | tree.Push(5, 7) 51 | tree.Push(4, 6) 52 | tree.Push(6, 9) 53 | tree.BuildTree() 54 | fmt.Println(tree.Query(3, 5)) 55 | } 56 | ``` 57 | 58 | The serial algorithm resides in the same package: 59 | 60 | ```go 61 | import ( 62 | "github.com/toberndo/go-stree/stree" 63 | ) 64 | 65 | func main() { 66 | serial := stree.NewSerial() 67 | } 68 | ``` 69 | 70 | A parallel version of the segment tree is in the sub package *multi*: 71 | 72 | ```go 73 | import ( 74 | "github.com/toberndo/go-stree/stree/multi" 75 | ) 76 | 77 | func main() { 78 | mtree := multi.NewMTree() 79 | } 80 | ``` 81 | 82 | ## Segment tree 83 | 84 | A [segment tree](http://en.wikipedia.org/wiki/Segment_tree) is a data structure that can be used to run range queries on large sets of intervals. This is for example required to analyze data of gene sequences. 85 | The usage is as in the example above: we build a new tree object, push intervals to the data structure, build the tree and can then run certain queries on the tree. The segment tree is a static structure which means we cannot add further intervals once the tree is built. Rebuilding the tree is then required. 86 | 87 | ![segment tree example](http://assets.yarkon.de/images/Segment_tree_instance.gif) 88 | 89 | ## Serial 90 | 91 | The sequential algorithm simply traverses the array of intervals to search for overlaps. It builds up a dynamic structure where intervals can be added at any time. The interface is equal to the segment tree, but tree specific methods like BuildTree(), Print() and Tree2Array() are not supported. 92 | 93 | ## API 94 | 95 | See http://go.pkgdoc.org/github.com/toberndo/go-stree 96 | 97 | ## Performance 98 | 99 | To test performance execute the following command in directories **stree** and **multi**: 100 | 101 | go test -test.bench "." -test.cpu 4 102 | 103 | As a short summary: the performance depends highly on the quality of the test data. Parallelism does not always improve performance, in some scenarios the stree algorithm is faster. In the optimal case mtree version with parallel support performs 20% better on a dual core machine than single threaded stree version. 104 | A detailed analysis can be found in this article: http://www.chasinclouds.com/2012/05/building-segment-trees-with-go.html 105 | 106 | ## Licence 107 | 108 | Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 109 | 110 | ## About 111 | 112 | written by Thomas Oberndörfer 113 | Blog: http://www.chasinclouds.com/ 114 | follow me on [Twitter](https://twitter.com/#!/toberndo) -------------------------------------------------------------------------------- /stree/multi/mtree.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Thomas Oberndörfer. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package implements a segment tree that uses parallel 6 | // processing with multiple concurrent goroutines 7 | package multi 8 | 9 | import ( 10 | . "github.com/toberndo/go-stree/stree" 11 | "math" 12 | "runtime" 13 | "sync" 14 | ) 15 | 16 | const ( 17 | // number of goroutines = 2 ** P_LEVEL 18 | P_LEVEL = 6 // 64 goroutines 19 | ) 20 | 21 | // number of goroutines for tree walker 22 | var NUM_WORKER int = runtime.NumCPU() * 2 23 | 24 | type mtree struct { 25 | // Number of intervals 26 | count int 27 | root *mnode 28 | // Interval stack 29 | base []Interval 30 | // Min value of all intervals 31 | min int 32 | // Max value of all intervals 33 | max int 34 | // channel to signal goroutine is done 35 | done chan bool 36 | // channel to limit number of running goroutines 37 | sem chan int 38 | // max number of goroutines used 39 | numG int 40 | // fallback to single processing if low number of intervals 41 | single bool 42 | } 43 | 44 | type mnode struct { 45 | // A segment is a interval represented by the node 46 | segment Segment 47 | left, right *mnode 48 | // All intervals that overlap with segment 49 | overlap []*Interval 50 | // lock node for concurrent write access 51 | lock sync.Mutex 52 | } 53 | 54 | func (n *mnode) Segment() Segment { 55 | return n.segment 56 | } 57 | 58 | func (n *mnode) Left() Node { 59 | return n.left 60 | } 61 | 62 | func (n *mnode) Right() Node { 63 | return n.right 64 | } 65 | 66 | // Overlap transforms []*Interval to []Interval 67 | func (n *mnode) Overlap() []Interval { 68 | if n.overlap == nil { 69 | return nil 70 | } 71 | interval := make([]Interval, len(n.overlap)) 72 | for i, pintrvl := range n.overlap { 73 | interval[i] = *pintrvl 74 | } 75 | return interval 76 | } 77 | 78 | // NewMTree returns a Tree interface with underlying parallel segment tree implementation 79 | func NewMTree() Tree { 80 | t := new(mtree) 81 | t.Clear() 82 | return t 83 | } 84 | 85 | // Push new interval to stack 86 | func (t *mtree) Push(from, to int) { 87 | t.base = append(t.base, Interval{t.count, Segment{from, to}}) 88 | t.count++ 89 | } 90 | 91 | // Push array of intervals to stack 92 | func (t *mtree) PushArray(from, to []int) { 93 | for i := 0; i < len(from); i++ { 94 | t.Push(from[i], to[i]) 95 | } 96 | } 97 | 98 | // Clear the interval stack 99 | func (t *mtree) Clear() { 100 | t.count = 0 101 | t.root = nil 102 | t.base = make([]Interval, 0, 100) 103 | t.min = 0 104 | t.max = 0 105 | // max number of goroutines = 2 ** P_LEVEL 106 | t.numG = int(math.Pow(2, P_LEVEL)) 107 | // buffered channels 108 | t.done = make(chan bool, t.numG) 109 | t.sem = make(chan int, t.numG) 110 | // default: parallel processing 111 | t.single = false 112 | } 113 | 114 | // Build segment tree out of interval stack 115 | func (t *mtree) BuildTree() { 116 | if len(t.base) == 0 { 117 | panic("No intervals in stack to build tree. Push intervals first") 118 | } 119 | var endpoint []int 120 | // attempts to parallelize the creation of endpoint array 121 | // only showed decrease in performance 122 | endpoint, t.min, t.max = Endpoints(t.base) 123 | // number of endpoints must be at least 10 times higher than number of 124 | // goroutines to justify effort and avoid locking situation 125 | if len(endpoint) < t.numG*10 { 126 | t.single = true 127 | } 128 | // create tree nodes from interval endpoints, uses goroutines if t.single == false 129 | t.root = t.insertNodes(endpoint, 0) 130 | if !t.single { 131 | // wait for goroutines to finish 132 | t.wait() 133 | // insert intervals using multi processing 134 | t.insertIntervalM() 135 | } else { 136 | // fall back for single processing 137 | for i := range t.base { 138 | t.insertInterval(t.root, &t.base[i]) 139 | } 140 | } 141 | } 142 | 143 | func (t *mtree) wait() { 144 | for i := 0; i < t.numG; i++ { 145 | <-t.done 146 | } 147 | } 148 | 149 | func (t *mtree) Print() { 150 | Print(t.root) 151 | } 152 | 153 | func (t *mtree) Tree2Array() []SegmentOverlap { 154 | return Tree2Array(t.root) 155 | } 156 | 157 | // insertNodes builds tree structure from given endpoints 158 | // starts with single processing, at P_LEVEL level of tree the children 159 | // are created in seperate goroutines 160 | func (t *mtree) insertNodes(endpoint []int, level int) *mnode { 161 | var n *mnode 162 | //fmt.Printf("Level: %d\n", level) 163 | if len(endpoint) == 1 { 164 | n = &mnode{segment: Segment{endpoint[0], endpoint[0]}} 165 | n.left = nil 166 | n.right = nil 167 | } else if len(endpoint) == 2 { 168 | n = &mnode{segment: Segment{endpoint[0], endpoint[1]}} 169 | if endpoint[1] != t.max { 170 | n.left = &mnode{segment: Segment{endpoint[0], endpoint[0]}} 171 | n.right = &mnode{segment: Segment{endpoint[1], endpoint[1]}} 172 | } 173 | } else { 174 | n = &mnode{segment: Segment{endpoint[0], endpoint[len(endpoint)-1]}} 175 | center := len(endpoint) / 2 176 | level++ 177 | if level == P_LEVEL && !t.single { 178 | t.insertNodesAsync(&n.left, endpoint[:center+1], level) 179 | t.insertNodesAsync(&n.right, endpoint[center+1:], level) 180 | } else { 181 | n.left = t.insertNodes(endpoint[:center+1], level) 182 | n.right = t.insertNodes(endpoint[center+1:], level) 183 | } 184 | } 185 | return n 186 | } 187 | 188 | // insertNodesAsync starts new goroutine for creation of tree branch 189 | func (t *mtree) insertNodesAsync(ppNode **mnode, endpoint []int, level int) { 190 | go func() { 191 | *ppNode = t.insertNodes(endpoint, level) 192 | t.done <- true 193 | }() 194 | } 195 | 196 | // Insert intervals with multiple goroutines 197 | func (t *mtree) insertIntervalM() { 198 | for i := range t.base { 199 | // create new goroutines as long as space in buffer 200 | t.sem <- 1 201 | go func(index int) { 202 | t.insertInterval(t.root, &t.base[index]) 203 | // release one entry in buffer when goroutine finishes 204 | <-t.sem 205 | }(i) 206 | } 207 | // wait for running goroutines to finish 208 | for i := 0; i < t.numG; i++ { 209 | t.sem <- 1 210 | } 211 | } 212 | 213 | // Inserts interval into given tree structure, write access locked 214 | func (t *mtree) insertInterval(node *mnode, intrvl *Interval) { 215 | switch node.segment.CompareTo(&intrvl.Segment) { 216 | case SUBSET: 217 | node.lock.Lock() 218 | // interval of node is a subset of the specified interval or equal 219 | if node.overlap == nil { 220 | node.overlap = make([]*Interval, 0, 10) 221 | } 222 | node.overlap = append(node.overlap, intrvl) 223 | node.lock.Unlock() 224 | case INTERSECT_OR_SUPERSET: 225 | // interval of node is a superset, have to look in both children 226 | if node.left != nil { 227 | t.insertInterval(node.left, intrvl) 228 | } 229 | if node.right != nil { 230 | t.insertInterval(node.right, intrvl) 231 | } 232 | case DISJOINT: 233 | // nothing to do 234 | } 235 | } 236 | 237 | // A tree walker for querying intervals 238 | type twalker struct { 239 | // number of goroutines 240 | num int 241 | // wait until goroutines are finished 242 | wait *sync.WaitGroup 243 | // queue where each buffer entry represents an available goroutine 244 | queue chan byte 245 | // result map of intervals 246 | result chan *map[int]Interval 247 | } 248 | 249 | // init with max number of goroutines 250 | func (t *twalker) init(num int) { 251 | t.num = num 252 | t.wait = new(sync.WaitGroup) 253 | t.queue = make(chan byte, num) 254 | t.result = make(chan *map[int]Interval, num) 255 | } 256 | 257 | // collect results from goroutines 258 | func (t *twalker) collect(result *map[int]Interval) { 259 | // wait for all to finish 260 | t.wait.Wait() 261 | for i := 0; i < t.num; i++ { 262 | // the number of started goroutines might be lower than the max number of goroutines 263 | // therefore this construct to break out if t.result is empty 264 | select { 265 | case rmap := <-t.result: 266 | for key, value := range *rmap { 267 | (*result)[key] = value 268 | } 269 | default: 270 | break 271 | } 272 | } 273 | } 274 | 275 | // Query interval with parallel tree walker 276 | func (t *mtree) Query(from, to int) []Interval { 277 | if t.root == nil { 278 | panic("Can't run query on empty tree. Call BuildTree() first") 279 | } 280 | result := make(map[int]Interval) 281 | tw := new(twalker) 282 | tw.init(NUM_WORKER) 283 | querySingle(t.root, from, to, &result, tw, false) 284 | tw.collect(&result) 285 | sl := make([]Interval, 0, len(result)) 286 | for _, intrvl := range result { 287 | sl = append(sl, intrvl) 288 | } 289 | return sl 290 | } 291 | 292 | // querySingle traverses tree in parallel to search for overlaps 293 | func querySingle(node *mnode, from, to int, result *map[int]Interval, tw *twalker, back bool) { 294 | if !node.segment.Disjoint(from, to) { 295 | for _, pintrvl := range node.overlap { 296 | (*result)[pintrvl.Id] = *pintrvl 297 | } 298 | if node.right != nil { 299 | // buffered channel tw.queue is a safe counter to limit number of started goroutines 300 | select { 301 | case tw.queue <- 1: 302 | // create new map for result 303 | newMap := make(map[int]Interval) 304 | // increment counter of wait group 305 | tw.wait.Add(1) 306 | // start new query in goroutine 307 | go querySingle(node.right, from, to, &newMap, tw, true) 308 | default: 309 | // pass-through result map of parent 310 | querySingle(node.right, from, to, result, tw, false) 311 | } 312 | } 313 | if node.left != nil { 314 | select { 315 | case tw.queue <- 1: 316 | newMap := make(map[int]Interval) 317 | tw.wait.Add(1) 318 | go querySingle(node.left, from, to, &newMap, tw, true) 319 | default: 320 | querySingle(node.left, from, to, result, tw, false) 321 | } 322 | } 323 | } 324 | // if back is true then this method was called with go 325 | if back { 326 | // pass the result in the channel 327 | tw.result <- result 328 | // let wait group know that we are done 329 | tw.wait.Done() 330 | } 331 | } 332 | 333 | // Query interval array in parallel 334 | func (t *mtree) QueryArray(from, to []int) []Interval { 335 | if t.root == nil { 336 | panic("Can't run query on empty tree. Call BuildTree() first") 337 | } 338 | result := make(map[int]Interval) 339 | tw := new(twalker) 340 | tw.init(NUM_WORKER) 341 | queryMulti(t.root, from, to, &result, tw, false) 342 | tw.collect(&result) 343 | sl := make([]Interval, 0, len(result)) 344 | for _, intrvl := range result { 345 | sl = append(sl, intrvl) 346 | } 347 | return sl 348 | } 349 | 350 | // queryMulti traverses tree parallel in search of overlaps with multiple intervals 351 | func queryMulti(node *mnode, from, to []int, result *map[int]Interval, tw *twalker, back bool) { 352 | hitsFrom := make([]int, 0, 2) 353 | hitsTo := make([]int, 0, 2) 354 | for i, fromvalue := range from { 355 | if !node.segment.Disjoint(fromvalue, to[i]) { 356 | for _, pintrvl := range node.overlap { 357 | (*result)[pintrvl.Id] = *pintrvl 358 | } 359 | hitsFrom = append(hitsFrom, fromvalue) 360 | hitsTo = append(hitsTo, to[i]) 361 | } 362 | } 363 | // search in children only with overlapping intervals of parent 364 | if len(hitsFrom) != 0 { 365 | if node.right != nil { 366 | // buffered channel tw.queue is a safe counter to limit number of started goroutines 367 | select { 368 | case tw.queue <- 1: 369 | // create new map for result 370 | newMap := make(map[int]Interval) 371 | // increment counter of wait group 372 | tw.wait.Add(1) 373 | // start new query in goroutine 374 | go queryMulti(node.right, from, to, &newMap, tw, true) 375 | default: 376 | // pass-through result map of parent 377 | queryMulti(node.right, from, to, result, tw, false) 378 | } 379 | } 380 | if node.left != nil { 381 | select { 382 | case tw.queue <- 1: 383 | newMap := make(map[int]Interval) 384 | tw.wait.Add(1) 385 | go queryMulti(node.left, from, to, &newMap, tw, true) 386 | default: 387 | queryMulti(node.left, from, to, result, tw, false) 388 | } 389 | } 390 | } 391 | // if back is true then this method was called with go 392 | if back { 393 | // pass the result in the channel 394 | tw.result <- result 395 | // let wait group know that we are done 396 | tw.wait.Done() 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /stree/multi/mtree_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Thomas Oberndörfer. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package multi 6 | 7 | import ( 8 | "fmt" 9 | . "github.com/toberndo/go-stree/stree" 10 | "math" 11 | "math/rand" 12 | "testing" 13 | ) 14 | 15 | func TestTreeEqualMTree(t *testing.T) { 16 | tree := NewTree() 17 | mtree := NewMTree() 18 | for i := 0; i < 1000; i++ { 19 | min := rand.Int() 20 | max := rand.Int() 21 | if min > max { 22 | min, max = max, min 23 | } 24 | tree.Push(min, max) 25 | mtree.Push(min, max) 26 | } 27 | tree.BuildTree() 28 | mtree.BuildTree() 29 | tSegArray := tree.Tree2Array() 30 | mSegArray := mtree.Tree2Array() 31 | fail := false 32 | if len(tSegArray) != len(mSegArray) { 33 | fail = true 34 | fmt.Printf("unequal array length") 35 | goto Fail 36 | } 37 | outer: 38 | for i, seg := range tSegArray { 39 | mseg := mSegArray[i] 40 | if seg.Segment != mseg.Segment { 41 | fail = true 42 | fmt.Printf("unequal segment") 43 | break 44 | } 45 | 46 | if len(seg.Interval) != len(mseg.Interval) { 47 | fail = true 48 | fmt.Printf("unequal interval len\n") 49 | fmt.Println(len(seg.Interval)) 50 | fmt.Println(len(mseg.Interval)) 51 | break 52 | } 53 | for _, intrvl := range seg.Interval { 54 | count := 0 55 | for _, mintrvl := range mseg.Interval { 56 | if intrvl == mintrvl { 57 | count++ 58 | } 59 | } 60 | if count != 1 { 61 | fail = true 62 | fmt.Printf("unequal count\n") 63 | break outer 64 | } 65 | } 66 | } 67 | Fail: 68 | if fail { 69 | t.Errorf("Trees not equal") 70 | } 71 | 72 | } 73 | 74 | func TestMinimalTree(t *testing.T) { 75 | tree := NewMTree() 76 | tree.Push(3, 7) 77 | tree.BuildTree() 78 | fail := false 79 | result := tree.Query(1, 2) 80 | if len(result) != 0 { 81 | fail = true 82 | } 83 | result = tree.Query(2, 3) 84 | if len(result) != 1 { 85 | fail = true 86 | } 87 | if fail { 88 | t.Errorf("fail query minimal tree") 89 | } 90 | } 91 | 92 | func TestMinimalTree2(t *testing.T) { 93 | tree := NewTree() 94 | tree.Push(1, 1) 95 | tree.BuildTree() 96 | if result := tree.Query(1, 1); len(result) != 1 { 97 | t.Errorf("fail query minimal tree for (1, 1)") 98 | } 99 | if result := tree.Query(1, 2); len(result) != 1 { 100 | t.Errorf("fail query minimal tree for (1, 2)") 101 | } 102 | if result := tree.Query(2, 3); len(result) != 0 { 103 | t.Errorf("fail query minimal tree for (2, 3)") 104 | } 105 | } 106 | 107 | func TestNormalTree(t *testing.T) { 108 | tree := NewTree() 109 | tree.Push(1, 1) 110 | tree.Push(2, 3) 111 | tree.Push(5, 7) 112 | tree.Push(4, 6) 113 | tree.Push(6, 9) 114 | tree.BuildTree() 115 | if result := tree.Query(3, 5); len(result) != 3 { 116 | t.Errorf("fail query multiple tree for (3, 5)") 117 | } 118 | qvalid := map[int]int{ 119 | 0: 0, 120 | 1: 1, 121 | 2: 1, 122 | 3: 1, 123 | 4: 1, 124 | 5: 2, 125 | 6: 3, 126 | 7: 2, 127 | 8: 1, 128 | 9: 1, 129 | } 130 | for i := 0; i <= 9; i++ { 131 | if result := tree.Query(i, i); len(result) != qvalid[i] { 132 | t.Errorf("fail query multiple tree for (%d, %d)", i, i) 133 | } 134 | } 135 | } 136 | 137 | func BenchmarkSimple(b *testing.B) { 138 | for i := 0; i < b.N; i++ { 139 | tree := NewMTree() 140 | tree.Push(1, 1) 141 | tree.Push(2, 3) 142 | tree.Push(5, 7) 143 | tree.Push(4, 6) 144 | tree.Push(6, 9) 145 | tree.Push(9, 14) 146 | tree.Push(10, 13) 147 | tree.Push(11, 11) 148 | tree.BuildTree() 149 | } 150 | } 151 | 152 | func BenchmarkBuildTree100000(b *testing.B) { 153 | tree := NewTree() 154 | buildTree(b, tree, 100000) 155 | } 156 | 157 | func BenchmarkBuildMulti100000(b *testing.B) { 158 | tree := NewMTree() 159 | buildTree(b, tree, 100000) 160 | } 161 | 162 | func buildTree(b *testing.B, tree Tree, count int) { 163 | for i := 0; i < b.N; i++ { 164 | b.StopTimer() 165 | tree.Clear() 166 | pushRandom(tree, count) 167 | b.StartTimer() 168 | tree.BuildTree() 169 | } 170 | } 171 | 172 | func pushRandom(tree Tree, count int) { 173 | for j := 0; j < count; j++ { 174 | min := rand.Int() 175 | max := rand.Int() 176 | if min > max { 177 | min, max = max, min 178 | } 179 | tree.Push(min, max) 180 | } 181 | } 182 | 183 | func BenchmarkInsertNodesMulti100000(b *testing.B) { 184 | for i := 0; i < b.N; i++ { 185 | b.StopTimer() 186 | tree := NewMTree().(*mtree) 187 | pushRandom(tree, 100000) 188 | var endpoint []int 189 | endpoint, tree.min, tree.max = Endpoints(tree.base) 190 | b.StartTimer() 191 | tree.root = tree.insertNodes(endpoint, 0) 192 | for i := 0; i < tree.numG; i++ { 193 | <-tree.done 194 | } 195 | } 196 | } 197 | 198 | func BenchmarkInsertIntervalsMulti100000(b *testing.B) { 199 | for i := 0; i < b.N; i++ { 200 | b.StopTimer() 201 | tree := NewMTree().(*mtree) 202 | pushRandom(tree, 100000) 203 | var endpoint []int 204 | endpoint, tree.min, tree.max = Endpoints(tree.base) 205 | tree.root = tree.insertNodes(endpoint, 0) 206 | for i := 0; i < tree.numG; i++ { 207 | <-tree.done 208 | } 209 | b.StartTimer() 210 | tree.insertIntervalM() 211 | } 212 | } 213 | 214 | var tree Tree 215 | var multi Tree 216 | 217 | func init() { 218 | tree = NewTree() 219 | multi = NewMTree() 220 | for j := 0; j < 100000; j++ { 221 | min := rand.Int() 222 | max := rand.Int() 223 | if min > max { 224 | min, max = max, min 225 | } 226 | tree.Push(min, max) 227 | multi.Push(min, max) 228 | } 229 | tree.BuildTree() 230 | multi.BuildTree() 231 | } 232 | 233 | func BenchmarkQueryTree(b *testing.B) { 234 | for i := 0; i < b.N; i++ { 235 | tree.Query(0, 100000) 236 | } 237 | } 238 | 239 | func BenchmarkQueryMulti(b *testing.B) { 240 | for i := 0; i < b.N; i++ { 241 | multi.Query(0, 100000) 242 | } 243 | } 244 | 245 | func BenchmarkQueryTreeMax(b *testing.B) { 246 | for i := 0; i < b.N; i++ { 247 | tree.Query(0, math.MaxInt32) 248 | } 249 | } 250 | 251 | func BenchmarkQueryMulitMax(b *testing.B) { 252 | for i := 0; i < b.N; i++ { 253 | multi.Query(0, math.MaxInt32) 254 | } 255 | } 256 | 257 | func BenchmarkQueryArray(b *testing.B) { 258 | for i := 0; i < b.N; i++ { 259 | tree.QueryArray([]int{0, 100000000, 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000}, 260 | []int{50000000, 150000000, 250000000, 350000000, 450000000, 550000000, 650000000, 750000000, 850000000, 950000000}) 261 | } 262 | } 263 | 264 | func BenchmarkQueryArrayMulti(b *testing.B) { 265 | for i := 0; i < b.N; i++ { 266 | multi.QueryArray([]int{0, 100000000, 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000}, 267 | []int{50000000, 150000000, 250000000, 350000000, 450000000, 550000000, 650000000, 750000000, 850000000, 950000000}) 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /stree/serial.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Thomas Oberndörfer. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package stree 6 | 7 | // serial is a structure that allows to query intervals 8 | // with a sequential algorithm 9 | type serial struct { 10 | stree 11 | } 12 | 13 | // NewSerial returns a Tree interface with underlying serial algorithm 14 | func NewSerial() Tree { 15 | t := new(serial) 16 | t.Clear() 17 | return t 18 | } 19 | 20 | func (t *serial) BuildTree() { 21 | panic("BuildTree() not supported for serial data structure") 22 | } 23 | 24 | func (t *serial) Print() { 25 | panic("Print() not supported for serial data structure") 26 | } 27 | 28 | func (t *serial) Tree2Array() []SegmentOverlap { 29 | panic("Tree2Array() not supported for serial data structure") 30 | } 31 | 32 | // Query interval by looping through the interval stack 33 | func (t *serial) Query(from, to int) []Interval { 34 | result := make([]Interval, 0, 10) 35 | for _, intrvl := range t.base { 36 | if !intrvl.Segment.Disjoint(from, to) { 37 | result = append(result, intrvl) 38 | } 39 | } 40 | return result 41 | } 42 | 43 | // Query interval array by looping through the interval stack 44 | func (t *serial) QueryArray(from, to []int) []Interval { 45 | result := make([]Interval, 0, 10) 46 | for i, fromvalue := range from { 47 | result = append(result, t.Query(fromvalue, to[i])...) 48 | } 49 | return result 50 | } 51 | -------------------------------------------------------------------------------- /stree/stree.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Thomas Oberndörfer. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package implements a segment tree and serial algorithm to query intervals 6 | package stree 7 | 8 | import ( 9 | "fmt" 10 | "reflect" 11 | "sort" 12 | ) 13 | 14 | // Main interface to access tree 15 | type Tree interface { 16 | // Push new interval to stack 17 | Push(from, to int) 18 | // Push array of intervals to stack 19 | PushArray(from, to []int) 20 | // Clear the interval stack 21 | Clear() 22 | // Build segment tree out of interval stack 23 | BuildTree() 24 | // Print tree recursively to stdout 25 | Print() 26 | // Transform tree to array 27 | Tree2Array() []SegmentOverlap 28 | // Query interval 29 | Query(from, to int) []Interval 30 | // Query interval array 31 | QueryArray(from, to []int) []Interval 32 | } 33 | 34 | type stree struct { 35 | // Number of intervals 36 | count int 37 | root *node 38 | // Interval stack 39 | base []Interval 40 | // Min value of all intervals 41 | min int 42 | // Max value of all intervals 43 | max int 44 | } 45 | 46 | // Interface to provide unified access to nodes 47 | type Node interface { 48 | Segment() Segment 49 | Left() Node 50 | Right() Node 51 | Overlap() []Interval 52 | } 53 | 54 | type node struct { 55 | // A segment is a interval represented by the node 56 | segment Segment 57 | left, right *node 58 | // All intervals that overlap with segment 59 | overlap []*Interval 60 | } 61 | 62 | func (n *node) Segment() Segment { 63 | return n.segment 64 | } 65 | 66 | func (n *node) Left() Node { 67 | return n.left 68 | } 69 | 70 | func (n *node) Right() Node { 71 | return n.right 72 | } 73 | 74 | // Overlap transforms []*Interval to []Interval 75 | func (n *node) Overlap() []Interval { 76 | if n.overlap == nil { 77 | return nil 78 | } 79 | interval := make([]Interval, len(n.overlap)) 80 | for i, pintrvl := range n.overlap { 81 | interval[i] = *pintrvl 82 | } 83 | return interval 84 | } 85 | 86 | type Interval struct { 87 | Id int // unique 88 | Segment 89 | } 90 | 91 | type Segment struct { 92 | From int 93 | To int 94 | } 95 | 96 | // Represents overlapping intervals of a segment 97 | type SegmentOverlap struct { 98 | Segment Segment 99 | Interval []Interval 100 | } 101 | 102 | // Node receiver for tree traversal 103 | type NodeReceive func(Node) 104 | 105 | const ( 106 | // Relations of two intervals 107 | SUBSET = iota 108 | DISJOINT 109 | INTERSECT_OR_SUPERSET 110 | ) 111 | 112 | // NewTree returns a Tree interface with underlying segment tree implementation 113 | func NewTree() Tree { 114 | t := new(stree) 115 | t.Clear() 116 | return t 117 | } 118 | 119 | // Push new interval to stack 120 | func (t *stree) Push(from, to int) { 121 | t.base = append(t.base, Interval{t.count, Segment{from, to}}) 122 | t.count++ 123 | } 124 | 125 | // Push array of intervals to stack 126 | func (t *stree) PushArray(from, to []int) { 127 | for i := 0; i < len(from); i++ { 128 | t.Push(from[i], to[i]) 129 | } 130 | } 131 | 132 | // Clear the interval stack 133 | func (t *stree) Clear() { 134 | t.count = 0 135 | t.root = nil 136 | t.base = make([]Interval, 0, 100) 137 | t.min = 0 138 | t.max = 0 139 | } 140 | 141 | // Build segment tree out of interval stack 142 | func (t *stree) BuildTree() { 143 | if len(t.base) == 0 { 144 | panic("No intervals in stack to build tree. Push intervals first") 145 | } 146 | var endpoint []int 147 | endpoint, t.min, t.max = Endpoints(t.base) 148 | // Create tree nodes from interval endpoints 149 | t.root = t.insertNodes(endpoint) 150 | for i := range t.base { 151 | insertInterval(t.root, &t.base[i]) 152 | } 153 | } 154 | 155 | func (t *stree) Print() { 156 | Print(t.root) 157 | } 158 | 159 | func (t *stree) Tree2Array() []SegmentOverlap { 160 | return Tree2Array(t.root) 161 | } 162 | 163 | // Endpoints returns a slice with all endpoints (sorted, unique) 164 | func Endpoints(base []Interval) (result []int, min, max int) { 165 | baseLen := len(base) 166 | endpoints := make([]int, baseLen*2) 167 | for i, interval := range base { 168 | endpoints[i] = interval.From 169 | endpoints[i+baseLen] = interval.To 170 | } 171 | result = Dedup(endpoints) 172 | min = result[0] 173 | max = result[len(result)-1] 174 | return 175 | } 176 | 177 | // Dedup removes duplicates from a given slice 178 | func Dedup(sl []int) []int { 179 | sort.Sort(sort.IntSlice(sl)) 180 | unique := make([]int, 0, len(sl)) 181 | prev := sl[0] + 1 182 | for _, val := range sl { 183 | if val != prev { 184 | unique = append(unique, val) 185 | prev = val 186 | } 187 | } 188 | return unique 189 | } 190 | 191 | // insertNodes builds tree structure from given endpoints 192 | func (t *stree) insertNodes(endpoint []int) *node { 193 | var n *node 194 | if len(endpoint) == 1 { 195 | n = &node{segment: Segment{endpoint[0], endpoint[0]}} 196 | n.left = nil 197 | n.right = nil 198 | } else { 199 | n = &node{segment: Segment{endpoint[0], endpoint[len(endpoint)-1]}} 200 | center := len(endpoint) / 2 201 | n.left = t.insertNodes(endpoint[:center]) 202 | n.right = t.insertNodes(endpoint[center:]) 203 | } 204 | return n 205 | } 206 | 207 | // CompareTo compares two Segments and returns: DISJOINT, SUBSET or INTERSECT_OR_SUPERSET 208 | func (s *Segment) CompareTo(other *Segment) int { 209 | if other.From > s.To || other.To < s.From { 210 | return DISJOINT 211 | } 212 | if other.From <= s.From && other.To >= s.To { 213 | return SUBSET 214 | } 215 | return INTERSECT_OR_SUPERSET 216 | } 217 | 218 | // Disjoint returns true if Segment does not overlap with interval 219 | func (s *Segment) Disjoint(from, to int) bool { 220 | if from > s.To || to < s.From { 221 | return true 222 | } 223 | return false 224 | } 225 | 226 | // Inserts interval into given tree structure 227 | func insertInterval(node *node, intrvl *Interval) { 228 | switch node.segment.CompareTo(&intrvl.Segment) { 229 | case SUBSET: 230 | // interval of node is a subset of the specified interval or equal 231 | if node.overlap == nil { 232 | node.overlap = make([]*Interval, 0, 10) 233 | } 234 | node.overlap = append(node.overlap, intrvl) 235 | case INTERSECT_OR_SUPERSET: 236 | // interval of node is a superset, have to look in both children 237 | if node.left != nil { 238 | insertInterval(node.left, intrvl) 239 | } 240 | if node.right != nil { 241 | insertInterval(node.right, intrvl) 242 | } 243 | case DISJOINT: 244 | // nothing to do 245 | } 246 | } 247 | 248 | // Query interval 249 | func (t *stree) Query(from, to int) []Interval { 250 | if t.root == nil { 251 | panic("Can't run query on empty tree. Call BuildTree() first") 252 | } 253 | result := make(map[int]Interval) 254 | querySingle(t.root, from, to, &result) 255 | // transform map to slice 256 | sl := make([]Interval, 0, len(result)) 257 | for _, intrvl := range result { 258 | sl = append(sl, intrvl) 259 | } 260 | return sl 261 | } 262 | 263 | // querySingle traverse tree in search of overlaps 264 | func querySingle(node *node, from, to int, result *map[int]Interval) { 265 | if !node.segment.Disjoint(from, to) { 266 | for _, pintrvl := range node.overlap { 267 | (*result)[pintrvl.Id] = *pintrvl 268 | } 269 | if node.right != nil { 270 | querySingle(node.right, from, to, result) 271 | } 272 | if node.left != nil { 273 | querySingle(node.left, from, to, result) 274 | } 275 | } 276 | } 277 | 278 | // Query interval array 279 | func (t *stree) QueryArray(from, to []int) []Interval { 280 | if t.root == nil { 281 | panic("Can't run query on empty tree. Call BuildTree() first") 282 | } 283 | result := make(map[int]Interval) 284 | queryMulti(t.root, from, to, &result) 285 | sl := make([]Interval, 0, len(result)) 286 | for _, intrvl := range result { 287 | sl = append(sl, intrvl) 288 | } 289 | return sl 290 | } 291 | 292 | // queryMulti traverse tree in search of overlaps with multiple intervals 293 | func queryMulti(node *node, from, to []int, result *map[int]Interval) { 294 | hitsFrom := make([]int, 0, 2) 295 | hitsTo := make([]int, 0, 2) 296 | for i, fromvalue := range from { 297 | if !node.segment.Disjoint(fromvalue, to[i]) { 298 | for _, pintrvl := range node.overlap { 299 | (*result)[pintrvl.Id] = *pintrvl 300 | } 301 | hitsFrom = append(hitsFrom, fromvalue) 302 | hitsTo = append(hitsTo, to[i]) 303 | } 304 | } 305 | // search in children only with overlapping intervals of parent 306 | if len(hitsFrom) != 0 { 307 | if node.right != nil { 308 | queryMulti(node.right, hitsFrom, hitsTo, result) 309 | } 310 | if node.left != nil { 311 | queryMulti(node.left, hitsFrom, hitsTo, result) 312 | } 313 | } 314 | } 315 | 316 | // Traverse tree recursively call enter when entering node, resp. leave 317 | func traverse(node Node, enter, leave NodeReceive) { 318 | if reflect.ValueOf(node).IsNil() { 319 | return 320 | } 321 | if enter != nil { 322 | enter(node) 323 | } 324 | traverse(node.Right(), enter, leave) 325 | traverse(node.Left(), enter, leave) 326 | if leave != nil { 327 | leave(node) 328 | } 329 | } 330 | 331 | // Print tree recursively to sdout 332 | func Print(root Node) { 333 | traverse(root, func(node Node) { 334 | fmt.Printf("\nSegment: (%d,%d)", node.Segment().From, node.Segment().To) 335 | for _, intrvl := range node.Overlap() { 336 | fmt.Printf("\nInterval %d: (%d,%d)", intrvl.Id, intrvl.From, intrvl.To) 337 | } 338 | }, nil) 339 | } 340 | 341 | // Tree2Array transforms tree to array 342 | func Tree2Array(root Node) []SegmentOverlap { 343 | array := make([]SegmentOverlap, 0, 50) 344 | traverse(root, func(node Node) { 345 | seg := SegmentOverlap{Segment: node.Segment(), Interval: node.Overlap()} 346 | array = append(array, seg) 347 | }, nil) 348 | return array 349 | } 350 | -------------------------------------------------------------------------------- /stree/stree_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Thomas Oberndörfer. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package stree 6 | 7 | import ( 8 | "fmt" 9 | "math" 10 | "math/rand" 11 | "testing" 12 | ) 13 | 14 | func TestTreeEqualSerial(t *testing.T) { 15 | tree := NewTree() 16 | serial := NewSerial() 17 | for i := 0; i < 100000; i++ { 18 | min := rand.Int() 19 | max := rand.Int() 20 | if min > max { 21 | min, max = max, min 22 | } 23 | tree.Push(min, max) 24 | serial.Push(min, max) 25 | } 26 | tree.BuildTree() 27 | treeresult := tree.Query(0, 1000000) 28 | //fmt.Println(treeresult) 29 | serialresult := serial.Query(0, 1000000) 30 | //fmt.Println(serialresult) 31 | treemap := make(map[int]Segment) 32 | fail := false 33 | if len(treeresult) != len(serialresult) { 34 | fail = true 35 | fmt.Printf("unequal result length") 36 | goto Fail 37 | } 38 | for _, value := range treeresult { 39 | treemap[value.Id] = value.Segment 40 | } 41 | for _, intrvl := range serialresult { 42 | if treemap[intrvl.Id] != intrvl.Segment { 43 | fail = true 44 | fmt.Printf("result interval mismatch") 45 | break 46 | } 47 | } 48 | Fail: 49 | if fail { 50 | t.Errorf("Result not equal") 51 | } 52 | } 53 | 54 | func TestMinimalTree(t *testing.T) { 55 | tree := NewTree() 56 | tree.Push(3, 7) 57 | tree.BuildTree() 58 | fail := false 59 | result := tree.Query(1, 2) 60 | if len(result) != 0 { 61 | fail = true 62 | } 63 | result = tree.Query(2, 3) 64 | if len(result) != 1 { 65 | fail = true 66 | } 67 | if fail { 68 | t.Errorf("fail query minimal tree") 69 | } 70 | } 71 | 72 | func TestMinimalTree2(t *testing.T) { 73 | tree := NewTree() 74 | tree.Push(1, 1) 75 | tree.BuildTree() 76 | if result := tree.Query(1, 1); len(result) != 1 { 77 | t.Errorf("fail query minimal tree for (1, 1)") 78 | } 79 | if result := tree.Query(1, 2); len(result) != 1 { 80 | t.Errorf("fail query minimal tree for (1, 2)") 81 | } 82 | if result := tree.Query(2, 3); len(result) != 0 { 83 | t.Errorf("fail query minimal tree for (2, 3)") 84 | } 85 | } 86 | 87 | func TestNormalTree(t *testing.T) { 88 | tree := NewTree() 89 | tree.Push(1, 1) 90 | tree.Push(2, 3) 91 | tree.Push(5, 7) 92 | tree.Push(4, 6) 93 | tree.Push(6, 9) 94 | tree.BuildTree() 95 | if result := tree.Query(3, 5); len(result) != 3 { 96 | t.Errorf("fail query multiple tree for (3, 5)") 97 | } 98 | qvalid := map[int]int{ 99 | 0: 0, 100 | 1: 1, 101 | 2: 1, 102 | 3: 1, 103 | 4: 1, 104 | 5: 2, 105 | 6: 3, 106 | 7: 2, 107 | 8: 1, 108 | 9: 1, 109 | } 110 | for i := 0; i <= 9; i++ { 111 | if result := tree.Query(i, i); len(result) != qvalid[i] { 112 | t.Errorf("fail query multiple tree for (%d, %d)", i, i) 113 | } 114 | } 115 | } 116 | 117 | func BenchmarkSimple(b *testing.B) { 118 | for i := 0; i < b.N; i++ { 119 | tree := NewTree() 120 | tree.Push(1, 1) 121 | tree.Push(2, 3) 122 | tree.Push(5, 7) 123 | tree.Push(4, 6) 124 | tree.Push(6, 9) 125 | tree.Push(9, 14) 126 | tree.Push(10, 13) 127 | tree.Push(11, 11) 128 | tree.BuildTree() 129 | } 130 | } 131 | 132 | var tree Tree 133 | var ser Tree 134 | 135 | func init() { 136 | tree = NewTree() 137 | ser = NewSerial() 138 | for j := 0; j < 100000; j++ { 139 | min := rand.Int() 140 | max := rand.Int() 141 | if min > max { 142 | min, max = max, min 143 | } 144 | tree.Push(min, max) 145 | ser.Push(min, max) 146 | } 147 | tree.BuildTree() 148 | } 149 | 150 | func BenchmarkBuildTree1000(b *testing.B) { 151 | tree := NewTree() 152 | buildTree(b, tree, 1000) 153 | } 154 | 155 | func BenchmarkBuildTree100000(b *testing.B) { 156 | tree := NewTree() 157 | buildTree(b, tree, 100000) 158 | } 159 | 160 | func BenchmarkQueryTree(b *testing.B) { 161 | for i := 0; i < b.N; i++ { 162 | tree.Query(0, 100000) 163 | } 164 | } 165 | 166 | func BenchmarkQuerySerial(b *testing.B) { 167 | for i := 0; i < b.N; i++ { 168 | ser.Query(0, 100000) 169 | } 170 | } 171 | 172 | func BenchmarkQueryTreeMax(b *testing.B) { 173 | for i := 0; i < b.N; i++ { 174 | tree.Query(0, math.MaxInt32) 175 | } 176 | } 177 | 178 | func BenchmarkQuerySerialMax(b *testing.B) { 179 | for i := 0; i < b.N; i++ { 180 | ser.Query(0, math.MaxInt32) 181 | } 182 | } 183 | 184 | func BenchmarkQueryTreeArray(b *testing.B) { 185 | from := []int{0, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000} 186 | to := []int{10, 1000010, 2000010, 3000010, 4000010, 5000010, 6000010, 7000010, 8000010, 9000010} 187 | for i := 0; i < b.N; i++ { 188 | tree.QueryArray(from, to) 189 | } 190 | } 191 | 192 | func BenchmarkQuerySerialArray(b *testing.B) { 193 | from := []int{0, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000} 194 | to := []int{10, 1000010, 2000010, 3000010, 4000010, 5000010, 6000010, 7000010, 8000010, 9000010} 195 | for i := 0; i < b.N; i++ { 196 | ser.QueryArray(from, to) 197 | } 198 | } 199 | 200 | func buildTree(b *testing.B, tree Tree, count int) { 201 | for i := 0; i < b.N; i++ { 202 | b.StopTimer() 203 | tree.Clear() 204 | pushRandom(tree, count) 205 | b.StartTimer() 206 | tree.BuildTree() 207 | } 208 | } 209 | 210 | func pushRandom(tree Tree, count int) { 211 | for j := 0; j < count; j++ { 212 | min := rand.Int() 213 | max := rand.Int() 214 | if min > max { 215 | min, max = max, min 216 | } 217 | tree.Push(min, max) 218 | } 219 | } 220 | 221 | func BenchmarkEndpoints100000(b *testing.B) { 222 | for i := 0; i < b.N; i++ { 223 | b.StopTimer() 224 | tree := NewTree().(*stree) 225 | pushRandom(tree, 100000) 226 | b.StartTimer() 227 | Endpoints(tree.base) 228 | } 229 | } 230 | 231 | func BenchmarkInsertNodes100000(b *testing.B) { 232 | for i := 0; i < b.N; i++ { 233 | b.StopTimer() 234 | tree := NewTree().(*stree) 235 | pushRandom(tree, 100000) 236 | var endpoint []int 237 | endpoint, tree.min, tree.max = Endpoints(tree.base) 238 | //fmt.Println(len(endpoint)) 239 | b.StartTimer() 240 | tree.root = tree.insertNodes(endpoint) 241 | } 242 | } 243 | 244 | func BenchmarkInsertIntervals100000(b *testing.B) { 245 | for i := 0; i < b.N; i++ { 246 | b.StopTimer() 247 | tree := NewTree().(*stree) 248 | pushRandom(tree, 100000) 249 | var endpoint []int 250 | endpoint, tree.min, tree.max = Endpoints(tree.base) 251 | tree.root = tree.insertNodes(endpoint) 252 | b.StartTimer() 253 | for i := range tree.base { 254 | insertInterval(tree.root, &tree.base[i]) 255 | } 256 | } 257 | } 258 | --------------------------------------------------------------------------------