/** * */ package cz.cuni.mff.peckam.java.origamist.unused.utils; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; /** * An implementation of interval tree. * * @author Martin Pecka */ public class IntervalTree<K extends Comparable<? super K>, V> extends RedBlackTree<Interval<K>, V> { /** */ private static final long serialVersionUID = -2870778379455176949L; /** * Construct an empty interval tree. */ public IntervalTree() { super(new IntervalByMinComparator<K>()); entryFactory = new IntervalEntryFactory(); } /** * Construct interval tree with mappings from the given map. * * @param m The map to read mappings from. */ public IntervalTree(Map<? extends Interval<K>, ? extends V> m) { super(new IntervalByMinComparator<K>()); entryFactory = new IntervalEntryFactory(); putAll(m); } /** * Construct interval tree with mappings from the given map. * * If the given map's comparator is instance of {@link IntervalByMinComparator}<K>, this method will run in * linear time, otherwise it will run in n*log n time. * * @param m The map to read mappings from. */ public IntervalTree(SortedMap<Interval<K>, ? extends V> m) { super(new IntervalByMinComparator<K>()); entryFactory = new IntervalEntryFactory(); if (!(m.comparator() instanceof IntervalByMinComparator<?>)) putAll(m); else buildFromSorted(m.size(), m.entrySet().iterator()); } @Override protected void repairTreeAfterInsert(TreePath path) { // the inserted value is on the end of the path K max = path.getLast().getKey().getMax(); // we update the maximum values for all nodes on the path (setting it also for the last one is ok) for (Entry e : path) { @SuppressWarnings("unchecked") IntervalEntry ie = (IntervalEntry) e; if (ie.getMax() == null || ie.getMax().compareTo(max) < 0) ie.setMax(max); } super.repairTreeAfterInsert(path); } @SuppressWarnings("unchecked") @Override protected void deleteLastPathEntry(TreePath path) { ((IntervalEntry) path.getLast()).setMax(null); Iterator<Entry> it = path.descendingIterator(); it.next(); // skip the last node which we've already checked // walk up the path and repair the subtree maximum caches while (it.hasNext()) { IntervalEntry e = (IntervalEntry) it.next(); K maxK = e.getKey().getMax(); K maxL = (e.left == null ? null : ((IntervalEntry) e.left).getMax()); K maxR = (e.right == null ? null : ((IntervalEntry) e.right).getMax()); e.setMax(max(maxK, max(maxL, maxR))); } super.deleteLastPathEntry(path); } /** * Return the value of a node that has its key overlapping with the given interval. * * @param key The interval to find overlap for. * @return The value of a node that has its key overlapping with the given interval. */ public V intervalGet(Interval<K> key) { IntervalEntry e = getIntervalEntry(key); return (e == null ? null : e.value); } /** * Return a node that has its key overlapping with the given interval. * * @param key The interval to find overlap for. * @return A node that has its key overlapping with the given interval. */ @SuppressWarnings("unchecked") protected IntervalEntry getIntervalEntry(Interval<K> key) { IntervalEntry p = (IntervalEntry) root; while (p != null && !p.getKey().overlapsWith(key)) { if (p.left != null && ((IntervalEntry) p.left).getMax() != null && ((IntervalEntry) p.left).getMax().compareTo(key.getMin()) >= 0) p = (IntervalEntry) p.left; else p = (IntervalEntry) p.right; } return p; } /** * Comparator of intervals that compares them according to their lower bounds. * * <code>null</code> is less than everything else, two <code>null</code>s are equal. * * @author Martin Pecka */ protected static class IntervalByMinComparator<T extends Comparable<? super T>> implements Comparator<Interval<T>> { @Override public int compare(Interval<T> o1, Interval<T> o2) { if (o1 == null) return (o2 == null ? 0 : -1); if (o2 == null) return 1; return o1.getMax().compareTo(o2.getMax()); } } /** * Entry factory that returns {@link IntervalEntry} entries and {@link IntervalTreePath} paths. * * @author Martin Pecka */ protected class IntervalEntryFactory extends EntryFactory { @Override public IntervalEntry createEntry(Interval<K> key, V value) { return new IntervalEntry(key, value); } @Override public IntervalTreePath createTreePath() { return new IntervalTreePath(); } } /** * Entry of the interval tree - it has to store the maximum value contained in the subtree defined by this entry. * * @author Martin Pecka */ protected class IntervalEntry extends Entry { /** The maximum upper bound contained in the subtree defined by this entry. */ protected K max; /** * @param key * @param value */ IntervalEntry(Interval<K> key, V value) { super(key, value); max = key.getMax(); } /** * @return the max */ public K getMax() { return max; } /** * @param max the max to set */ public void setMax(K max) { this.max = max; } @Override public String toString() { return key + "=" + value + "(max=" + max + ")"; } } /** * A tree path in the interval tree which handles maximum subtree caches correctly. * * @author Martin Pecka */ protected class IntervalTreePath extends TreePath { /** */ private static final long serialVersionUID = -7383073835756793866L; @SuppressWarnings("unchecked") @Override public void rotateLeft() { IntervalEntry x = (IntervalEntry) getLast(); IntervalEntry y = (IntervalEntry) x.right; super.rotateLeft(); y.setMax(x.getMax()); K maxK = x.getKey().getMax(); K maxL = (x.left == null ? null : ((IntervalEntry) x.left).getMax()); K maxR = (x.right == null ? null : ((IntervalEntry) x.right).getMax()); x.setMax(max(maxK, max(maxL, maxR))); } @SuppressWarnings("unchecked") @Override public void rotateRight() { IntervalEntry x = (IntervalEntry) getLast(); IntervalEntry y = (IntervalEntry) x.left; super.rotateRight(); y.setMax(x.getMax()); K maxK = x.getKey().getMax(); K maxL = (x.left == null ? null : ((IntervalEntry) x.left).getMax()); K maxR = (x.right == null ? null : ((IntervalEntry) x.right).getMax()); x.setMax(max(maxK, max(maxL, maxR))); } } /** * Return the maximum of the two comparables. <code>null</code> is less than everything. * * @param <K> * @param val1 The first value to compare. * @param val2 The second value to compare. * @return The maximum. */ protected static <K extends Comparable<? super K>> K max(K val1, K val2) { if (val1 == null) return val2; if (val2 == null) return val1; return (val1.compareTo(val2) >= 0 ? val1 : val2); } }