/*
* Kodkod -- Copyright (c) 2005-present, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.util.ints;
/**
* A tree with integer keys.
*
* @specfield root: lone N
* @specfield nodes: root.*(left + right)
* @author Emina Torlak
*/
final class IntTree<N extends IntTree.Node<N>> implements Cloneable {
private static final boolean BLACK = true, RED = false;
private N root;
/**
* Creates an empty IntTree.
* @ensures no this.root'
*/
IntTree() {
root = null;
}
/**
* Discards all elements from this tree.
* @ensures no this.root'
**/
final void clear() {
root = null;
}
/**
* Returns the node with the given key, or null no such node exists.
* @return this.nodes & key.index
*/
final N search(int k) {
N node = root;
while(node != null) {
if (node.key==k) break;
else if (node.key>k) node = node.left;
else node = node.right;
}
return node;
}
/**
* Returns the node whose key is the ceiling of <tt>k</tt> in this tree, or
* null if no such node exists.
* @return {n: this.nodes | n.key >= k &&
* no n': this.nodes - n | n'.key >= k && n'.key < n.key }
*/
final N searchGTE(int k) {
if (root==null) return null;
N c = root;
while (true) {
if (c.key==k) {
return c;
} else if (c.key>k) {
if (c.left != null)
c = c.left;
else
return c;
} else {
if (c.right != null)
c = c.right;
else
return successor(c);
}
}
}
/**
* Returns the node whose key is the floor of <tt>k</tt> in this tree, or
* null if no such node exists.
* @return {n: this.nodes | n.key <= k &&
* no n': this.nodes - n | n'.key <= k && n'.key > n.key }
*/
final N searchLTE(int k) {
if (root==null) return null;
N f = root;
while(true) {
if (f.key==k)
return f;
else if (f.key>k) {
if (f.left != null)
f = f.left;
else
return predecessor(f);
} else {
if (f.right != null)
f = f.right;
else
return f;
}
}
}
/**
* Implementation of the tree-predecessor algorithm from CLR.
* Returns the given node's predecessor, if it exists.
* Otherwise returns null.
* @return the given node's predecessor
* @throws NullPointerException node = null
*/
final N predecessor(N node) {
if (node.left != null) {
return max(node.left);
} else {
N n = node;
N ancestor = n.parent;
while (ancestor != null && n == ancestor.left) {
n = ancestor;
ancestor = ancestor.parent;
}
return ancestor;
}
}
/**
* Implementation of the tree-successor algorithm from CLR.
* Returns the given node's successor, if it exists.
* Otherwise returns null.
* @return the given node's successor
* @throws NullPointerException node = null
*/
final N successor(N node) {
if (node.right != null) {
return min(node.right);
} else {
N n = node;
N ancestor = n.parent;
while (ancestor != null && n == ancestor.right) {
n = ancestor;
ancestor = ancestor.parent;
}
return ancestor;
}
}
/**
* Returns the node with the smallest key.
* @return key.(min(this.nodes.key))
*/
final N min() {
return min(root);
}
/**
* Returns the node with the largest key.
* @return key.(max(this.nodes.key))
*/
final N max() {
return max(root);
}
/**
* Returns the leftmost node in the subtree rooted at start.
* The behavior of this method is unspecified if the given node
* is not in this tree.
* @requires node in this.nodes
* @return {n: start.*left | no n.left }
*/
private final N min(N start) {
if (start != null) {
while(start.left != null) {
start = start.left;
}
}
return start;
}
/**
* Returns the rightmost in the subtree rooted at start.
* The behavior of this method is unspecified if the given node
* is not in this tree.
* @requires node in this.nodes
* @return {n: start.*left | no n.right }
*/
private final N max(N start) {
if (start != null) {
while(start.right != null) {
start = start.right;
}
}
return start;
}
/**
* Replaces the old node, o, with the given new node, n, in this tree.
* @requires no n.(left + right + parent)
* @requires o = o.parent.left => n.key < o.parent.key
* @requires o = o.parent.right => n.key > o.parent.key
* @requires some o.left => n.key > o.left.key
* @requires some o.right => n.key < o.right.key
* @ensures this.nodes' = this.nodes - o + n
* @ensures o.parent' = o.left' = o.right' = null
*/
final void replace(N o, N n) {
n.color = o.color;
n.parent = o.parent;
n.left = o.left;
n.right = o.right;
if (o.left != null) { o.left.parent = n; }
if (o.right != null) { o.right.parent = n; }
if (o.parent == null) { root = n; }
else if (o == o.parent.left) { o.parent.left = n; }
else { o.parent.right = n; }
o.parent = o.left = o.right = null;
}
private final N parentOf(N n) { return n==null ? null : n.parent; }
private final N leftOf(N n) { return n==null ? null : n.left; }
private final N rightOf(N n) { return n==null ? null : n.right; }
private final boolean colorOf(N n) { return n==null ? BLACK : n.color; }
private final void setColor(N n, boolean color) { if (n!=null) n.color = color; }
/**
* Implementation of the CLR insertion algorithm.
* @requires no z.key & this.nodes.key
* @ensures this.nodes' = this.nodes + z
*/
final void insert(N z) {
N y = null;
for (N x = root; x != null;) {
y = x;
if (x.key>z.key)
x = x.left;
else
x = x.right;
}
z.parent = y;
z.left = z.right = null;
if (y==null) {
root = z;
} else {
z.color = RED;
if (y.key>z.key) { y.left = z; }
else { y.right = z; }
insertFixUp(z);
}
}
/**
* A slightly modified implementation of the CLR deletion algorithm.
* @requires z in this.nodes
* @ensures this.nodes' = this.nodes - z
*/
final void delete(N z) {
N y = (z.left==null || z.right==null ? z : successor(z));
N x = (y.left != null ? y.left : y.right);
N yparent = y.parent;
final boolean yleft = (y==leftOf(y.parent));
final boolean ycolor = y.color;
if (x!=null) { x.parent = yparent; }
if (yparent == null) { root = x; }
else if (yleft) { yparent.left = x; }
else { yparent.right = x; }
if (y != z) { replace(z, y); }
if (ycolor==BLACK) {
if (x!=null) {
deleteFixUp(x);
} else if (yparent!=null) { // z is not the only node
if (z==yparent) yparent = y; // y, z's successor, is z's right child
z.color = BLACK;
z.left = z.right = null;
z.parent = yparent;
if (yleft) { yparent.left = z; }
else { yparent.right = z; }
deleteFixUp(z);
if (z==z.parent.left) { z.parent.left = null; }
else { z.parent.right = null; }
}
}
z.left = z.right = z.parent = null; // cut z out of the tree by nulling out its pointers
}
/**
* {@inheritDoc}
* @see java.lang.Object#clone()
* @throws CloneNotSupportedException nodes contained in this tree are not cloneable
*/
@SuppressWarnings("unchecked")
protected IntTree<N> clone() throws CloneNotSupportedException {
final IntTree<N> ret = (IntTree<N>) super.clone();
ret.root = clone(root, null);
return ret;
}
/**
* Recursively clones the given node.
*/
@SuppressWarnings("unchecked")
private N clone(N n, N parent) throws CloneNotSupportedException {
if (n==null) return null;
N clone = (N) n.clone();
clone.parent = parent;
clone.left = clone(n.left, clone);
clone.right = clone(n.right, clone);
return clone;
}
/*---------balancing operations (CLR, pp.278-289)---------*/
/**
* From CLR.
*/
private void insertFixUp(N z) {
while (z != null && z != root && z.parent.color == RED) {
if (parentOf(z) == leftOf(parentOf(parentOf(z)))) {
N y = rightOf(parentOf(parentOf(z)));
if (colorOf(y) == RED) {
setColor(parentOf(z), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(z)), RED);
z = parentOf(parentOf(z));
} else {
if (z == rightOf(parentOf(z))) {
z = parentOf(z);
rotateLeft(z);
}
setColor(parentOf(z), BLACK);
setColor(parentOf(parentOf(z)), RED);
if (parentOf(parentOf(z)) != null)
rotateRight(parentOf(parentOf(z)));
}
} else {
N y = leftOf(parentOf(parentOf(z)));
if (colorOf(y) == RED) {
setColor(parentOf(z), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(z)), RED);
z = parentOf(parentOf(z));
} else {
if (z == leftOf(parentOf(z))) {
z = parentOf(z);
rotateRight(z);
}
setColor(parentOf(z), BLACK);
setColor(parentOf(parentOf(z)), RED);
if (parentOf(parentOf(z)) != null)
rotateLeft(parentOf(parentOf(z)));
}
}
}
root.color = BLACK;
}
/**
* From CLR.
*/
private void deleteFixUp(N x) {
while (x != root && colorOf(x) == BLACK) {
if (x == leftOf(parentOf(x))) {
N sib = rightOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
sib = rightOf(parentOf(x));
}
if (colorOf(leftOf(sib)) == BLACK &&
colorOf(rightOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(rightOf(sib)) == BLACK) {
setColor(leftOf(sib), BLACK);
setColor(sib, RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(rightOf(sib), BLACK);
rotateLeft(parentOf(x));
x = root;
}
} else { // symmetric
N sib = leftOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
if (colorOf(rightOf(sib)) == BLACK &&
colorOf(leftOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(leftOf(sib)) == BLACK) {
setColor(rightOf(sib), BLACK);
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
setColor(x, BLACK);
}
/**
* From CLR.
*/
private void rotateLeft(N x) {
N y = x.right;
x.right = y.left;
if (y.left != null)
y.left.parent = x;
y.parent = x.parent;
if (x.parent == null)
root = y;
else if (x.parent.left == x)
x.parent.left = y;
else
x.parent.right = y;
y.left = x;
x.parent = y;
}
/**
* From CLR.
*/
private void rotateRight(N x) {
N y = x.left;
x.left = y.right;
if (y.right != null)
y.right.parent = x;
y.parent = x.parent;
if (x.parent == null)
root = y;
else if (x.parent.right == x)
x.parent.right = y;
else
x.parent.left = y;
y.right = x;
x.parent = y;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return root.toString();
}
/**
* A node in an int tree. Subclasses need to
* implement the clone method iff IntTree.clone will
* be called on the tree containing the nodes.
* @specfield key: int
* @specfield parent: lone N
* @specfield left: lone N
* @specfield right: lone N
* @author Emina Torlak
*/
abstract static class Node<N extends Node<N>> implements Cloneable {
N parent, left, right;
boolean color;
/**
* Subclasses are required to maintain the following invariant:
* @invariant this = this.parent.left => this.key < this.parent.key &&
* this = this.parent.right => this.key > this.parent.key &&
* some this.left => this.key > this.left.key &&
* some this.right => this.key < this.right.key
*/
protected int key;
/**
* Constructs an empty node with the given key.
* @ensures no this.(parent' + left' + right') && this.key' = key
*/
Node(int key) {
this.parent = this.left = this.right = null;
this.color = BLACK;
this.key = key;
}
/**
* Returns the left child of this node.
* @return this.left
*/
final N left() { return left; }
/**
* Returns the right child of this node.
* @return this.right
*/
final N right() { return right; }
/**
* Return the parent of this node.
* @return this.parent
*/
final N parent() { return parent; }
/**
* Clones this node. Subclasses must override
* this method (and call super.clone()) in order
* for IntTree.clone() to function properly.
* @throws CloneNotSupportedException
* @see java.lang.Object#clone()
*/
@SuppressWarnings("unchecked")
protected Node<N> clone() throws CloneNotSupportedException {
Node<N> ret = (Node<N>) super.clone();
ret.parent = ret.left = ret.right = null;
return ret;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return "[" + key + " " + (color ? "b" : "r") + " " + (left==this ? key : left) + " "+
(right==this ? key : right) + "]";
}
}
}