Skip to content

ideahitme/segment

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Segment Tree

Build Status Coverage Status Go Report Card

Basic implementation of segment tree in Go

Read more about segment tree: https://en.wikipedia.org/wiki/Segment_tree

All operations (see below) are O(log(n)) where n is the size of the array on which queries are performed.

Basic Usage

package main

import "github.com/ideahitme/segment"

func main() {
	tree, err := segment.NewTree([]int{1,2,3,4,5}, segment.MinFunc{})
	if err != nil { 
		//handle error, only happens when empty slice is passed
	}

	// minimum value in range [0:4]
	fmt.Println(tree.RQ(0, 4)) // 1, <nil>

	// increase values in range [1:4] by -5
	err := tree.Add(-5, 1, 4)
	if err != nil { 
		//handle error, only happens when ranges are incorrect
	}

	// so now we have array of [1, -3, -2, -1, 0]
	fmt.Println(tree.RQ(0, 2)) // -3, <nil>
}

NOTE: Slice passed to the tree is internally copied, therefore can be safely modified

API

NewTree(x []int, TreeFunc)

	import "github.com/ideahitme/segment" 

	...

	// supports range minimum queries
	minTree, _ := segment.NewTree([]int{124,123, 1, -10000, 412}, segment.MinFunc{})
	// supports range maximum queries
	maxTree, _ := segment.NewTree([]int{124,123, 1, -10000, 412}, segment.MaxFunc{})

RQ(l, r): range queries on range [l:r]

	x := []int{1, 20, 3, 40, 5, 60, 7, -100} // our original array
	tree, _ := segment.NewTree(x, segment.MaxFunc{}) // segment tree which supports Range Maximum Queries

	fmt.Println(tree.RQ(0, 0))
	fmt.Println(tree.RQ(0, 3))
	fmt.Println(tree.RQ(3, 5))
	fmt.Println(tree.RQ(6, 7))
	fmt.Println(tree.RQ(7, 7))

	//Output:
	//1 <nil>
	//40 <nil>
	//60 <nil>
	//7 <nil>
	//-100 <nil>

Add(x, l, r): add value x to all numbers in range [l:r]

	x := []int{1, 20, 3, 40, 5, 60, 7, -100} // our original array
	tree, _ := segment.NewTree(x, segment.MaxFunc{}) // segment tree which supports Range Maximum Queries

	fmt.Println(tree.RQ(0, 3))
	tree.Add(5, 2, 4) //increase elements in [2:4] by 5
	fmt.Println(tree.RQ(2, 4))
	tree.Add(13, 2, 2) // increase element at 2 by 13
	fmt.Println(tree.RQ(0, 2))
	tree.Add(10000, 0, 7) // increase all by 10000
	fmt.Println(tree.RQ(0, 7))

	//Output:
	//40 <nil>
	//45 <nil>
	//21 <nil>
	//10060 <nil>

More functionalities and their examples coming soon...

Benchmark

Naive approach vs Segment Tree

BenchmarkNaive2-4                   5000            370691 ns/op
BenchmarkNaive100-4                 2000            959208 ns/op
BenchmarkNaive10000-4                 20          90091228 ns/op
BenchmarkNaive100000-4                 1        1003322923 ns/op
BenchmarkTree2-4                    2000            828003 ns/op
BenchmarkTree100-4                   300           4318972 ns/op
BenchmarkTree10000-4                 100          12195815 ns/op
BenchmarkTree100000-4                100          15319705 ns/op

TODOs

  1. Make it work for other types, at least in64 and float64
  2. More/better Benchmarks