Java Program to Implement Interval Tree

This is a java program to implement Interval Tree. In computer science, an interval tree is an ordered tree data structure to hold intervals. Specifically, it allows one to efficiently find all intervals that overlap with any given interval or point. It is often used for windowing queries, for instance, to find all roads on a computerized map inside a rectangular viewport, or to find all visible elements inside a three-dimensional scene. A similar data structure is the segment tree. The trivial solution is to visit each interval and test whether it intersects the given point or interval, which requires T(n) time, where n is the number of intervals in the collection.

Here is the source code of the Java Program to Implement Interval Tree. The Java program is successfully compiled and run on a Windows system. The program output is also shown below.

//This is a java program to implement a interval tree
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
 
class Interval<Type> implements Comparable<Interval<Type>>
{
 
    private long start;
    private long end;
    private Type data;
 
    public Interval(long start, long end, Type data)
    {
        this.start = start;
        this.end = end;
        this.data = data;
    }
 
    public long getStart()
    {
        return start;
    }
 
    public void setStart(long start)
    {
        this.start = start;
    }
 
    public long getEnd()
    {
        return end;
    }
 
    public void setEnd(long end)
    {
        this.end = end;
    }
 
    public Type getData()
    {
        return data;
    }
 
    public void setData(Type data)
    {
        this.data = data;
    }
 
    public boolean contains(long time)
    {
        return time < end && time > start;
    }
 
    public boolean intersects(Interval<?> other)
    {
        return other.getEnd() > start && other.getStart() < end;
    }
 
    public int compareTo(Interval<Type> other)
    {
        if (start < other.getStart())
            return -1;
        else if (start > other.getStart())
            return 1;
        else if (end < other.getEnd())
            return -1;
        else if (end > other.getEnd())
            return 1;
        else
            return 0;
    }
 
}
 
class IntervalNode<Type>
{
 
    private SortedMap<Interval<Type>, List<Interval<Type>>> intervals;
    private long                                            center;
    private IntervalNode<Type>                              leftNode;
    private IntervalNode<Type>                              rightNode;
 
    public IntervalNode()
    {
        intervals = new TreeMap<Interval<Type>, List<Interval<Type>>>();
        center = 0;
        leftNode = null;
        rightNode = null;
    }
 
    public IntervalNode(List<Interval<Type>> intervalList)
    {
 
        intervals = new TreeMap<Interval<Type>, List<Interval<Type>>>();
 
        SortedSet<Long> endpoints = new TreeSet<Long>();
 
        for (Interval<Type> interval : intervalList)
        {
            endpoints.add(interval.getStart());
            endpoints.add(interval.getEnd());
        }
 
        long median = getMedian(endpoints);
        center = median;
 
        List<Interval<Type>> left = new ArrayList<Interval<Type>>();
        List<Interval<Type>> right = new ArrayList<Interval<Type>>();
 
        for (Interval<Type> interval : intervalList)
        {
            if (interval.getEnd() < median)
                left.add(interval);
            else if (interval.getStart() > median)
                right.add(interval);
            else
            {
                List<Interval<Type>> posting = intervals.get(interval);
                if (posting == null)
                {
                    posting = new ArrayList<Interval<Type>>();
                    intervals.put(interval, posting);
                }
                posting.add(interval);
            }
        }
 
        if (left.size() > 0)
            leftNode = new IntervalNode<Type>(left);
        if (right.size() > 0)
            rightNode = new IntervalNode<Type>(right);
    }
 
    public List<Interval<Type>> stab(long time)
    {
        List<Interval<Type>> result = new ArrayList<Interval<Type>>();
 
        for (Entry<Interval<Type>, List<Interval<Type>>> entry : intervals
                .entrySet())
        {
            if (entry.getKey().contains(time))
                for (Interval<Type> interval : entry.getValue())
                    result.add(interval);
            else if (entry.getKey().getStart() > time)
                break;
        }
 
        if (time < center && leftNode != null)
            result.addAll(leftNode.stab(time));
        else if (time > center && rightNode != null)
            result.addAll(rightNode.stab(time));
        return result;
    }
 
    public List<Interval<Type>> query(Interval<?> target)
    {
        List<Interval<Type>> result = new ArrayList<Interval<Type>>();
 
        for (Entry<Interval<Type>, List<Interval<Type>>> entry : intervals
                .entrySet())
        {
            if (entry.getKey().intersects(target))
                for (Interval<Type> interval : entry.getValue())
                    result.add(interval);
            else if (entry.getKey().getStart() > target.getEnd())
                break;
        }
 
        if (target.getStart() < center && leftNode != null)
            result.addAll(leftNode.query(target));
        if (target.getEnd() > center && rightNode != null)
            result.addAll(rightNode.query(target));
        return result;
    }
 
    public long getCenter()
    {
        return center;
    }
 
    public void setCenter(long center)
    {
        this.center = center;
    }
 
    public IntervalNode<Type> getLeft()
    {
        return leftNode;
    }
 
    public void setLeft(IntervalNode<Type> left)
    {
        this.leftNode = left;
    }
 
    public IntervalNode<Type> getRight()
    {
        return rightNode;
    }
 
    public void setRight(IntervalNode<Type> right)
    {
        this.rightNode = right;
    }
 
    private Long getMedian(SortedSet<Long> set)
    {
        int i = 0;
        int middle = set.size() / 2;
        for (Long point : set)
        {
            if (i == middle)
                return point;
            i++;
        }
        return null;
    }
 
    @Override
    public String toString()
    {
        StringBuffer sb = new StringBuffer();
        sb.append(center + ": ");
        for (Entry<Interval<Type>, List<Interval<Type>>> entry : intervals
                .entrySet())
        {
            sb.append("[" + entry.getKey().getStart() + ","
                    + entry.getKey().getEnd() + "]:{");
            for (Interval<Type> interval : entry.getValue())
            {
                sb.append("(" + interval.getStart() + "," + interval.getEnd()
                        + "," + interval.getData() + ")");
            }
            sb.append("} ");
        }
        return sb.toString();
    }
 
}
 
class IntervalTree<Type>
{
 
    private IntervalNode<Type>   head;
    private List<Interval<Type>> intervalList;
    private boolean              inSync;
    private int                  size;
 
    public IntervalTree()
    {
        this.head = new IntervalNode<Type>();
        this.intervalList = new ArrayList<Interval<Type>>();
        this.inSync = true;
        this.size = 0;
    }
 
    public IntervalTree(List<Interval<Type>> intervalList)
    {
        this.head = new IntervalNode<Type>(intervalList);
        this.intervalList = new ArrayList<Interval<Type>>();
        this.intervalList.addAll(intervalList);
        this.inSync = true;
        this.size = intervalList.size();
    }
 
    public List<Type> get(long time)
    {
        List<Interval<Type>> intervals = getIntervals(time);
        List<Type> result = new ArrayList<Type>();
        for (Interval<Type> interval : intervals)
            result.add(interval.getData());
        return result;
    }
 
    public List<Interval<Type>> getIntervals(long time)
    {
        build();
        return head.stab(time);
    }
 
    public List<Type> get(long start, long end)
    {
        List<Interval<Type>> intervals = getIntervals(start, end);
        List<Type> result = new ArrayList<Type>();
        for (Interval<Type> interval : intervals)
            result.add(interval.getData());
        return result;
    }
 
    public List<Interval<Type>> getIntervals(long start, long end)
    {
        build();
        return head.query(new Interval<Type>(start, end, null));
    }
 
    public void addInterval(Interval<Type> interval)
    {
        intervalList.add(interval);
        inSync = false;
    }
 
    public void addInterval(long begin, long end, Type data)
    {
        intervalList.add(new Interval<Type>(begin, end, data));
        inSync = false;
    }
 
    public boolean inSync()
    {
        return inSync;
    }
 
    public void build()
    {
        if (!inSync)
        {
            head = new IntervalNode<Type>(intervalList);
            inSync = true;
            size = intervalList.size();
        }
    }
 
    public int currentSize()
    {
        return size;
    }
 
    public int listSize()
    {
        return intervalList.size();
    }
 
    @Override
    public String toString()
    {
        return nodeString(head, 0);
    }
 
    private String nodeString(IntervalNode<Type> node, int level)
    {
        if (node == null)
            return "";
 
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < level; i++)
            sb.append("\t");
        sb.append(node + "\n");
        sb.append(nodeString(node.getLeft(), level + 1));
        sb.append(nodeString(node.getRight(), level + 1));
        return sb.toString();
    }
}
 
public class IntervalTreeProblem
{
    public static void main(String args[])
    {
        IntervalTree<Integer> it = new IntervalTree<Integer>();
 
        it.addInterval(0L, 10L, 1);
        it.addInterval(20L, 30L, 2);
        it.addInterval(15L, 17L, 3);
        it.addInterval(25L, 35L, 4);
 
        List<Integer> result1 = it.get(5L);
        List<Integer> result2 = it.get(10L);
        List<Integer> result3 = it.get(29L);
        List<Integer> result4 = it.get(5L, 15L);
 
        System.out.print("\nIntervals that contain 5L:");
        for (int r : result1)
            System.out.print(r + " ");
 
        System.out.print("\nIntervals that contain 10L:");
        for (int r : result2)
            System.out.print(r + " ");
 
        System.out.print("\nIntervals that contain 29L:");
        for (int r : result3)
            System.out.print(r + " ");
 
        System.out.print("\nIntervals that intersect (5L,15L):");
        for (int r : result4)
            System.out.print(r + " ");
    }
}

Output:

$ javac IntervalTreeImplementation.java
$ java IntervalTreeImplementation
 
Interval Tree Implementation
 
Intervals that contain 5L:1 
Intervals that contain 10L:
Intervals that contain 29L:2 4 
Intervals that intersect (5L,15L):1

Related posts:

Removing all Nulls from a List in Java
Java Program to Find Second Smallest of n Elements with Given Complexity Constraint
A Guide to the finalize Method in Java
Java Program to Implement Trie
Send an email with an attachment
Java Program to Perform Finite State Automaton based Search
Java Program to Find the Number of Ways to Write a Number as the Sum of Numbers Smaller than Itself
Java Program to Implement HashMap API
Java Program to Implement Triply Linked List
Guide to Java 8’s Collectors
Java Program to Check if an UnDirected Graph is a Tree or Not Using DFS
Java Program to Perform Encoding of a Message Using Matrix Multiplication
Java Program to Implement Doubly Linked List
Write/Read cookies using HTTP and Read a file from the internet
Java Program to Perform integer Partition for a Specific Case
Send an email using the SMTP protocol
Map to String Conversion in Java
Java Program to Describe the Representation of Graph using Incidence Matrix
Find the Registered Spring Security Filters
Java Program to Implement Interpolation Search Algorithm
Ignore Null Fields with Jackson
Limiting Query Results with JPA and Spring Data JPA
Java Web Services – JAX-WS – SOAP
Spring Boot - Cloud Configuration Client
Java Program to Generate All Pairs of Subsets Whose Union Make the Set
Validations for Enum Types
Spring Security with Maven
Creating a Generic Array in Java
Java Program to Generate Random Partition out of a Given Set of Numbers or Characters
Java 14 Record Keyword
Java Program to Use rand and srand Functions
Guide to Java OutputStream