reformat all code

This commit is contained in:
Leijurv
2023-03-15 13:30:23 -07:00
parent 2af6dec3df
commit 8ee36bcd46
23 changed files with 341 additions and 203 deletions

View File

@@ -7,7 +7,7 @@ package com.github.btrekkie.connectivity;
* combine(combine(combine(A1, A2), A3), A4). In order for an augmentation result to be meaningful, the combining
* function must be commutative, meaning combine(x, y) is equivalent to combine(y, x), and associative, meaning
* combine(x, combine(y, z)) is equivalent to combine(combine(x, y), z).
*
* <p>
* If a ConnGraph represents a game map, then one example of an augmentation would be the amount of gold accessible from
* a certain location. Each vertex would be augmented with the amount of gold in that location, and the combining
* function would add the two amounts of gold passed in as arguments. Another example would be the strongest monster
@@ -16,18 +16,18 @@ package com.github.btrekkie.connectivity;
* in as arguments. A third example would be the number of locations accessible from a given vertex. Each vertex would
* be augmented with the number 1, and the combining function would add the two numbers of vertices passed in as
* arguments.
*
* <p>
* ConnGraph treats two augmentation values X and Y as interchangeable if they are equal, as in
* X != null ? X.equals(Y) : Y == null. The same holds for two combined augmentation values, and for one combined
* augmentation value and one augmentation value.
*
* <p>
* See the comments for ConnGraph.
*/
public interface Augmentation {
/**
* Returns the result of combining the specified values into one. Each argument is either the augmentation
* information associated with a vertex, or the result of a previous call to "combine".
*
* <p>
* Note that a value of null is never passed in to indicate the absence of augmentation information. The fact that
* ConnGraph.getVertexAugmentation, for example, may return null when there is no associated augmentation might lead
* you to believe that a null argument indicates the absence of augmentation information, but again, it does not. A

View File

@@ -4,7 +4,7 @@ package com.github.btrekkie.connectivity;
* Represents an edge in a ConnGraph, at the level of the edge (i.e. at the lowest level i for which G_i contains the
* edge). Every graph edge has exactly one corresponding ConnEdge object, regardless of the number of levels it appears
* in. See the comments for the implementation of ConnGraph.
*
* <p>
* ConnEdges are stored in the linked lists suggested by EulerTourVertex.graphListHead and
* EulerTourVertex.forestListHead. Each ConnEdge is in two linked lists, so care must be taken when traversing the
* linked lists. prev1 and next1 are the links for the list starting at vertex1.graphListHead or vertex1.forestListHead,
@@ -14,10 +14,14 @@ package com.github.btrekkie.connectivity;
* after next1 is next1.next1, but otherwise, it is next1.next2.
*/
class ConnEdge {
/** The edge's first endpoint (at the same level as the edge). */
/**
* The edge's first endpoint (at the same level as the edge).
*/
public EulerTourVertex vertex1;
/** The edge's second endpoint (at the same level as the edge). */
/**
* The edge's second endpoint (at the same level as the edge).
*/
public EulerTourVertex vertex2;
/**

View File

@@ -1,10 +1,6 @@
package com.github.btrekkie.connectivity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* Implements an undirected graph with dynamic connectivity. It supports adding and removing edges and determining
@@ -12,7 +8,7 @@ import java.util.Map;
* amortized time with high probability, while checking whether two vertices are connected takes O(log N) time with high
* probability. It uses O(V log V + E) space, where V is the number of vertices and E is the number of edges. Note that
* a ConnVertex may appear in multiple ConnGraphs, with a different set of adjacent vertices in each graph.
*
* <p>
* ConnGraph optionally supports arbitrary augmentation. Each vertex may have an associated augmentation, or value.
* Given a vertex V, ConnGraph can quickly report the result of combining the augmentations of all of the vertices in
* the connected component containing V, using a combining function provided to the constructor. For example, if a
@@ -22,12 +18,12 @@ import java.util.Map;
* the augmentation takes a constant amount of space. Retrieving the combined augmentation for a connected component
* takes O(log N) time with high probability. (Although ConnGraph does not directly support augmenting edges, this can
* also be accomplished, by imputing each edge's augmentation to an adjacent vertex.)
*
* <p>
* When a vertex no longer has any adjacent edges, and it has no augmentation information, ConnGraph stops keeping track
* of the vertex. This reduces the time and space bounds of the ConnGraph, and it enables the ConnVertex to be garbage
* collected. If you know you are finished with a vertex, and that vertex has an augmentation, then you should call
* removeVertexAugmentation on the vertex, so that the graph can release it.
*
* <p>
* As a side note, it would be more proper if ConnGraph had a generic type parameter indicating the type of the
* augmentation values. However, it is expected that it is more common not to use augmentation, so by not using a type
* parameter, we make usage of the ConnGraph class more convenient and less confusing in the common case.
@@ -106,7 +102,7 @@ public class ConnGraph {
* The maximum number of vertices we can store in a ConnGraph. This is limited by the fact that EulerTourNode.size
* is an int. Since the size of an Euler tour tree is one less than twice the number of vertices in the tree, the
* number of vertices may be at most (int)((((long)Integer.MAX_VALUE) + 1) / 2).
*
* <p>
* Of course, we could simply change the "size" field to be a long. But more fundamentally, the number of vertices
* is limited by the fact that vertexInfo and VertexInfo.edges use HashMaps. Using a HashMap becomes problematic at
* around Integer.MAX_VALUE entries. HashMap buckets entries based on 32-bit hash codes, so in principle, it can
@@ -115,7 +111,9 @@ public class ConnGraph {
*/
private static final int MAX_VERTEX_COUNT = 1 << 30;
/** The augmentation function for the graph, if any. */
/**
* The augmentation function for the graph, if any.
*/
private final Augmentation augmentation;
/**
@@ -139,22 +137,28 @@ public class ConnGraph {
*/
private int maxVertexInfoSize;
/** Constructs a new ConnGraph with no augmentation. */
/**
* Constructs a new ConnGraph with no augmentation.
*/
public ConnGraph() {
augmentation = null;
}
/** Constructs an augmented ConnGraph, using the specified function to combine augmentation values. */
/**
* Constructs an augmented ConnGraph, using the specified function to combine augmentation values.
*/
public ConnGraph(Augmentation augmentation) {
this.augmentation = augmentation;
}
/** Equivalent implementation is contractual. */
/**
* Equivalent implementation is contractual.
*/
private void assertIsAugmented() {
if (augmentation == null) {
throw new RuntimeException(
"You may only call augmentation-related methods on ConnGraph if the graph is augmented, i.e. if an " +
"Augmentation was passed to the constructor");
"You may only call augmentation-related methods on ConnGraph if the graph is augmented, i.e. if an " +
"Augmentation was passed to the constructor");
}
}
@@ -171,8 +175,8 @@ public class ConnGraph {
if (vertexInfo.size() == MAX_VERTEX_COUNT) {
throw new RuntimeException(
"Sorry, ConnGraph has too many vertices to perform this operation. ConnGraph does not support " +
"storing more than ~2^30 vertices at a time.");
"Sorry, ConnGraph has too many vertices to perform this operation. ConnGraph does not support " +
"storing more than ~2^30 vertices at a time.");
}
EulerTourVertex eulerTourVertex = new EulerTourVertex();
@@ -215,9 +219,10 @@ public class ConnGraph {
* list for an EulerTourVertex that represents the same underlying ConnVertex, but at a higher level. This has the
* effect of prepending the list for the lower level to the beginning of the list for the higher level, and
* replacing all links to the lower-level vertex in the ConnEdges with links to the higher-level vertex.
* @param head The first node in the list for the higher-level vertex.
* @param lowerHead The first node in the list for the lower-level vertex.
* @param vertex The higher-level vertex.
*
* @param head The first node in the list for the higher-level vertex.
* @param lowerHead The first node in the list for the lower-level vertex.
* @param vertex The higher-level vertex.
* @param lowerVertex The lower-level vertex.
* @return The head of the combined linked list.
*/
@@ -257,7 +262,7 @@ public class ConnGraph {
/**
* Equivalent implementation is contractual.
*
* <p>
* This method is useful for when an EulerTourVertex's lists (graphListHead or forestListHead) or arbitrary visit
* change, as these affect the hasGraphEdge and hasForestEdge augmentations.
*/
@@ -301,7 +306,7 @@ public class ConnGraph {
}
vertex.graphListHead =
collapseEdgeList(vertex.graphListHead, lowerVertex.graphListHead, vertex, lowerVertex);
collapseEdgeList(vertex.graphListHead, lowerVertex.graphListHead, vertex, lowerVertex);
if (lowerVertex.forestListHead != null) {
// Change the eulerTourEdge links
ConnEdge lowerEdge = lowerVertex.forestListHead;
@@ -320,7 +325,7 @@ public class ConnGraph {
}
vertex.forestListHead =
collapseEdgeList(vertex.forestListHead, lowerVertex.forestListHead, vertex, lowerVertex);
collapseEdgeList(vertex.forestListHead, lowerVertex.forestListHead, vertex, lowerVertex);
}
}
@@ -505,7 +510,9 @@ public class ConnGraph {
return new EulerTourEdge(newNode, max);
}
/** Removes the specified edge from the Euler tour forest F_i. */
/**
* Removes the specified edge from the Euler tour forest F_i.
*/
private void removeForestEdge(EulerTourEdge edge) {
EulerTourNode firstNode;
EulerTourNode secondNode;
@@ -535,8 +542,9 @@ public class ConnGraph {
/**
* Adds the specified edge to the edge map for srcInfo (srcInfo.edges). Assumes that the edge is not currently in
* the map.
* @param edge The edge.
* @param srcInfo The source vertex's info.
*
* @param edge The edge.
* @param srcInfo The source vertex's info.
* @param destVertex The destination vertex, i.e. the edge's key in srcInfo.edges.
*/
private void addToEdgeMap(ConnEdge edge, VertexInfo srcInfo, ConnVertex destVertex) {
@@ -549,6 +557,7 @@ public class ConnGraph {
/**
* Adds an edge between the specified vertices, if such an edge is not already present. Taken together with
* removeEdge, this method takes O(log^2 N) amortized time with high probability.
*
* @return Whether there was no edge between the vertices.
*/
public boolean addEdge(ConnVertex connVertex1, ConnVertex connVertex2) {
@@ -557,8 +566,8 @@ public class ConnGraph {
}
if (vertexInfo.size() >= MAX_VERTEX_COUNT - 1) {
throw new RuntimeException(
"Sorry, ConnGraph has too many vertices to perform this operation. ConnGraph does not support " +
"storing more than ~2^30 vertices at a time.");
"Sorry, ConnGraph has too many vertices to perform this operation. ConnGraph does not support " +
"storing more than ~2^30 vertices at a time.");
}
VertexInfo info1 = ensureInfo(connVertex1);
if (info1.edges.containsKey(connVertex2)) {
@@ -614,7 +623,7 @@ public class ConnGraph {
return;
}
EulerTourNode node;
for (node = root; node.left.hasForestEdge; node = node.left);
for (node = root; node.left.hasForestEdge; node = node.left) ;
while (node != null) {
EulerTourVertex vertex = node.vertex;
ConnEdge edge = vertex.forestListHead;
@@ -657,7 +666,7 @@ public class ConnGraph {
// Iterate to the next node with hasForestEdge == true, clearing hasForestEdge as we go
if (node.right.hasForestEdge) {
for (node = node.right; node.left.hasForestEdge; node = node.left);
for (node = node.right; node.left.hasForestEdge; node = node.left) ;
} else {
node.hasForestEdge = false;
while (node.parent != null && node.parent.right == node) {
@@ -674,6 +683,7 @@ public class ConnGraph {
* tree, where i is the level of the tree. This is a "replacement" edge because it replaces the edge that was
* previously connecting the two trees. We push any level-i edges we encounter that do not connect to another tree
* down to level i - 1, adding them to G_{i - 1}. This method assumes that root.hasForestEdge is false.
*
* @param root The root of the tree.
* @return The replacement edge, or null if there is no replacement edge.
*/
@@ -683,7 +693,7 @@ public class ConnGraph {
return null;
}
EulerTourNode node;
for (node = root; node.left.hasGraphEdge; node = node.left);
for (node = root; node.left.hasGraphEdge; node = node.left) ;
while (node != null) {
EulerTourVertex vertex = node.vertex;
ConnEdge edge = vertex.graphListHead;
@@ -767,7 +777,7 @@ public class ConnGraph {
// Iterate to the next node with hasGraphEdge == true. Note that nodes' hasGraphEdge fields can change as we
// push down edges.
if (node.right.hasGraphEdge) {
for (node = node.right; node.left.hasGraphEdge; node = node.left);
for (node = node.right; node.left.hasGraphEdge; node = node.left) ;
} else {
while (node.parent != null && (node.parent.right == node || !node.parent.hasGraphEdge)) {
node = node.parent;
@@ -798,6 +808,7 @@ public class ConnGraph {
/**
* Removes the edge between the specified vertices, if there is such an edge. Taken together with addEdge, this
* method takes O(log^2 N) amortized time with high probability.
*
* @return Whether there was an edge between the vertices.
*/
public boolean removeEdge(ConnVertex vertex1, ConnVertex vertex2) {
@@ -912,7 +923,9 @@ public class ConnGraph {
return info2 != null && info1.vertex.arbitraryVisit.root() == info2.vertex.arbitraryVisit.root();
}
/** Returns the vertices that are directly adjacent to the specified vertex. */
/**
* Returns the vertices that are directly adjacent to the specified vertex.
*/
public Collection<ConnVertex> adjacentVertices(ConnVertex vertex) {
VertexInfo info = vertexInfo.get(vertex);
if (info != null) {
@@ -925,12 +938,12 @@ public class ConnGraph {
/**
* Sets the augmentation associated with the specified vertex. This method takes O(log N) time with high
* probability.
*
* <p>
* Note that passing a null value for the second argument is not the same as removing the augmentation. For that,
* you need to call removeVertexAugmentation.
*
* @return The augmentation that was previously associated with the vertex. Returns null if it did not have any
* associated augmentation.
* associated augmentation.
*/
public Object setVertexAugmentation(ConnVertex connVertex, Object vertexAugmentation) {
assertIsAugmented();
@@ -952,8 +965,9 @@ public class ConnGraph {
/**
* Removes any augmentation associated with the specified vertex. This method takes O(log N) time with high
* probability.
*
* @return The augmentation that was previously associated with the vertex. Returns null if it did not have any
* associated augmentation.
* associated augmentation.
*/
public Object removeVertexAugmentation(ConnVertex connVertex) {
assertIsAugmented();
@@ -1127,7 +1141,7 @@ public class ConnGraph {
private void optimizeGraphEdges() {
for (VertexInfo info : vertexInfo.values()) {
EulerTourVertex vertex;
for (vertex = info.vertex; vertex.lowerVertex != null; vertex = vertex.lowerVertex);
for (vertex = info.vertex; vertex.lowerVertex != null; vertex = vertex.lowerVertex) ;
while (vertex != null) {
EulerTourNode node = vertex.arbitraryVisit;
ConnEdge edge = vertex.graphListHead;

View File

@@ -2,9 +2,13 @@ package com.github.btrekkie.connectivity;
import java.util.Random;
/** A vertex in a ConnGraph. See the comments for ConnGraph. */
/**
* A vertex in a ConnGraph. See the comments for ConnGraph.
*/
public class ConnVertex {
/** The thread-local random number generator we use by default to set the "hash" field. */
/**
* The thread-local random number generator we use by default to set the "hash" field.
*/
private static final ThreadLocal<Random> random = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
@@ -24,8 +28,9 @@ public class ConnVertex {
/**
* Constructs a new ConnVertex.
*
* @param random The random number generator to use to produce a random hash code. ConnGraph relies on random hash
* codes for its performance guarantees.
* codes for its performance guarantees.
*/
public ConnVertex(Random random) {
hash = random.nextInt();

View File

@@ -7,13 +7,19 @@ import com.github.btrekkie.red_black_node.RedBlackNode;
* ConnGraph.
*/
class EulerTourNode extends RedBlackNode<EulerTourNode> {
/** The dummy leaf node. */
/**
* The dummy leaf node.
*/
public static final EulerTourNode LEAF = new EulerTourNode(null, null);
/** The vertex this node visits. */
/**
* The vertex this node visits.
*/
public final EulerTourVertex vertex;
/** The number of nodes in the subtree rooted at this node. */
/**
* The number of nodes in the subtree rooted at this node.
*/
public int size;
/**
@@ -53,13 +59,15 @@ class EulerTourNode extends RedBlackNode<EulerTourNode> {
this.augmentationFunc = augmentationFunc;
}
/** Like augment(), but only updates the augmentation fields hasGraphEdge and hasForestEdge. */
/**
* Like augment(), but only updates the augmentation fields hasGraphEdge and hasForestEdge.
*/
public boolean augmentFlags() {
boolean newHasGraphEdge =
left.hasGraphEdge || right.hasGraphEdge || (vertex.arbitraryVisit == this && vertex.graphListHead != null);
left.hasGraphEdge || right.hasGraphEdge || (vertex.arbitraryVisit == this && vertex.graphListHead != null);
boolean newHasForestEdge =
left.hasForestEdge || right.hasForestEdge ||
(vertex.arbitraryVisit == this && vertex.forestListHead != null);
left.hasForestEdge || right.hasForestEdge ||
(vertex.arbitraryVisit == this && vertex.forestListHead != null);
if (newHasGraphEdge == hasGraphEdge && newHasForestEdge == hasForestEdge) {
return false;
} else {

View File

@@ -35,9 +35,13 @@ class EulerTourVertex {
*/
public ConnEdge forestListHead;
/** The augmentation associated with this vertex, if any. This is null instead if higherVertex != null. */
/**
* The augmentation associated with this vertex, if any. This is null instead if higherVertex != null.
*/
public Object augmentation;
/** Whether there is any augmentation associated with this vertex. This is false instead if higherVertex != null. */
/**
* Whether there is any augmentation associated with this vertex. This is false instead if higherVertex != null.
*/
public boolean hasAugmentation;
}

View File

@@ -8,7 +8,9 @@ import java.util.Map;
* a given graph, regardless of how many levels the vertex is in. See the comments for the implementation of ConnGraph.
*/
class VertexInfo {
/** The representation of the vertex in the highest level. */
/**
* The representation of the vertex in the highest level.
*/
public EulerTourVertex vertex;
/**

View File

@@ -3,11 +3,7 @@
package com.github.btrekkie.red_black_node;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.*;
/**
* A node in a red-black tree ( https://en.wikipedia.org/wiki/Red%E2%80%93black_tree ). Compared to a class like Java's
@@ -15,20 +11,20 @@ import java.util.Set;
* clients to directly observe and manipulate the structure of the tree. This gives clients flexibility, although it
* also enables them to violate the red-black or BST properties. The RedBlackNode class provides methods for performing
* various standard operations, such as insertion and removal.
*
* <p>
* Unlike most implementations of binary search trees, RedBlackNode supports arbitrary augmentation. By subclassing
* RedBlackNode, clients can add arbitrary data and augmentation information to each node. For example, if we were to
* use a RedBlackNode subclass to implement a sorted set, the subclass would have a field storing an element in the set.
* If we wanted to keep track of the number of non-leaf nodes in each subtree, we would store this as a "size" field and
* override augment() to update this field. All RedBlackNode methods (such as "insert" and remove()) call augment() as
* necessary to correctly maintain the augmentation information, unless otherwise indicated.
*
* <p>
* The values of the tree are stored in the non-leaf nodes. RedBlackNode does not support use cases where values must be
* stored in the leaf nodes. It is recommended that all of the leaf nodes in a given tree be the same (black)
* RedBlackNode instance, to save space. The root of an empty tree is a leaf node, as opposed to null.
*
* <p>
* For reference, a red-black tree is a binary search tree satisfying the following properties:
*
* <p>
* - Every node is colored red or black.
* - The leaf nodes, which are dummy nodes that do not store any values, are colored black.
* - The root is black.
@@ -36,11 +32,13 @@ import java.util.Set;
* - Every path from the root to a leaf contains the same number of black nodes.
*
* @param <N> The type of node in the tree. For example, we might have
* "class FooNode<T> extends RedBlackNode<FooNode<T>>".
* "class FooNode<T> extends RedBlackNode<FooNode<T>>".
* @author Bill Jacobs
*/
public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Comparable<N> {
/** A Comparator that compares Comparable elements using their natural order. */
/**
* A Comparator that compares Comparable elements using their natural order.
*/
private static final Comparator<Comparable<Object>> NATURAL_ORDER = new Comparator<Comparable<Object>>() {
@Override
public int compare(Comparable<Object> value1, Comparable<Object> value2) {
@@ -48,16 +46,24 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
};
/** The parent of this node, if any. "parent" is null if this is a leaf node. */
/**
* The parent of this node, if any. "parent" is null if this is a leaf node.
*/
public N parent;
/** The left child of this node. "left" is null if this is a leaf node. */
/**
* The left child of this node. "left" is null if this is a leaf node.
*/
public N left;
/** The right child of this node. "right" is null if this is a leaf node. */
/**
* The right child of this node. "right" is null if this is a leaf node.
*/
public N right;
/** Whether the node is colored red, as opposed to black. */
/**
* Whether the node is colored red, as opposed to black.
*/
public boolean isRed;
/**
@@ -65,12 +71,12 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* example, if we augment each node by subtree size (the number of non-leaf nodes in the subtree), this method would
* set the size field of this node to be equal to the size field of the left child plus the size field of the right
* child plus one.
*
* <p>
* "Augmentation information" is information that we can compute about a subtree rooted at some node, preferably
* based only on the augmentation information in the node's two children and the information in the node. Examples
* of augmentation information are the sum of the values in a subtree and the number of non-leaf nodes in a subtree.
* Augmentation information may not depend on the colors of the nodes.
*
* <p>
* This method returns whether the augmentation information in any of the ancestors of this node might have been
* affected by changes in this subtree since the last call to augment(). In the usual case, where the augmentation
* information depends only on the information in this node and the augmentation information in its immediate
@@ -79,7 +85,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* calling augment() differed from the size field of the left child plus the size field of the right child plus one.
* False positives are permitted. The return value is unspecified if we have not called augment() on this node
* before.
*
* <p>
* This method may assume that this is not a leaf node. It may not assume that the augmentation information stored
* in any of the tree's nodes is correct. However, if the augmentation information stored in all of the node's
* descendants is correct, then the augmentation information stored in this node must be correct after calling
@@ -94,7 +100,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* of RedBlackNode. For example, if this stores the size of the subtree rooted at this node, this should throw a
* RuntimeException if the size field of this is not equal to the size field of the left child plus the size field
* of the right child plus one. Note that we may call this on a leaf node.
*
* <p>
* assertSubtreeIsValid() calls assertNodeIsValid() on each node, or at least starts to do so until it detects a
* problem. assertNodeIsValid() should assume the node is in a tree that satisfies all properties common to all
* red-black trees, as assertSubtreeIsValid() is responsible for such checks. assertNodeIsValid() should be
@@ -107,58 +113,68 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
/** Returns whether this is a leaf node. */
/**
* Returns whether this is a leaf node.
*/
public boolean isLeaf() {
return left == null;
}
/** Returns the root of the tree that contains this node. */
/**
* Returns the root of the tree that contains this node.
*/
public N root() {
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
while (node.parent != null) {
node = node.parent;
}
return node;
}
/** Returns the first node in the subtree rooted at this node, if any. */
/**
* Returns the first node in the subtree rooted at this node, if any.
*/
public N min() {
if (isLeaf()) {
return null;
}
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
while (!node.left.isLeaf()) {
node = node.left;
}
return node;
}
/** Returns the last node in the subtree rooted at this node, if any. */
/**
* Returns the last node in the subtree rooted at this node, if any.
*/
public N max() {
if (isLeaf()) {
return null;
}
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
while (!node.right.isLeaf()) {
node = node.right;
}
return node;
}
/** Returns the node immediately before this in the tree that contains this node, if any. */
/**
* Returns the node immediately before this in the tree that contains this node, if any.
*/
public N predecessor() {
if (!left.isLeaf()) {
N node;
for (node = left; !node.right.isLeaf(); node = node.right);
for (node = left; !node.right.isLeaf(); node = node.right) ;
return node;
} else if (parent == null) {
return null;
} else {
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
while (node.parent != null && node.parent.left == node) {
node = node.parent;
}
@@ -166,17 +182,19 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
}
/** Returns the node immediately after this in the tree that contains this node, if any. */
/**
* Returns the node immediately after this in the tree that contains this node, if any.
*/
public N successor() {
if (!right.isLeaf()) {
N node;
for (node = right; !node.left.isLeaf(); node = node.left);
for (node = right; !node.left.isLeaf(); node = node.left) ;
return node;
} else if (parent == null) {
return null;
} else {
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
while (node.parent != null && node.parent.right == node) {
node = node.parent;
}
@@ -188,6 +206,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Performs a left rotation about this node. This method assumes that !isLeaf() && !right.isLeaf(). It calls
* augment() on this node and on its resulting parent. However, it does not call augment() on any of the resulting
* parent's ancestors, because that is normally the responsibility of the caller.
*
* @return The return value from calling augment() on the resulting parent.
*/
public boolean rotateLeft() {
@@ -197,7 +216,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
N newParent = right;
right = newParent.left;
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
if (!right.isLeaf()) {
right.parent = nThis;
}
@@ -219,6 +238,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Performs a right rotation about this node. This method assumes that !isLeaf() && !left.isLeaf(). It calls
* augment() on this node and on its resulting parent. However, it does not call augment() on any of the resulting
* parent's ancestors, because that is normally the responsibility of the caller.
*
* @return The return value from calling augment() on the resulting parent.
*/
public boolean rotateRight() {
@@ -228,7 +248,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
N newParent = left;
left = newParent.right;
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
if (!left.isLeaf()) {
left.parent = nThis;
}
@@ -252,6 +272,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs
* any rotations by calling rotateLeft() and rotateRight(). This method is more efficient than fixInsertion if
* "augment" is false or augment() might return false.
*
* @param augment Whether to set the augmentation information for "node" and its ancestors, by calling augment().
*/
public void fixInsertionWithoutGettingRoot(boolean augment) {
@@ -339,6 +360,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be
* red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs
* any rotations by calling rotateLeft() and rotateRight().
*
* @param augment Whether to set the augmentation information for "node" and its ancestors, by calling augment().
* @return The root of the resulting tree.
*/
@@ -352,6 +374,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be
* red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs
* any rotations by calling rotateLeft() and rotateRight().
*
* @return The root of the resulting tree.
*/
public N fixInsertion() {
@@ -359,27 +382,29 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
return root();
}
/** Returns a Comparator that compares instances of N using their natural order, as in N.compareTo. */
/**
* Returns a Comparator that compares instances of N using their natural order, as in N.compareTo.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private Comparator<N> naturalOrder() {
Comparator comparator = (Comparator)NATURAL_ORDER;
return (Comparator<N>)comparator;
Comparator comparator = (Comparator) NATURAL_ORDER;
return (Comparator<N>) comparator;
}
/**
* Inserts the specified node into the tree rooted at this node. Assumes this is the root. We treat newNode as a
* solitary node that does not belong to any tree, and we ignore its initial "parent", "left", "right", and isRed
* fields.
*
* <p>
* If it is not efficient or convenient to find the location for a node using a Comparator, then you should manually
* add the node to the appropriate location, color it red, and call fixInsertion().
*
* @param newNode The node to insert.
* @param newNode The node to insert.
* @param allowDuplicates Whether to insert newNode if there is an equal node in the tree. To check whether we
* inserted newNode, check whether newNode.parent is null and the return value differs from newNode.
* @param comparator A comparator indicating where to put the node. If this is null, we use the nodes' natural
* order, as in N.compareTo. If you are passing null, then you must override the compareTo method, because the
* default implementation requires the nodes to already be in the same tree.
* inserted newNode, check whether newNode.parent is null and the return value differs from newNode.
* @param comparator A comparator indicating where to put the node. If this is null, we use the nodes' natural
* order, as in N.compareTo. If you are passing null, then you must override the compareTo method, because the
* default implementation requires the nodes to already be in the same tree.
* @return The root of the resulting tree.
*/
public N insert(N newNode, boolean allowDuplicates, Comparator<? super N> comparator) {
@@ -387,7 +412,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
throw new IllegalArgumentException("This is not the root of a tree");
}
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
if (isLeaf()) {
newNode.isRed = false;
newNode.left = nThis;
@@ -436,6 +461,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
/**
* Moves this node to its successor's former position in the tree and vice versa, i.e. sets the "left", "right",
* "parent", and isRed fields of each. This method assumes that this is not a leaf node.
*
* @return The node with which we swapped.
*/
private N swapWithSuccessor() {
@@ -458,7 +484,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
isRed = oldReplacementIsRed;
left = oldReplacementLeft;
right = oldReplacementRight;
@@ -575,7 +601,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Removes this node from the tree that contains it. The effect of this method on the fields of this node is
* unspecified. This method assumes that this is not a leaf node. This method is more efficient than remove() if
* augment() might return false.
*
* <p>
* If the node has two children, we begin by moving the node's successor to its former position, by changing the
* successor's "left", "right", "parent", and isRed fields.
*/
@@ -665,7 +691,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
/**
* Removes this node from the tree that contains it. The effect of this method on the fields of this node is
* unspecified. This method assumes that this is not a leaf node.
*
* <p>
* If the node has two children, we begin by moving the node's successor to its former position, by changing the
* successor's "left", "right", "parent", and isRed fields.
*
@@ -697,13 +723,14 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* "iterator", in iteration order. This method is responsible for setting the "left", "right", "parent", and isRed
* fields of the nodes, and calling augment() as appropriate. It ignores the initial values of the "left", "right",
* "parent", and isRed fields.
*
* @param iterator The nodes.
* @param size The number of nodes.
* @param height The "height" of the subtree's root node above the deepest leaf in the tree that contains it. Since
* insertion fixup is slow if there are too many red nodes and deleteion fixup is slow if there are too few red
* nodes, we compromise and have red nodes at every fourth level. We color a node red iff its "height" is equal
* to 1 mod 4.
* @param leaf The leaf node.
* @param size The number of nodes.
* @param height The "height" of the subtree's root node above the deepest leaf in the tree that contains it. Since
* insertion fixup is slow if there are too many red nodes and deleteion fixup is slow if there are too few red
* nodes, we compromise and have red nodes at every fourth level. We color a node red iff its "height" is equal
* to 1 mod 4.
* @param leaf The leaf node.
* @return The root of the subtree.
*/
private static <N extends RedBlackNode<N>> N createTree(
@@ -735,8 +762,9 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* method is responsible for setting the "left", "right", "parent", and isRed fields of the nodes (excluding
* "leaf"), and calling augment() as appropriate. It ignores the initial values of the "left", "right", "parent",
* and isRed fields.
*
* @param nodes The nodes.
* @param leaf The leaf node.
* @param leaf The leaf node.
* @return The root of the tree.
*/
public static <N extends RedBlackNode<N>> N createTree(Collection<? extends N> nodes, N leaf) {
@@ -762,7 +790,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* all of these nodes. This method destroys the trees rooted at "this" and "last". We treat "pivot" as a solitary
* node that does not belong to any tree, and we ignore its initial "parent", "left", "right", and isRed fields.
* This method assumes that this node and "last" are the roots of their respective trees.
*
* <p>
* This method takes O(log N) time. It is more efficient than inserting "pivot" and then calling concatenate(last).
* It is considerably more efficient than inserting "pivot" and all of the nodes in "last".
*/
@@ -783,7 +811,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
// Compute the black height of the trees
int firstBlackHeight = 0;
@SuppressWarnings("unchecked")
N first = (N)this;
N first = (N) this;
for (N node = first; node != null; node = node.right) {
if (!node.isRed) {
firstBlackHeight++;
@@ -868,7 +896,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
return last;
} else if (last.isLeaf()) {
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
return nThis;
} else {
N node = last.min();
@@ -884,6 +912,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* destructive, meaning it does not preserve the original tree. It assumes that this node is the root and is in the
* same tree as splitNode. It takes O(log N) time. It is considerably more efficient than removing all of the
* nodes at or after splitNode and then creating a new tree from those nodes.
*
* @param The node at which to split the tree.
* @return An array consisting of the resulting trees.
*/
@@ -929,7 +958,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
N first = null;
N firstParent = null;
N last = null;
@@ -1082,7 +1111,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
last.augment();
@SuppressWarnings("unchecked")
N[] result = (N[])Array.newInstance(getClass(), 2);
N[] result = (N[]) Array.newInstance(getClass(), 2);
result[0] = first;
result[1] = last;
return result;
@@ -1092,7 +1121,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Returns the lowest common ancestor of this node and "other" - the node that is an ancestor of both and is not the
* parent of a node that is an ancestor of both. Assumes that this is in the same tree as "other". Assumes that
* neither "this" nor "other" is a leaf node. This method may return "this" or "other".
*
* <p>
* Note that while it is possible to compute the lowest common ancestor in O(P) time, where P is the length of the
* path from this node to "other", the "lca" method is not guaranteed to take O(P) time. If your application
* requires this, then you should write your own lowest common ancestor method.
@@ -1114,7 +1143,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
// Go up to nodes of the same depth
@SuppressWarnings("unchecked")
N parent = (N)this;
N parent = (N) this;
N otherParent = other;
if (depth <= otherDepth) {
for (int i = otherDepth; i > depth; i--) {
@@ -1142,10 +1171,10 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Returns an integer comparing the position of this node in the tree that contains it with that of "other". Returns
* a negative number if this is earlier, a positive number if this is later, and 0 if this is at the same position.
* Assumes that this is in the same tree as "other". Assumes that neither "this" nor "other" is a leaf node.
*
* <p>
* The base class's implementation takes O(log N) time. If a RedBlackNode subclass stores a value used to order the
* nodes, then it could override compareTo to compare the nodes' values, which would take O(1) time.
*
* <p>
* Note that while it is possible to compare the positions of two nodes in O(P) time, where P is the length of the
* path from this node to "other", the default implementation of compareTo is not guaranteed to take O(P) time. If
* your application requires this, then you should write your own comparison method.
@@ -1224,7 +1253,9 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
}
/** Throws a RuntimeException if the RedBlackNode fields of this are not correct for a leaf node. */
/**
* Throws a RuntimeException if the RedBlackNode fields of this are not correct for a leaf node.
*/
private void assertIsValidLeaf() {
if (left != null || right != null || parent != null || isRed) {
throw new RuntimeException("A leaf node's \"left\", \"right\", \"parent\", or isRed field is incorrect");
@@ -1234,14 +1265,15 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
/**
* Throws a RuntimeException if the subtree rooted at this node does not satisfy the red-black properties, excluding
* the requirement that the root be black, or it contains a repeated node other than a leaf node.
*
* @param blackHeight The required number of black nodes in each path from this to a leaf node, including this and
* the leaf node.
* @param visited The nodes we have reached thus far, other than leaf nodes. This method adds the non-leaf nodes in
* the subtree rooted at this node to "visited".
* the leaf node.
* @param visited The nodes we have reached thus far, other than leaf nodes. This method adds the non-leaf nodes in
* the subtree rooted at this node to "visited".
*/
private void assertSubtreeIsValidRedBlack(int blackHeight, Set<Reference<N>> visited) {
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
if (left == null || right == null) {
assertIsValidLeaf();
if (blackHeight != 1) {
@@ -1276,7 +1308,9 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
}
}
/** Calls assertNodeIsValid() on every node in the subtree rooted at this node. */
/**
* Calls assertNodeIsValid() on every node in the subtree rooted at this node.
*/
private void assertNodesAreValid() {
assertNodeIsValid();
if (left != null) {
@@ -1304,7 +1338,7 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
Set<Reference<N>> nodes = new HashSet<Reference<N>>();
int blackHeight = 0;
@SuppressWarnings("unchecked")
N node = (N)this;
N node = (N) this;
while (node != null) {
if (!nodes.add(new Reference<N>(node))) {
throw new RuntimeException("The tree contains a repeated non-leaf node");
@@ -1333,14 +1367,15 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Throws a RuntimeException if the nodes in the subtree rooted at this node are not in the specified order or they
* do not lie in the specified range. Assumes that the subtree rooted at this node is a valid binary tree, i.e. it
* has no repeated nodes other than leaf nodes.
*
* @param comparator A comparator indicating how the nodes should be ordered.
* @param start The lower limit for nodes in the subtree, if any.
* @param end The upper limit for nodes in the subtree, if any.
* @param start The lower limit for nodes in the subtree, if any.
* @param end The upper limit for nodes in the subtree, if any.
*/
private void assertOrderIsValid(Comparator<? super N> comparator, N start, N end) {
if (!isLeaf()) {
@SuppressWarnings("unchecked")
N nThis = (N)this;
N nThis = (N) this;
if (start != null && comparator.compare(nThis, start) < 0) {
throw new RuntimeException("The nodes are not ordered correctly");
}
@@ -1359,8 +1394,9 @@ public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Compara
* Assumes that this is a valid binary tree, i.e. there are no repeated nodes other than leaf nodes. This method is
* useful for debugging. RedBlackNode subclasses may want to override assertSubtreeIsValid() to call
* assertOrderIsValid.
*
* @param comparator A comparator indicating how the nodes should be ordered. If this is null, we use the nodes'
* natural order, as in N.compareTo.
* natural order, as in N.compareTo.
*/
public void assertOrderIsValid(Comparator<? super N> comparator) {
if (comparator == null) {

View File

@@ -5,10 +5,13 @@ package com.github.btrekkie.red_black_node;
/**
* Wraps a value using reference equality. In other words, two references are equal only if their values are the same
* object instance, as in ==.
*
* @param <T> The type of value.
*/
class Reference<T> {
/** The value this wraps. */
/**
* The value this wraps.
*/
private final T value;
public Reference(T value) {
@@ -19,7 +22,7 @@ class Reference<T> {
if (!(obj instanceof Reference)) {
return false;
}
Reference<?> reference = (Reference<?>)obj;
Reference<?> reference = (Reference<?>) obj;
return value == reference.value;
}

View File

@@ -11,7 +11,9 @@ import java.util.Comparator;
/* We implement an ArbitraryOrderCollection using a red-black tree. We order the nodes arbitrarily.
*/
public class ArbitraryOrderCollection {
/** The Comparator for ordering ArbitraryOrderNodes. */
/**
* The Comparator for ordering ArbitraryOrderNodes.
*/
private static final Comparator<ArbitraryOrderNode> NODE_COMPARATOR = new Comparator<ArbitraryOrderNode>() {
@Override
public int compare(ArbitraryOrderNode node1, ArbitraryOrderNode node2) {
@@ -19,10 +21,14 @@ public class ArbitraryOrderCollection {
}
};
/** The root node of the tree. */
/**
* The root node of the tree.
*/
private ArbitraryOrderNode root = new ArbitraryOrderNode();
/** Adds and returns a new value for ordering. */
/**
* Adds and returns a new value for ordering.
*/
public ArbitraryOrderValue createValue() {
ArbitraryOrderNode node = new ArbitraryOrderNode();
root = root.insert(node, true, NODE_COMPARATOR);

View File

@@ -2,7 +2,9 @@ package com.github.btrekkie.arbitrary_order_collection;
import com.github.btrekkie.red_black_node.RedBlackNode;
/** A node in an ArbitraryOrderCollection tree. See ArbitraryOrderCollection. */
/**
* A node in an ArbitraryOrderCollection tree. See ArbitraryOrderCollection.
*/
class ArbitraryOrderNode extends RedBlackNode<ArbitraryOrderNode> {
}

View File

@@ -5,7 +5,9 @@ package com.github.btrekkie.arbitrary_order_collection;
* compareTo.
*/
public class ArbitraryOrderValue implements Comparable<ArbitraryOrderValue> {
/** The node that establishes this value's relative position. */
/**
* The node that establishes this value's relative position.
*/
final ArbitraryOrderNode node;
ArbitraryOrderValue(ArbitraryOrderNode node) {

View File

@@ -1,19 +1,20 @@
package com.github.btrekkie.arbitrary_order_collection.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.github.btrekkie.arbitrary_order_collection.ArbitraryOrderCollection;
import com.github.btrekkie.arbitrary_order_collection.ArbitraryOrderValue;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import com.github.btrekkie.arbitrary_order_collection.ArbitraryOrderCollection;
import com.github.btrekkie.arbitrary_order_collection.ArbitraryOrderValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ArbitraryOrderCollectionTest {
/** Tests ArbitraryOrderCollection. */
/**
* Tests ArbitraryOrderCollection.
*/
@Test
public void test() {
ArbitraryOrderCollection collection = new ArbitraryOrderCollection();

View File

@@ -2,14 +2,18 @@ package com.github.btrekkie.connectivity.test;
import com.github.btrekkie.connectivity.Augmentation;
/** Stores two values: a sum and a maximum. Used for testing augmentation in ConnGraph. */
/**
* Stores two values: a sum and a maximum. Used for testing augmentation in ConnGraph.
*/
class SumAndMax {
/** An Augmentation that combines two SumAndMaxes into one. */
/**
* An Augmentation that combines two SumAndMaxes into one.
*/
public static final Augmentation AUGMENTATION = new Augmentation() {
@Override
public Object combine(Object value1, Object value2) {
SumAndMax sumAndMax1 = (SumAndMax)value1;
SumAndMax sumAndMax2 = (SumAndMax)value2;
SumAndMax sumAndMax1 = (SumAndMax) value1;
SumAndMax sumAndMax2 = (SumAndMax) value2;
return new SumAndMax(sumAndMax1.sum + sumAndMax2.sum, Math.max(sumAndMax1.max, sumAndMax2.max));
}
};
@@ -28,7 +32,7 @@ class SumAndMax {
if (!(obj instanceof SumAndMax)) {
return false;
}
SumAndMax sumAndMax = (SumAndMax)obj;
SumAndMax sumAndMax = (SumAndMax) obj;
return sum == sumAndMax.sum && max == sumAndMax.max;
}

View File

@@ -8,16 +8,21 @@ package com.github.btrekkie.interval_tree;
* interval. Each node is augmented with the maximum ending value of an interval in the subtree rooted at the node.
*/
public class IntervalTree {
/** The root node of the tree. */
/**
* The root node of the tree.
*/
private IntervalTreeNode root = IntervalTreeNode.LEAF;
/** Adds the specified interval to this. */
/**
* Adds the specified interval to this.
*/
public void addInterval(IntervalTreeInterval interval) {
root = root.insert(new IntervalTreeNode(interval), true, null);
}
/**
* Removes the specified interval from this, if it is present.
*
* @param interval The interval.
* @return Whether the interval was present.
*/

View File

@@ -4,10 +4,14 @@ package com.github.btrekkie.interval_tree;
* An inclusive range of values [start, end]. Two intervals are equal if they have the same starting and ending values.
*/
public class IntervalTreeInterval {
/** The smallest value in the range. */
/**
* The smallest value in the range.
*/
public final double start;
/** The largest value in the range. */
/**
* The largest value in the range.
*/
public final double end;
public IntervalTreeInterval(double start, double end) {
@@ -22,7 +26,7 @@ public class IntervalTreeInterval {
if (!(obj instanceof IntervalTreeInterval)) {
return false;
}
IntervalTreeInterval interval = (IntervalTreeInterval)obj;
IntervalTreeInterval interval = (IntervalTreeInterval) obj;
return start == interval.start && end == interval.end;
}
}

View File

@@ -7,13 +7,19 @@ import com.github.btrekkie.red_black_node.RedBlackNode;
* nodes as suggested in the comments for the implementation of IntervalTree.
*/
class IntervalTreeNode extends RedBlackNode<IntervalTreeNode> {
/** The dummy leaf node. */
/**
* The dummy leaf node.
*/
public static final IntervalTreeNode LEAF = new IntervalTreeNode();
/** The interval stored in this node. */
/**
* The interval stored in this node.
*/
public IntervalTreeInterval interval;
/** The maximum ending value of an interval in the subtree rooted at this node. */
/**
* The maximum ending value of an interval in the subtree rooted at this node.
*/
public double maxEnd;
public IntervalTreeNode(IntervalTreeInterval interval) {
@@ -21,7 +27,9 @@ class IntervalTreeNode extends RedBlackNode<IntervalTreeNode> {
maxEnd = interval.end;
}
/** Constructs a new dummy leaf node. */
/**
* Constructs a new dummy leaf node.
*/
private IntervalTreeNode() {
interval = null;
maxEnd = Double.NEGATIVE_INFINITY;

View File

@@ -1,17 +1,15 @@
package com.github.btrekkie.interval_tree.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import com.github.btrekkie.interval_tree.IntervalTree;
import com.github.btrekkie.interval_tree.IntervalTreeInterval;
import org.junit.Test;
import static org.junit.Assert.*;
public class IntervalTreeTest {
/** Tests IntervalTree. */
/**
* Tests IntervalTree.
*/
@Test
public void test() {
IntervalTree tree = new IntervalTree();

View File

@@ -1,11 +1,11 @@
package com.github.btrekkie.red_black_node.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.util.Comparator;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Tests RedBlackNode. Most of the testing for RedBlackNode takes place in TreeListTest, IntervalTreeTest,
@@ -30,8 +30,9 @@ public class RedBlackNodeTest {
/**
* Returns whether the nodes in the subtree rooted at the specified node are ordered correctly, as in
* TestRedBlackNode.assertOrderIsValid.
*
* @param comparator A comparator indicating how the nodes should be ordered. If this is null, we use the nodes'
* natural ordering, as in TestRedBlackNode.compare.
* natural ordering, as in TestRedBlackNode.compare.
*/
private boolean isOrderValid(TestRedBlackNode node, Comparator<TestRedBlackNode> comparator) {
try {
@@ -42,7 +43,9 @@ public class RedBlackNodeTest {
}
}
/** Tests RedBlackNode.assertSubtreeIsValid() and RedBlackNode.assertOrderIsValid. */
/**
* Tests RedBlackNode.assertSubtreeIsValid() and RedBlackNode.assertOrderIsValid.
*/
@Test
public void testAssertIsValid() {
// Create a perfectly balanced tree of height 3
@@ -129,12 +132,12 @@ public class RedBlackNodeTest {
node2.value = 3;
assertFalse(isOrderValid(node3, null));
assertFalse(
isOrderValid(node3, new Comparator<TestRedBlackNode>() {
@Override
public int compare(TestRedBlackNode node1, TestRedBlackNode node2) {
return node1.value - node2.value;
}
}));
isOrderValid(node3, new Comparator<TestRedBlackNode>() {
@Override
public int compare(TestRedBlackNode node1, TestRedBlackNode node2) {
return node1.value - node2.value;
}
}));
node3.value = 3;
node2.value = 2;
@@ -161,11 +164,11 @@ public class RedBlackNodeTest {
assertTrue(isOrderValid(node0, null));
assertTrue(isOrderValid(TestRedBlackNode.LEAF, null));
assertTrue(
isOrderValid(node3, new Comparator<TestRedBlackNode>() {
@Override
public int compare(TestRedBlackNode node1, TestRedBlackNode node2) {
return node1.value - node2.value;
}
}));
isOrderValid(node3, new Comparator<TestRedBlackNode>() {
@Override
public int compare(TestRedBlackNode node1, TestRedBlackNode node2) {
return node1.value - node2.value;
}
}));
}
}

View File

@@ -2,22 +2,32 @@ package com.github.btrekkie.red_black_node.test;
import com.github.btrekkie.red_black_node.RedBlackNode;
/** A RedBlackNode for RedBlackNodeTest. */
/**
* A RedBlackNode for RedBlackNodeTest.
*/
class TestRedBlackNode extends RedBlackNode<TestRedBlackNode> {
/** The dummy leaf node. */
/**
* The dummy leaf node.
*/
public static final TestRedBlackNode LEAF = new TestRedBlackNode();
/** The value stored in this node. "value" is unspecified if this is a leaf node. */
/**
* The value stored in this node. "value" is unspecified if this is a leaf node.
*/
public int value;
/** Whether this node is considered valid, as in assertNodeIsValid(). */
/**
* Whether this node is considered valid, as in assertNodeIsValid().
*/
public boolean isValid = true;
public TestRedBlackNode(int value) {
this.value = value;
}
/** Constructs a new dummy leaf node. */
/**
* Constructs a new dummy leaf node.
*/
private TestRedBlackNode() {
}

View File

@@ -1,14 +1,20 @@
package com.github.btrekkie.sub_array_min;
/** A list of integers. SubArrayMin provides the ability to quickly determine the minimum value in a given sublist. */
/**
* A list of integers. SubArrayMin provides the ability to quickly determine the minimum value in a given sublist.
*/
/* We implement SubArrayMin using a red-black tree augmented by subtree size and minimum value. Using the subtree size
* augmentation, we can find the node at a given index.
*/
public class SubArrayMin {
/** The root node. */
/**
* The root node.
*/
private SubArrayMinNode root = SubArrayMinNode.LEAF;
/** Appends the specified value to the end of the list. */
/**
* Appends the specified value to the end of the list.
*/
public void add(int value) {
SubArrayMinNode newNode = new SubArrayMinNode(value);
newNode.left = SubArrayMinNode.LEAF;
@@ -25,7 +31,9 @@ public class SubArrayMin {
}
}
/** Returns the node for the element with the specified index. Assumes "index" is in the range [0, root.size). */
/**
* Returns the node for the element with the specified index. Assumes "index" is in the range [0, root.size).
*/
private SubArrayMinNode getNode(int index) {
if (index < 0 || index >= root.size) {
throw new IndexOutOfBoundsException("Index " + index + " is not in the range [0, " + root.size + ")");

View File

@@ -2,18 +2,28 @@ package com.github.btrekkie.sub_array_min;
import com.github.btrekkie.red_black_node.RedBlackNode;
/** A node in a SubArrayMin object. See the comments for the implementation of that class. */
/**
* A node in a SubArrayMin object. See the comments for the implementation of that class.
*/
class SubArrayMinNode extends RedBlackNode<SubArrayMinNode> {
/** The dummy leaf node. */
/**
* The dummy leaf node.
*/
public static final SubArrayMinNode LEAF = new SubArrayMinNode();
/** The element stored in the node. The value is unspecified if this is a leaf node. */
/**
* The element stored in the node. The value is unspecified if this is a leaf node.
*/
public final int value;
/** The number of elements in the subtree rooted at this node. */
/**
* The number of elements in the subtree rooted at this node.
*/
public int size;
/** The minimum element in the subtree rooted at this node. This is Integer.MAX_VALUE if this is a leaf node. */
/**
* The minimum element in the subtree rooted at this node. This is Integer.MAX_VALUE if this is a leaf node.
*/
public int min;
public SubArrayMinNode(int value) {

View File

@@ -1,13 +1,14 @@
package com.github.btrekkie.sub_array_min.test;
import com.github.btrekkie.sub_array_min.SubArrayMin;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.github.btrekkie.sub_array_min.SubArrayMin;
public class SubArrayMinTest {
/** Tests SubArrayMin. */
/**
* Tests SubArrayMin.
*/
@Test
public void test() {
SubArrayMin sam = new SubArrayMin();