Red-black tree
 All Classes Functions
IntervalTreeMultiSet.java
1 /*
2  * Created by: Karol Sobczak (napewnotrafi@gmail.com)
3  */
4 package org.adblocktv.tagsserver.utils.rbtree;
5 
6 import java.util.*;
7 import org.adblocktv.tagsserver.utils.*;
8 
9 /**
10  * An implementation of an interval tree multi-set.
11  * @author Karol Sobczak
12  */
13 public class IntervalTreeMultiSet<K extends Comparable, V>
14  extends RedBlackTree<K, IntervalTreeMultiSet<K, V>.IntervalTreeNode>
15  implements Iterable<IntervalTreeMultiSet<K, V>.IntervalTreeNode> {
16 
17  /**
18  * An interval tree specific node.
19  */
20  public class IntervalTreeNode
21  extends RedBlackTree<K, IntervalTreeMultiSet<K, V>.IntervalTreeNode>.Node {
22 
23  /**
24  * An actual interval.
25  */
26  private Pair<K, K> interval;
27  /**
28  * The lowest value in a current node subtree.
29  */
30  private K min;
31  /**
32  * The highest value in a current node subtree.
33  */
34  private K max;
35  /**
36  * An interval tree node specific value.
37  */
38  private V value;
39 
40  @Override
41  protected void updatePath() {
42  Node nil = getNilNode();
43  Node node = this;
44  while (node != nil) {
45  node.updateSingle();
46  node = node.getParent();
47  }
48  }
49 
50  @Override
51  protected void updateSingle() {
52  //fix extreme values
53  IntervalTreeNode left = getLeftChild().getInternalValue();
54  IntervalTreeNode right = getRightChild().getInternalValue();
55  min = interval.a;
56  max = interval.b;
57  if (left != null) {
58  min = min.compareTo(left.min) < 0 ? min : left.min;
59  max = max.compareTo(left.max) > 0 ? max : left.max;
60  }
61  if (right != null) {
62  max = max.compareTo(right.max) > 0 ? max : right.max;
63  }
64  }
65 
66  @Override
67  protected void rotateUpdate() {
68  updateSingle();
69  }
70 
71  /**
72  * Constructs an interval tree node.
73  * @param interval
74  */
75  private IntervalTreeNode(Pair<K, K> interval, V value) {
76  super(interval.a, null);
77  this.interval = interval;
78  this.value = value;
79  setInternalValue(this);
80  }
81 
82  /**
83  * Returns a current node interval.
84  * @return a current node interval
85  */
86  public Pair<K, K> getInterval() {
87  return interval;
88  }
89 
90  /**
91  * Returns an interval tree node value.
92  * @return an interval tree node value
93  */
94  public V getValue() {
95  return value;
96  }
97 
98  @Override
99  public String toString() {
100  return "{ <" + interval.a + "," + interval.b + "> <" + min + "," + max + "> "
101  + (getLeftChild() != getNilNode() ? getLeftChild().toString() : "{ null }")
102  + (getRightChild() != getNilNode() ? getRightChild().toString() : "{ null }")
103  + " }";
104  }
105  }
106 
107  /**
108  * An iterator over interval tree nodes.
109  */
110  private class IntervalTreeMultiSetIterator implements Iterator<IntervalTreeNode> {
111 
112  private Iterator<Node> nodesIterator = nodesIterator();
113 
114  @Override
115  public boolean hasNext() {
116  return nodesIterator.hasNext();
117  }
118 
119  @Override
120  public IntervalTreeNode next() {
121  return nodesIterator.next().getInternalValue();
122  }
123 
124  @Override
125  public void remove() {
126  }
127  }
128  /**
129  * A flag determining if intervals are left exclusive.
130  */
131  private final boolean leftExclusive;
132  /**
133  * A flag determining if intervals are right exclusive
134  */
135  private final boolean rightExclusive;
136 
137  /**
138  * Compares a low value from a first interval with a high value from a second
139  * one (depending on exclusiveness equality might not be possible at all).
140  */
141  private int compareLowHigh(K low, K high) {
142  int result = low.compareTo(high);
143  return result != 0 ? result : (leftExclusive | rightExclusive ? 1 : 0);
144  }
145 
146  /**
147  * Compares a low value from an interval with a point value.
148  */
149  private int compareLowPoint(K low, K point) {
150  int result = low.compareTo(point);
151  return result != 0 ? result : (leftExclusive ? 1 : 0);
152  }
153 
154  /**
155  * Compares a high value from an interval with a point value.
156  */
157  private int compareHighPoint(K high, K point) {
158  int result = high.compareTo(point);
159  return result != 0 ? result : (rightExclusive ? -1 : 0);
160  }
161 
162  /**
163  * Checks whether intervals intersect.
164  */
165  private boolean intersect(Pair<K, K> x, Pair<K, K> y) {
166  return compareLowHigh(x.a, y.b) <= 0 && compareLowHigh(y.a, x.b) <= 0;
167  }
168 
169  /**
170  * Checks whether interval intersects point.
171  */
172  private boolean intersect(Pair<K, K> x, K point) {
173  return compareLowPoint(x.a, point) <= 0 && compareHighPoint(x.b, point) >= 0;
174  }
175 
176  /**
177  * Searches for all nodes intersecting a given interval.
178  */
179  private void searchAll(
180  Pair<K, K> interval,
181  IntervalTreeNode node,
182  List<IntervalTreeNode> resultNodes) {
183  //check whether there are possible intersections in left subtree
184  IntervalTreeNode left = node.getLeftChild().getInternalValue();
185  if (left != null && compareLowHigh(interval.a, left.max) <= 0) {
186  searchAll(interval, left, resultNodes);
187  }
188  //check whether current node intersects
189  if (intersect(node.interval, interval)) {
190  resultNodes.add(node);
191  }
192  //check whether there are possible intersections in right subtree
193  IntervalTreeNode right = node.getRightChild().getInternalValue();
194  if (right != null && compareLowHigh(right.min, interval.b) <= 0) {
195  searchAll(interval, right, resultNodes);
196  }
197  }
198 
199  /**
200  * Searches for all nodes intersecting a given point.
201  */
202  private void searchAll(
203  K point,
204  IntervalTreeNode node,
205  List<IntervalTreeNode> resultNodes) {
206  //check whether there are possible intersections in left subtree
207  IntervalTreeNode left = node.getLeftChild().getInternalValue();
208  if (left != null && compareHighPoint(left.max, point) >= 0) {
209  searchAll(point, left, resultNodes);
210  }
211  //checks whether current node intersects
212  if (intersect(node.interval, point)) {
213  resultNodes.add(node);
214  }
215  //check whether there are possible intersections in right subtree
216  IntervalTreeNode right = node.getRightChild().getInternalValue();
217  if (right != null && compareLowPoint(right.min, point) <= 0) {
218  searchAll(point, right, resultNodes);
219  }
220  }
221 
222  /**
223  * Constructs an IntervalTreeMultiSet instance.
224  * @param leftExclusive a flag determining if intervals are left exclusive
225  * @param rightExclusive a flag determining if intervals are right exclusive
226  */
227  public IntervalTreeMultiSet(boolean leftExclusive, boolean rightExclusive) {
228  this.leftExclusive = leftExclusive;
229  this.rightExclusive = rightExclusive;
230  }
231 
232  /**
233  * Adds an interval to the interval tree multi-set.
234  * @param interval an interval
235  * @param value an interval tree node value
236  * @return an interval tree node instance (can be used to remove the
237  * interval later)
238  */
239  public IntervalTreeNode add(Pair<K, K> interval, V value) {
240  IntervalTreeNode intervalTreeNode = new IntervalTreeNode(interval, value);
241  add(intervalTreeNode);
242  return intervalTreeNode;
243  }
244 
245  /**
246  * Removes an interval tree node from the interval tree.
247  * @param intervalTreeNode an interval tree node instance to be removed
248  */
249  public void remove(IntervalTreeNode intervalTreeNode) {
250  super.remove(intervalTreeNode);
251  }
252 
253  /**
254  * Searches for an interval tree node intersecting with a given interval or
255  * null if there is no such node.
256  * @param interval an interval
257  * @return an interval tree node that intersects with a given interval or
258  * null if there is no such node
259  */
260  public IntervalTreeNode search(Pair<K, K> interval) {
261  IntervalTreeNode node = getRootNode().getInternalValue();
262  while (node != null && !intersect(node.interval, interval)) {
263  IntervalTreeNode left = node.getLeftChild().getInternalValue();
264  if (left != null && compareLowHigh(interval.a, left.max) <= 0) {
265  node = left;
266  } else {
267  node = node.getRightChild().getInternalValue();
268  }
269  }
270  return node;
271  }
272 
273  /**
274  * Searches for an interval tree node intersecting with a given point or null
275  * if there is no such node.
276  * @param point a point
277  * @return an interval tree node that intersects with a given point or null
278  * if there is no such node
279  */
280  public IntervalTreeNode search(K point) {
281  IntervalTreeNode node = getRootNode().getInternalValue();
282  while (node != null && !intersect(node.interval, point)) {
283  IntervalTreeNode left = node.getLeftChild().getInternalValue();
284  if (left != null && compareHighPoint(left.max, point) >= 0) {
285  node = left;
286  } else {
287  node = node.getRightChild().getInternalValue();
288  }
289  }
290  return node;
291  }
292 
293  /**
294  * Searches for all interval tree nodes intersecting with a given interval.
295  * @param interval an interval
296  * @return a left ordered list of interval tree nodes intersecting with
297  * a given interval
298  */
299  public List<IntervalTreeNode> searchAll(Pair<K, K> interval) {
300  List<IntervalTreeNode> resultNodes = new LinkedList();
301  IntervalTreeNode root = getRootNode().getInternalValue();
302  if (root != null) {
303  searchAll(interval, root, resultNodes);
304  }
305  return resultNodes;
306  }
307 
308  /**
309  * Searches for all interval tree nodes intersecting with a given point.
310  * @param point a point
311  * @return a left ordered list of interval tree nodes intersecting with
312  * a given point
313  */
314  public List<IntervalTreeNode> searchAll(K point) {
315  List<IntervalTreeNode> resultNodes = new LinkedList();
316  IntervalTreeNode root = getRootNode().getInternalValue();
317  if (root != null) {
318  searchAll(point, root, resultNodes);
319  }
320  return resultNodes;
321  }
322 
323  /**
324  * Returns an iterator for interval tree nodes.
325  * @return an iterator for interval tree nodes
326  */
327  @Override
328  public Iterator<IntervalTreeNode> iterator() {
329  return new IntervalTreeMultiSetIterator();
330  }
331 }