package com.jwetherell.algorithms.data_structures;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Segment tree using objects and pointers. A segment tree is a tree data
* structure for storing intervals, or segments. It allows querying which of the
* stored segments contain a given point. It is, in principle, a static
* structure; that is, its content cannot be modified once the structure is
* built.
*
* http://en.wikipedia.org/wiki/Segment_tree
*
* This class is meant to be somewhat generic, all you'd have to do is extend
* the Data abstract class to store your custom data. I've also included a range
* minimum, range maximum, range sum, and interval stabbing implementations.
*
* @author Justin Wetherell <phishman3579@gmail.com>
*/
@SuppressWarnings("unchecked")
public abstract class SegmentTree<D extends SegmentTree.Data> {
protected Segment<D> root = null;
/**
* Stabbing query
*
* @param index
* index to query
* @return data at index.
*/
public abstract D query(long index);
/**
* Range query
*
* @param start
* start of range (inclusive)
* @param end
* end of range to (inclusive)
* @return data for range.
*/
public abstract D query(long start, long end);
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(SegmentTreePrinter.getString(this));
return builder.toString();
}
public abstract static class Data implements Comparable<Data> {
protected long start = Long.MIN_VALUE;
protected long end = Long.MAX_VALUE;
/**
* Constructor for data at index
*
* @param index
* of data.
*/
public Data(long index) {
this.start = index;
this.end = index;
}
/**
* Constructor for data at range (inclusive)
*
* @param start
* start of range for data.
* @param end
* end of range for data.
*/
public Data(long start, long end) {
this.start = start;
this.end = end;
}
/**
* Clear the indices
*/
public void clear() {
start = Long.MIN_VALUE;
end = Long.MAX_VALUE;
}
/**
* Combined this data with the Data parameter
*
* @param data
* Data to combined
* @return Data which represents the combination.
*/
public abstract Data combined(Data data);
/**
* Deep copy of data.
*
* @return deep copy.
*/
public abstract Data copy();
/**
* Query inside this data object.
*
* @param startOfRange
* start of range (inclusive)
* @param endOfRange
* end of range (inclusive)
* @return Data queried for or NULL if it doesn't match the query.
*/
public abstract Data query(long startOfRange, long endOfRange);
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(start).append("->").append(end);
return builder.toString();
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(Data d) {
if (this.end < d.end)
return -1;
if (d.end < this.end)
return 1;
return 0;
}
/**
* Data structure representing points in the x,y space and their
* location in the quadrants.
*/
public static final class QuadrantData extends Data {
public long quad0 = 0;
public long quad1 = 0;
public long quad2 = 0;
public long quad3 = 0;
public QuadrantData(long start, long end) {
super(start, end);
}
public QuadrantData(long index, long quad1, long quad2, long quad3, long quad4) {
super(index);
this.quad0 = quad1;
this.quad1 = quad2;
this.quad2 = quad3;
this.quad3 = quad4;
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
quad0 = 0;
quad1 = 0;
quad2 = 0;
quad3 = 0;
}
/**
* {@inheritDoc}
*/
@Override
public QuadrantData copy() {
final QuadrantData copy = new QuadrantData(start, end);
copy.quad0 = this.quad0;
copy.quad1 = this.quad1;
copy.quad2 = this.quad2;
copy.quad3 = this.quad3;
return copy;
}
/**
* {@inheritDoc}
*/
@Override
public Data query(long startOfQuery, long endOfQuery) {
if (endOfQuery < this.start || startOfQuery > this.end)
return null;
return copy();
}
/**
* {@inheritDoc}
*/
@Override
public Data combined(Data data) {
QuadrantData q = null;
if (data instanceof QuadrantData) {
q = (QuadrantData) data;
this.combined(q);
}
return this;
}
private void combined(QuadrantData data) {
this.quad0 += data.quad0;
this.quad1 += data.quad1;
this.quad2 += data.quad2;
this.quad3 += data.quad3;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return 31 * (int)(this.start + this.end + this.quad0 + this.quad1 + this.quad2 + this.quad3);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof QuadrantData))
return false;
QuadrantData data = (QuadrantData) obj;
if (this.start == data.start && this.end == data.end && this.quad0 == data.quad0
&& this.quad1 == data.quad1 && this.quad2 == data.quad2 && this.quad3 == data.quad3)
{
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append(quad0).append(",");
builder.append(quad1).append(",");
builder.append(quad2).append(",");
builder.append(quad3);
return builder.toString();
}
}
/**
* Data structure representing maximum in the range.
*/
public static final class RangeMaximumData<N extends Number> extends Data {
public N maximum = null;
public RangeMaximumData(long start, long end) {
super(start, end);
}
public RangeMaximumData(long index, N number) {
super(index);
this.maximum = number;
}
public RangeMaximumData(long start, long end, N number) {
super(start, end);
this.maximum = number;
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
maximum = null;
}
/**
* {@inheritDoc}
*/
@Override
public Data copy() {
return new RangeMaximumData<N>(start, end, maximum);
}
/**
* {@inheritDoc}
*/
@Override
public Data query(long startOfQuery, long endOfQuery) {
if (endOfQuery < this.start || startOfQuery > this.end)
return null;
return copy();
}
/**
* {@inheritDoc}
*/
@Override
public Data combined(Data data) {
RangeMaximumData<N> q = null;
if (data instanceof RangeMaximumData) {
q = (RangeMaximumData<N>) data;
this.combined(q);
}
return this;
}
private void combined(RangeMaximumData<N> data) {
if (this.maximum == null && data.maximum == null)
return;
else if (this.maximum != null && data.maximum == null)
return;
else if (this.maximum == null && data.maximum != null)
this.maximum = data.maximum;
else {
/* TODO: This is ugly */
if (this.maximum instanceof BigDecimal || data.maximum instanceof BigDecimal) {
if (((BigDecimal)data.maximum).compareTo(((BigDecimal)this.maximum))==1)
this.maximum = data.maximum;
} else if (this.maximum instanceof BigInteger || data.maximum instanceof BigInteger) {
if (((BigInteger)data.maximum).compareTo(((BigInteger)this.maximum))==1)
this.maximum = data.maximum;
} else if (this.maximum instanceof Long || data.maximum instanceof Long) {
if (((Long)data.maximum).compareTo(((Long)this.maximum))==1)
this.maximum = data.maximum;
} else if (this.maximum instanceof Double || data.maximum instanceof Double) {
if (((Double)data.maximum).compareTo(((Double)this.maximum))==1)
this.maximum = data.maximum;
} else if (this.maximum instanceof Float || data.maximum instanceof Float) {
if (((Float)data.maximum).compareTo(((Float)this.maximum))==1)
this.maximum = data.maximum;
} else {
// Integer
if (((Integer)data.maximum).compareTo(((Integer)this.maximum))==1)
this.maximum = data.maximum;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return 31 * (int)(this.start + this.end + this.maximum.hashCode());
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RangeMaximumData))
return false;
final RangeMaximumData<N> data = (RangeMaximumData<N>) obj;
if (this.start == data.start && this.end == data.end && this.maximum.equals(data.maximum))
return true;
return false;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append("maximum=").append(maximum);
return builder.toString();
}
}
/**
* Data structure representing minimum in the range.
*/
public static final class RangeMinimumData<N extends Number> extends Data {
public N minimum = null;
public RangeMinimumData(long start, long end) {
super(start, end);
}
public RangeMinimumData(long index, N number) {
super(index);
this.minimum = number;
}
public RangeMinimumData(long start, long end, N number) {
super(start, end);
this.minimum = number;
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
minimum = null;
}
/**
* {@inheritDoc}
*/
@Override
public Data copy() {
return new RangeMinimumData<N>(start, end, minimum);
}
/**
* {@inheritDoc}
*/
@Override
public Data query(long startOfQuery, long endOfQuery) {
if (endOfQuery < this.start || startOfQuery > this.end)
return null;
return copy();
}
/**
* {@inheritDoc}
*/
@Override
public Data combined(Data data) {
RangeMinimumData<N> q = null;
if (data instanceof RangeMinimumData) {
q = (RangeMinimumData<N>) data;
this.combined(q);
}
return this;
}
private void combined(RangeMinimumData<N> data) {
if (this.minimum == null && data.minimum == null)
return;
else if (this.minimum != null && data.minimum == null)
return;
else if (this.minimum == null && data.minimum != null)
this.minimum = data.minimum;
else {
/* TODO: This is ugly */
if (this.minimum instanceof BigDecimal || data.minimum instanceof BigDecimal) {
if (((BigDecimal)data.minimum).compareTo(((BigDecimal)this.minimum))==-1)
this.minimum = data.minimum;
} else if (this.minimum instanceof BigInteger || data.minimum instanceof BigInteger) {
if (((BigInteger)data.minimum).compareTo(((BigInteger)this.minimum))==-1)
this.minimum = data.minimum;
} else if (this.minimum instanceof Long || data.minimum instanceof Long) {
if (((Long)data.minimum).compareTo(((Long)this.minimum))==-1)
this.minimum = data.minimum;
} else if (this.minimum instanceof Double || data.minimum instanceof Double) {
if (((Double)data.minimum).compareTo(((Double)this.minimum))==-1)
this.minimum = data.minimum;
} else if (this.minimum instanceof Float || data.minimum instanceof Float) {
if (((Float)data.minimum).compareTo(((Float)this.minimum))==-1)
this.minimum = data.minimum;
} else {
// Integer
if (((Integer)data.minimum).compareTo(((Integer)this.minimum))==-1)
this.minimum = data.minimum;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return 31 * (int)(this.start + this.end + this.minimum.hashCode());
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RangeMinimumData))
return false;
final RangeMinimumData<N> data = (RangeMinimumData<N>) obj;
if (this.start == data.start && this.end == data.end && this.minimum.equals(data.minimum))
return true;
return false;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append("minimum=").append(minimum);
return builder.toString();
}
}
/**
* Data structure representing sum of the range.
*/
public static final class RangeSumData<N extends Number> extends Data {
public N sum = null;
public RangeSumData(long start, long end) {
super(start, end);
}
public RangeSumData(long index, N number) {
super(index);
this.sum = number;
}
public RangeSumData(long start, long end, N number) {
super(start, end);
this.sum = number;
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
sum = null;
}
/**
* {@inheritDoc}
*/
@Override
public Data copy() {
return new RangeSumData<N>(start, end, sum);
}
/**
* {@inheritDoc}
*/
@Override
public Data query(long startOfQuery, long endOfQuery) {
if (endOfQuery < this.start || startOfQuery > this.end)
return null;
return copy();
}
/**
* {@inheritDoc}
*/
@Override
public Data combined(Data data) {
RangeSumData<N> q = null;
if (data instanceof RangeSumData) {
q = (RangeSumData<N>) data;
this.combined(q);
}
return this;
}
private void combined(RangeSumData<N> data) {
if (this.sum == null && data.sum == null)
return;
else if (this.sum != null && data.sum == null)
return;
else if (this.sum == null && data.sum != null)
this.sum = data.sum;
else {
/* TODO: This is ugly and how to handle number overflow? */
if (this.sum instanceof BigDecimal || data.sum instanceof BigDecimal) {
BigDecimal result = ((BigDecimal)this.sum).add((BigDecimal)data.sum);
this.sum = (N)result;
} else if (this.sum instanceof BigInteger || data.sum instanceof BigInteger) {
BigInteger result = ((BigInteger)this.sum).add((BigInteger)data.sum);
this.sum = (N)result;
} else if (this.sum instanceof Long || data.sum instanceof Long) {
Long result = (this.sum.longValue() + data.sum.longValue());
this.sum = (N)result;
} else if (this.sum instanceof Double || data.sum instanceof Double) {
Double result = (this.sum.doubleValue() + data.sum.doubleValue());
this.sum = (N)result;
} else if (this.sum instanceof Float || data.sum instanceof Float) {
Float result = (this.sum.floatValue() + data.sum.floatValue());
this.sum = (N)result;
} else {
// Integer
Integer result = (this.sum.intValue() + data.sum.intValue());
this.sum = (N)result;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return 31 * (int)(this.start + this.end + this.sum.hashCode());
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RangeSumData))
return false;
final RangeSumData<N> data = (RangeSumData<N>) obj;
if (this.start == data.start && this.end == data.end && this.sum.equals(data.sum))
return true;
return false;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append("sum=").append(sum);
return builder.toString();
}
}
/**
* Data structure representing an interval.
*/
public static final class IntervalData<O extends Object> extends Data {
private Set<O> set = new TreeSet<O>(); // Sorted
/**
* Interval data using O as it's unique identifier
*
* @param object
* Object which defines the interval data
*/
public IntervalData(long index, O object) {
super(index);
this.set.add(object);
}
/**
* Interval data using O as it's unique identifier
*
* @param object
* Object which defines the interval data
*/
public IntervalData(long start, long end, O object) {
super(start, end);
this.set.add(object);
}
/**
* Interval data list which should all be unique
*
* @param list
* of interval data objects
*/
public IntervalData(long start, long end, Set<O> set) {
super(start, end);
this.set = set;
}
/**
* Get the data set in this interval
*
* @return Unmodifiable collection of data objects
*/
public Collection<O> getData() {
return Collections.unmodifiableCollection(this.set);
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
this.set.clear();
}
/**
* {@inheritDoc}
*/
@Override
public Data copy() {
final Set<O> listCopy = new TreeSet<O>();
listCopy.addAll(set);
return new IntervalData<O>(start, end, listCopy);
}
/**
* {@inheritDoc}
*/
@Override
public Data query(long startOfQuery, long endOfQuery) {
if (endOfQuery < this.start || startOfQuery > this.end)
return null;
return copy();
}
/**
* {@inheritDoc}
*/
@Override
public Data combined(Data data) {
IntervalData<O> q = null;
if (data instanceof IntervalData) {
q = (IntervalData<O>) data;
this.combined(q);
}
return this;
}
/**
* Combined for interval specific data.
*
* @param data
* resulted from combination.
*/
private void combined(IntervalData<O> data) {
if (data.start < this.start)
this.start = data.start;
if (data.end > this.end)
this.end = data.end;
this.set.addAll(data.set);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return 31 * (int)(this.start + this.end + this.set.size());
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof IntervalData))
return false;
final IntervalData<O> data = (IntervalData<O>) obj;
if (this.start == data.start && this.end == data.end) {
if (this.set.size() != data.set.size())
return false;
for (O o : set) {
if (!data.set.contains(o))
return false;
}
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append("set=").append(set);
return builder.toString();
}
}
}
/**
* Data structure representing a segment.
*/
protected abstract static class Segment<D extends Data> implements Comparable<Segment<D>> {
protected Segment<D>[] segments = null;
protected int length = 0;
protected int half = 0;
protected long start = 0;
protected long end = 0;
protected D data = null;
protected int minLength = 0;
public Segment(int minLength) {
this.minLength = minLength;
}
/**
* Query for data in range.
*
* @param startOfQuery
* of the range to query for.
* @param endOfQuery
* of range to query for.
* @return Data in the range.
*/
public abstract D query(long startOfQuery, long endOfQuery);
protected boolean hasChildren() {
return (segments != null);
}
protected Segment<D> getLeftChild() {
return segments[0];
}
protected Segment<D> getRightChild() {
return segments[1];
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(start).append("->");
builder.append(end).append(" ");
builder.append("Length=").append(length).append(" ");
builder.append("Data={").append(data).append("}");
return builder.toString();
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(Segment<D> p) {
if (this.end < p.end)
return -1;
if (p.end < this.end)
return 1;
return 0;
}
}
protected static class SegmentTreePrinter {
public static <D extends SegmentTree.Data> String getString(SegmentTree<D> tree) {
if (tree.root == null)
return "Tree has no nodes.";
return getString(tree.root, "", true);
}
private static <D extends SegmentTree.Data> String getString(Segment<D> segment, String prefix, boolean isTail) {
final StringBuilder builder = new StringBuilder();
builder.append(prefix + (isTail ? "└── " : "├── ") + segment.toString() + "\n");
final List<Segment<D>> children = new ArrayList<Segment<D>>();
if (segment.segments != null) {
for (Segment<D> c : segment.segments)
children.add(c);
}
for (int i = 0; i < children.size() - 1; i++)
builder.append(getString(children.get(i), prefix + (isTail ? " " : "│ "), false));
if (children.size() > 1)
builder.append(getString(children.get(children.size() - 1), prefix + (isTail ? " " : "│ "), true));
return builder.toString();
}
}
/**
* Flat segment tree is a variant of segment tree that is designed to store
* a collection of non-overlapping segments. This structure is efficient
* when you need to store values associated with 1 dimensional segments that
* never overlap with each other. The end points of stored segments are
* inclusive, that is, when a segment spans from 2 to 6, an arbitrary point
* x within that segment can take a value of 2 <= x <= 6.
*/
public static final class FlatSegmentTree<D extends Data> extends SegmentTree<D> {
public FlatSegmentTree(List<D> data) {
this(data, 1);
}
public FlatSegmentTree(List<D> data, int minLength) {
if (data.size() <= 0)
throw new InvalidParameterException("Segments list is empty.");
Collections.sort(data); // Make sure they are sorted
// Make sure they don't overlap
if (data.size() >= 2) {
for (int i = 0; i < (data.size() - 2); i++) {
Data s1 = data.get(i);
Data s2 = data.get(i + 1);
if (s1.end > s2.start)
throw new InvalidParameterException("Segments are overlapping.");
}
}
// Check for gaps
final List<NonOverlappingSegment<D>> segments = new ArrayList<NonOverlappingSegment<D>>();
for (int i = 0; i < data.size(); i++) {
if (i < data.size() - 1) {
final Data d1 = data.get(i);
final NonOverlappingSegment<D> s1 = new NonOverlappingSegment<D>(minLength, d1.start, d1.end, (D) d1);
segments.add(s1);
final Data d2 = data.get(i + 1);
if (d2.start - d1.end > 1) {
final Data d3 = d1.copy();
d3.clear();
d3.start = d1.end + 1;
d3.end = d2.start - 1;
final NonOverlappingSegment<D> s3 = new NonOverlappingSegment<D>(minLength, d3.start, d3.end, (D) d3);
segments.add(s3);
}
} else {
final Data d1 = data.get(i);
final NonOverlappingSegment<D> s1 = new NonOverlappingSegment<D>(minLength, d1.start, d1.end, (D) d1);
segments.add(s1);
}
}
final long start = segments.get(0).start;
final long end = segments.get(segments.size() - 1).end;
final int length = (int) (end - start) + 1;
root = NonOverlappingSegment.createFromList(minLength, segments, start, length);
}
/**
* {@inheritDoc}
*/
@Override
public D query(long index) {
return this.query(index, index);
}
/**
* {@inheritDoc}
*/
@Override
public D query(long startOfQuery, long endOfQuery) {
if (root == null)
return null;
long s = startOfQuery;
long e = endOfQuery;
if (s < root.start)
s = root.start;
if (e > root.end)
e = root.end;
return root.query(s, e);
}
/**
* Data structure representing a non-overlapping segment.
*/
protected static final class NonOverlappingSegment<D extends Data> extends Segment<D> {
private Set<Segment<D>> set = new TreeSet<Segment<D>>();
public NonOverlappingSegment(int minLength) {
super(minLength);
}
public NonOverlappingSegment(int minLength, D data) {
this(minLength, data.start, data.end, data);
}
public NonOverlappingSegment(int minLength, long start, long end, D data) {
super(minLength);
this.start = start;
this.end = end;
this.length = ((int) (end - start)) + 1;
if (data == null)
return;
this.data = ((D) data.copy());
}
protected static <D extends Data> Segment<D> createFromList(int minLength, List<NonOverlappingSegment<D>> segments, long start, int length) {
final NonOverlappingSegment<D> segment = new NonOverlappingSegment<D>(minLength);
segment.start = start;
segment.end = start + (length - 1);
segment.length = length;
for (Segment<D> s : segments) {
if (segment.data == null)
segment.data = ((D) s.data.copy());
else
segment.data.combined(s.data); // Update our data to reflect all children's data
}
// If segment is greater or equal to two, split data into children
if (segment.length >= 2 && segment.length >= minLength) {
segment.half = segment.length / 2;
final List<NonOverlappingSegment<D>> s1 = new ArrayList<NonOverlappingSegment<D>>();
final List<NonOverlappingSegment<D>> s2 = new ArrayList<NonOverlappingSegment<D>>();
for (int i = 0; i < segments.size(); i++) {
final NonOverlappingSegment<D> s = segments.get(i);
final long middle = segment.start + segment.half;
if (s.end < middle) {
s1.add(s);
} else if (s.start >= middle) {
s2.add(s);
} else {
// Need to split across middle
final NonOverlappingSegment<D> ss1 = new NonOverlappingSegment<D>(minLength, s.start, middle - 1, s.data);
s1.add(ss1);
final NonOverlappingSegment<D> ss2 = new NonOverlappingSegment<D>(minLength, middle, s.end, s.data);
s2.add(ss2);
}
}
final Segment<D> sub1 = createFromList(minLength, s1, segment.start, segment.half);
final Segment<D> sub2 = createFromList(minLength, s2, segment.start + segment.half, segment.length - segment.half);
segment.segments = new Segment[] { sub1, sub2 };
} else if (segment.length <= minLength) {
for (Segment<D> s : segments) {
segment.set.add(s);
}
}
return segment;
}
/**
* {@inheritDoc}
*/
@Override
public D query(long startOfQuery, long endOfQuery) {
if (startOfQuery == this.start && endOfQuery == this.end) {
if (this.data == null)
return null;
final D dataToReturn = ((D) this.data.query(startOfQuery, endOfQuery));
return dataToReturn;
}
if (!this.hasChildren()) {
if (endOfQuery < this.start || startOfQuery > this.end) {
// Ignore
} else {
D dataToReturn = null;
if (this.set.size() == 0)
return dataToReturn;
for (Segment<D> s : this.set) {
if (s.start >= startOfQuery && s.end <= endOfQuery) {
if (dataToReturn == null)
dataToReturn = (D) s.data.query(startOfQuery, endOfQuery);
else
dataToReturn.combined(s.data);
} else if (s.start <= startOfQuery && s.end >= endOfQuery) {
if (dataToReturn == null)
dataToReturn = (D) s.data.query(startOfQuery, endOfQuery);
else
dataToReturn.combined(s.data);
}
}
return dataToReturn;
}
}
if (this.hasChildren()) {
if (startOfQuery <= this.getLeftChild().end && endOfQuery > this.getLeftChild().end) {
final Data q1 = this.getLeftChild().query(startOfQuery, getLeftChild().end);
final Data q2 = this.getRightChild().query(getRightChild().start, endOfQuery);
if (q1 == null && q2 == null)
return null;
if (q1 != null && q2 == null)
return (D) q1;
if (q1 == null && q2 != null)
return (D) q2;
if (q1 != null && q2 != null)
return ((D) q1.combined(q2));
} else if (startOfQuery <= this.getLeftChild().end && endOfQuery <= this.getLeftChild().end) {
return this.getLeftChild().query(startOfQuery, endOfQuery);
}
return this.getRightChild().query(startOfQuery, endOfQuery);
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append("Set=").append(set);
return builder.toString();
}
}
}
/**
* Segment tree is a balanced-binary-tree based data structure efficient for
* detecting all intervals (or segments) that contain a given point. The
* segments may overlap with each other. The end points of stored segments
* are inclusive, that is, when an interval spans from 2 to 6, an arbitrary
* point x within that interval can take a value of 2 <= x <=6.
*/
public static final class DynamicSegmentTree<D extends Data> extends SegmentTree<D> {
private static final Comparator<OverlappingSegment<?>> START_COMPARATOR = new Comparator<OverlappingSegment<?>>() {
/**
* {@inheritDoc}
*/
@Override
public int compare(OverlappingSegment<?> arg0, OverlappingSegment<?> arg1) {
if (arg0.start < arg1.start)
return -1;
if (arg1.start < arg0.start)
return 1;
return 0;
}
};
private static final Comparator<OverlappingSegment<?>> END_COMPARATOR = new Comparator<OverlappingSegment<?>>() {
/**
* {@inheritDoc}
*/
@Override
public int compare(OverlappingSegment<?> arg0, OverlappingSegment<?> arg1) {
if (arg0.end < arg1.end)
return -1;
if (arg1.end < arg0.end)
return 1;
return 0;
}
};
public DynamicSegmentTree(List<D> data) {
this(data, 1);
}
public DynamicSegmentTree(List<D> data, int minLength) {
if (data.size() <= 0)
return;
// Check for gaps
final List<OverlappingSegment<D>> segments = new ArrayList<OverlappingSegment<D>>();
for (int i = 0; i < data.size(); i++) {
if (i < data.size() - 1) {
final Data d1 = data.get(i);
final OverlappingSegment<D> s1 = new OverlappingSegment<D>(minLength, d1.start, d1.end, (D) d1);
segments.add(s1);
final Data d2 = data.get(i + 1);
if (d2.start - d1.end > 1) {
final Data d3 = d1.copy();
d3.clear();
d3.start = d1.end + 1;
d3.end = d2.start - 1;
final OverlappingSegment<D> s3 = new OverlappingSegment<D>(minLength, d3.start, d3.end, (D) d3);
segments.add(s3);
}
} else {
final Data d1 = data.get(i);
final OverlappingSegment<D> s1 = new OverlappingSegment<D>(minLength, d1.start, d1.end, (D) d1);
segments.add(s1);
}
}
// First start first
Collections.sort(segments, START_COMPARATOR);
final OverlappingSegment<D> startNode = segments.get(0);
final long start = startNode.start - 1;
final OverlappingSegment<D> s1 = new OverlappingSegment<D>(minLength, start, startNode.start, null);
segments.add(0, s1);
// Last end last
Collections.sort(segments, END_COMPARATOR);
final OverlappingSegment<D> endNode = segments.get(segments.size() - 1);
final long end = endNode.end + 1;
final OverlappingSegment<D> s2 = new OverlappingSegment<D>(minLength, endNode.end, end, null);
segments.add(s2);
final int length = (int) (end - start) + 1;
root = OverlappingSegment.createFromList(minLength, segments, start, length);
}
/**
* {@inheritDoc}
*/
@Override
public D query(long index) {
return this.query(index, index);
}
/**
* {@inheritDoc}
*/
@Override
public D query(long startOfQuery, long endOfQuery) {
if (root == null)
return null;
long s = startOfQuery;
long e = endOfQuery;
if (s < root.start)
s = root.start;
if (e > root.end)
e = root.end;
final D result = root.query(s, e);
// reset the start and end, it can change during the query
result.start = startOfQuery;
result.end = endOfQuery;
return result;
}
/**
* Data structure representing a possibly overlapping segment.
*/
protected static final class OverlappingSegment<D extends Data> extends Segment<D> {
// Separate range set for fast range queries
protected Set<Segment<D>> range = new HashSet<Segment<D>>();
public OverlappingSegment(int minLength) {
super(minLength);
}
public OverlappingSegment(int minLength, long start, long end, D data) {
super(minLength);
this.start = start;
this.end = end;
this.length = ((int) (end - start)) + 1;
if (data == null)
return;
this.data = ((D) data.copy());
}
protected static <D extends Data> Segment<D> createFromList(int minLength, List<OverlappingSegment<D>> segments, long start, int length) {
final OverlappingSegment<D> segment = new OverlappingSegment<D>(minLength);
segment.start = start;
segment.end = start + (length - 1);
segment.length = length;
for (Segment<D> s : segments) {
if (s.data == null)
continue;
if (s.end < segment.start || s.start > segment.end) {
// Ignore
} else {
segment.range.add(s);
}
if (s.start == segment.start && s.end == segment.end) {
if (segment.data == null)
segment.data = ((D) s.data.copy());
else
segment.data.combined(s.data); // Update our data to reflect all children's data
} else if (!segment.hasChildren() && s.start >= segment.start && s.end <= segment.end) {
if (segment.data == null)
segment.data = ((D) s.data.copy());
else
segment.data.combined(s.data); // Update our data to reflect all children's data
}
}
// If segment is greater or equal to two, split data into children
if (segment.length >= 2 && segment.length >= minLength) {
segment.half = segment.length / 2;
final List<OverlappingSegment<D>> s1 = new ArrayList<OverlappingSegment<D>>();
final List<OverlappingSegment<D>> s2 = new ArrayList<OverlappingSegment<D>>();
for (int i = 0; i < segments.size(); i++) {
final OverlappingSegment<D> s = segments.get(i);
final long middle = segment.start + segment.half;
if (s.end < middle) {
s1.add(s);
} else if (s.start >= middle) {
s2.add(s);
} else {
// Need to split across middle
final OverlappingSegment<D> ss1 = new OverlappingSegment<D>(minLength, s.start, middle - 1, s.data);
s1.add(ss1);
final OverlappingSegment<D> ss2 = new OverlappingSegment<D>(minLength, middle, s.end, s.data);
s2.add(ss2);
}
}
final Segment<D> sub1 = createFromList(minLength, s1, segment.start, segment.half);
final Segment<D> sub2 = createFromList(minLength, s2, segment.start + segment.half, segment.length - segment.half);
segment.segments = new Segment[] { sub1, sub2 };
}
return segment;
}
/**
* {@inheritDoc}
*/
@Override
public D query(long startOfQuery, long endOfQuery) {
D result = null;
// Use the range data to make range queries faster
if (startOfQuery == this.start && endOfQuery == this.end) {
for (Segment<D> s : this.range) {
final D temp = (D) s.data.query(startOfQuery, endOfQuery);
if (temp != null) {
if (result == null)
result = (D) temp.copy();
else
result.combined(temp);
}
}
} else if (!this.hasChildren()) {
if (endOfQuery < this.start || startOfQuery > this.end) {
// Ignore
} else {
for (Segment<D> s : this.range) {
if (endOfQuery < s.start || startOfQuery > s.end) {
// Ignore
} else {
final D temp = (D) s.data.query(startOfQuery, endOfQuery);
if (temp != null) {
if (result == null)
result = (D) temp.copy();
else
result.combined(temp);
}
}
}
}
} else {
final long middle = this.start + this.half;
D temp = null;
if (startOfQuery < middle && endOfQuery >= middle) {
temp = this.getLeftChild().query(startOfQuery, middle - 1);
D temp2 = this.getRightChild().query(middle, endOfQuery);
if (temp2 != null) {
if (temp == null)
temp = (D) temp2.copy();
else
temp.combined(temp2);
}
} else if (endOfQuery < middle) {
temp = this.getLeftChild().query(startOfQuery, endOfQuery);
} else if (startOfQuery >= middle) {
temp = this.getRightChild().query(startOfQuery, endOfQuery);
}
if (temp != null)
result = (D) temp.copy();
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(super.toString()).append(" ");
builder.append("Range=").append(range);
return builder.toString();
}
}
}
}