package com.interview.tree;
/**
* Date 08/21/2014
* @author tusroy
*
* Video link - https://youtu.be/ZBHKZF5w4YU
*
* A segment tree is a tree data structure for storing intervals, or segments. It allows
* for faster querying (e.g sum or min) in these intervals.
* Write a program to support these operations for sum
* createSegmentTree(int arr[]) - create segment tree
* query(int segment[], int startRange, int endRange) - query in this range
*
* Similar segment trees can be created for min or max.
*
* Time complexity to create segment tree is O(nlogn)
* Space complexity to create segment tree is O(nlogn)
* Time complexity to search in segment tree is O(logn)
* References
* http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/
* http://www.geeksforgeeks.org/segment-tree-set-1-range-minimum-query/
*/
public class SegmentTree {
public int[] createTree(int input[], Operation operation){
int height = (int)Math.ceil(Math.log(input.length)/Math.log(2));
int segmentTree[] = new int[(int)(Math.pow(2, height+1)-1)];
constructTree(segmentTree,input,0,input.length-1,0, operation);
return segmentTree;
}
private void constructTree(int segmentTree[], int input[], int low, int high,int pos, Operation operation){
if(low == high){
segmentTree[pos] = input[low];
return;
}
int mid = (low + high)/2;
constructTree(segmentTree,input,low,mid,2*pos+1, operation);
constructTree(segmentTree,input,mid+1,high,2*pos+2, operation);
segmentTree[pos] = operation.perform(segmentTree[2*pos+1], segmentTree[2*pos+2]);
}
public int rangeQuery(int []segmentTree,int qlow,int qhigh,int len, Operation operation){
return rangeQuery(segmentTree,0,len-1,qlow,qhigh,0, operation);
}
private int rangeQuery(int segmentTree[],int low,int high,int qlow,int qhigh,int pos, Operation operation){
if(qlow <= low && qhigh >= high){
return segmentTree[pos];
}
if(qlow > high || qhigh < low){
return 0;
}
int mid = (low+high)/2;
return operation.perform(rangeQuery(segmentTree,low,mid,qlow,qhigh,2*pos+1, operation),
rangeQuery(segmentTree,mid+1,high,qlow,qhigh,2*pos+2, operation));
}
public void updateValueForSumOperation(int input[],int segmentTree[],int newVal,int index){
int diff = newVal - input[index];
input[index] = newVal;
updateVal(segmentTree,0,input.length-1,diff,index,0);
}
private void updateVal(int segmentTree[],int low,int high,int diff,int index, int pos){
if(index < low || index > high){
return;
}
segmentTree[pos] += diff;
if(low >= high){
return;
}
int mid = (low + high)/2;
updateVal(segmentTree,low,mid,diff,index,2*pos+1);
updateVal(segmentTree,mid+1,high,diff,index,2*pos+2);
}
public static void main(String args[]){
int input[] = {1,3,5,7,9,11};
SegmentTree st = new SegmentTree();
Operation sumOp = new SumOperation();
Operation minOp = new MinOperation();
int result [] = st.createTree(input, sumOp);
for(int i=0; i < result.length; i++){
System.out.print(result[i] + " ");
}
int input1[] = {3,4,2,1,6,-1};
int result1[] = st.createTree(input1, minOp);
for(int i=0; i < result1.length; i++){
System.out.print(result1[i] + " ");
}
st.updateValueForSumOperation(input, result,0 , 0);
System.out.println();
for(int i=0; i < result.length; i++){
System.out.print(result[i] + " ");
}
}
}
/**
* Provides interface to perform operations on range queue like sum or min
*/
interface Operation{
int perform(int a, int b);
}
class SumOperation implements Operation{
@Override
public int perform(int a, int b) {
return a+b;
}
}
class MinOperation implements Operation{
@Override
public int perform(int a, int b){
return Math.min(a,b);
}
}