2-3ツリーのjava実現
33924 ワード
点の定義
package TwoThreeTree;
class Node {
private Node parent;
private Node leftChild;
private Node rightChild;
private Node middleChild;
// When node is 2-node, leftVal is the values, and rightVal is null.
private T leftVal;
private T rightVal;
private boolean twoNode;
protected Node() {
}
public static Node newTwoNode(T value) {
Node node = new Node();
node.leftVal = value;
node.twoNode = true;
return node;
}
public static Node newThreeNode(T leftVal, T rightVal) {
Node node = new Node();
if (leftVal.compareTo(rightVal) > 0) {
node.rightVal = leftVal;
node.leftVal = rightVal;
} else {
node.leftVal = leftVal;
node.rightVal = rightVal;
}
node.twoNode = false;
return node;
}
public static HoleNode newHole() {
return new HoleNode();
}
public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
if (leftChild != null)
leftChild.setParent(this);
}
public void removeChildren() {
this.leftChild = null;
this.rightChild = null;
}
public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
if (rightChild != null)
rightChild.setParent(this);
}
public void setMiddleChild(Node middleChild) {
assert isThreeNode();
this.middleChild = middleChild;
if (middleChild != null) {
middleChild.setParent(this);
}
}
public final Node parent() {
return parent;
}
public final void setParent(Node parent) {
this.parent = parent;
}
public boolean isTerminal() {
return leftChild == null && rightChild == null;
}
public T val() {
assert isTwoNode();
return leftVal;
}
public T leftVal() {
assert isThreeNode();
return leftVal;
}
public void setVal(T val) {
assert isTwoNode();
leftVal = val;
}
public T rightVal() {
assert isThreeNode();
return rightVal;
}
public void setLeftVal(T leftVal) {
assert isThreeNode();
this.leftVal = leftVal;
}
public void setRightVal(T rightVal) {
assert isThreeNode();
this.rightVal = rightVal;
}
public boolean isTwoNode() {
// return rightVal == null;
return twoNode;
}
public boolean isThreeNode() {
return !isTwoNode();
}
public Node leftChild() {
return leftChild;
}
public Node rightChild() {
return rightChild;
}
public Node middleChild() {
assert isThreeNode();
return middleChild;
}
@SuppressWarnings("unchecked")
public void replaceChild(Node currentChild, Node newChild) {
if (currentChild == leftChild) {
leftChild = newChild;
} else if (currentChild == rightChild) {
rightChild = newChild;
} else {
assert middleChild == currentChild;
middleChild = newChild;
}
newChild.setParent(this);
currentChild.setParent(null);
}
}
空のポイントの定義package TwoThreeTree;
/**
* A hole node does not have any values, and have only one child.
*/
final class HoleNode extends Node {
private Node child;
HoleNode() {
super();
}
public boolean isTwoNode() {
return false;
}
public Node sibling() {
if (parent() != null) {
return parent().leftChild() == this ? parent().rightChild(): parent().leftChild();
}
return null;
}
@Override
public void setLeftChild(Node leftChild) {
}
@Override
public void removeChildren() {
child = null;
}
@Override
public void setRightChild(Node rightChild) {
}
public Node child() {
return child;
}
public void setChild(Node child) {
this.child = child;
}
}
2-3ツリー実現/**
* A 2-3 tree is a balanced search tree where each node can have either two children and one value (2-node),
* or three children and two values (3-node).
*
* References:
* http://scienceblogs.com/goodmath/2009/03/two-three_trees_a_different_ap.php
* http://cs.wellesley.edu/~cs230/spring07/2-3-trees.pdf
*
*
* Author: Sergejs Melderis ([email protected])
*/
package TwoThreeTree;
import java.util.*;
@SuppressWarnings("unchecked")
public class TwoTreeTree extends AbstractSet implements SortedSet {
Node root;
int size = 0;
public boolean add(T value) {
if (root == null)
root = Node.newTwoNode(value);
else {
try {
Node result = insert(value, root);
if (result != null) {
root = result;
}
} catch (DuplicateException e) {
return false;
}
}
size ++;
return true;
}
public boolean contains(T value) {
return findNode(root, value) != null;
}
private Node findNode(Node node, T value) {
if (node == null) return null;
if (node.isThreeNode()) {
int leftComp = value.compareTo(node.leftVal());
int rightComp = value.compareTo(node.rightVal());
if (leftComp == 0 || rightComp == 0) {
return node;
}
if (leftComp < 0) {
return findNode(node.leftChild(), value);
} else if (rightComp < 0) {
return findNode(node.middleChild(), value);
} else {
return findNode(node.rightChild(), value);
}
} else {
int comp = value.compareTo(node.val());
if (comp == 0)
return node;
if (comp < 0)
return findNode(node.leftChild(), value);
else
return findNode(node.rightChild(), value);
}
}
private static final class DuplicateException extends RuntimeException {};
private static final DuplicateException DUPLICATE = new DuplicateException();
private Node insert(T value, Node node) throws DuplicateException {
Node returnValue = null;
if (node.isTwoNode()) {
int comp = value.compareTo(node.val());
if (node.isTerminal()) {
if (comp == 0)
throw DUPLICATE;
Node thnode = Node.newThreeNode(value, node.val());
Node parent = node.parent();
if (parent != null)
parent.replaceChild(node, thnode);
else
root = thnode;
} else {
if (comp < 0) {
Node result = insert(value, node.leftChild());
if (result != null) {
Node threeNode = Node.newThreeNode(result.val(), node.val());
threeNode.setRightChild(node.rightChild());
threeNode.setMiddleChild(result.rightChild());
threeNode.setLeftChild(result.leftChild());
if (node.parent() != null) {
node.parent().replaceChild(node, threeNode);
} else {
root = threeNode;
}
unlinkNode(node);
}
} else if (comp > 0) {
Node result = insert(value, node.rightChild());
if (result != null) {
Node threeNode = Node.newThreeNode(result.val(), node.val());
threeNode.setLeftChild(node.leftChild());
threeNode.setMiddleChild(result.leftChild());
threeNode.setRightChild(result.rightChild());
if (node.parent() != null) {
node.parent().replaceChild(node, threeNode);
} else {
root = threeNode;
}
unlinkNode(node);
}
} else {
throw DUPLICATE;
}
}
} else { // three node
Node threeNode = node;
int leftComp = value.compareTo(threeNode.leftVal());
int rightComp = value.compareTo(threeNode.rightVal());
if (leftComp == 0 || rightComp == 0) {
throw DUPLICATE;
}
if (threeNode.isTerminal()) {
returnValue = splitNode(threeNode, value);
} else {
if (leftComp < 0) {
Node result = insert(value, threeNode.leftChild());
if (result != null) {
returnValue = splitNode(threeNode, result.val());
returnValue.leftChild().setLeftChild(result.leftChild());
returnValue.leftChild().setRightChild(result.rightChild());
returnValue.rightChild().setLeftChild(threeNode.middleChild());
returnValue.rightChild().setRightChild((threeNode.rightChild()));
unlinkNode(threeNode);
}
} else if (rightComp < 0) {
Node result = insert(value, threeNode.middleChild());
if (result != null) {
returnValue = splitNode(threeNode, result.val());
returnValue.leftChild().setLeftChild(threeNode.leftChild());
returnValue.leftChild().setRightChild(result.leftChild());
returnValue.rightChild().setLeftChild(result.rightChild());
returnValue.rightChild().setRightChild(threeNode.rightChild());
unlinkNode(threeNode);
}
} else {
Node result = insert(value, threeNode.rightChild());
if (result != null) {
returnValue = splitNode(threeNode, result.val());
returnValue.leftChild().setLeftChild(threeNode.leftChild());
returnValue.leftChild().setRightChild(threeNode.middleChild());
returnValue.rightChild().setLeftChild(result.leftChild());
returnValue.rightChild().setRightChild(result.rightChild());
unlinkNode(threeNode);
}
}
}
}
return returnValue;
}
public boolean remove(T value) {
if (value == null)
return false;
// System.out.println("removing " + value);
Node node = findNode(root, value);
if (node == null)
return false;
HoleNode hole = null;
Node terminalNode;
T holeValue;
if (node.isTerminal()) {
terminalNode = node;
holeValue = value;
} else {
// Replace by successor.
if (node.isThreeNode()) {
if (node.leftVal().equals(value)) {
Node pred = predecessor(node, value);
holeValue = pred.isThreeNode() ? pred.rightVal() : pred.val();
node.setLeftVal(holeValue);
terminalNode = pred;
} else {
Node succ = successor(node, value);
holeValue = succ.isThreeNode() ? succ.leftVal() : succ.val();
node.setRightVal(holeValue);
terminalNode = succ;
}
} else {
Node succ = successor(node, value);
holeValue = succ.isThreeNode() ? succ.leftVal() : succ.val();
node.setVal(holeValue);
terminalNode = succ;
}
}
assert terminalNode.isTerminal();
if (terminalNode.isThreeNode()) {
// Easy case. Replace 3-node by 2-node
T val = terminalNode.leftVal().equals(holeValue) ? terminalNode.rightVal() : terminalNode.leftVal();
Node twoNode = Node.newTwoNode(val);
if (terminalNode.parent() != null) {
terminalNode.parent().replaceChild(terminalNode, twoNode);
} else {
root = twoNode;
}
} else {
if (terminalNode.parent() != null) {
hole = Node.newHole();
terminalNode.parent().replaceChild(terminalNode, hole);
} else {
root = null;
}
}
// For description of each case see
// "2-3 Tree Deletion: Upward Phase" in http://cs.wellesley.edu/~cs230/spring07/2-3-trees.pdf
while (hole != null) {
// Case 1. The hole has a 2-node as parent and 2-node as sibling.
if (hole.parent().isTwoNode() && hole.sibling().isTwoNode()) {
//System.out.println("Case 1");
Node parent = hole.parent();
Node sibling = hole.sibling();
Node threeNode = Node.newThreeNode(parent.val(), sibling.val());
if (parent.leftChild() == hole) {
threeNode.setLeftChild(hole.child());
threeNode.setMiddleChild(sibling.leftChild());
threeNode.setRightChild(sibling.rightChild());
} else {
threeNode.setLeftChild(sibling.leftChild());
threeNode.setMiddleChild(sibling.rightChild());
threeNode.setRightChild(hole.child());
}
if (parent.parent() == null) {
unlinkNode(hole);
root = threeNode;
hole = null;
} else {
hole.setChild(threeNode);
parent.parent().replaceChild(parent, hole);
}
unlinkNode(parent);
unlinkNode(sibling);
}
// Case 2. The hole has a 2-node as parent and 3-node as sibling.
else if (hole.parent().isTwoNode() && hole.sibling().isThreeNode()) {
//System.out.println("Case 2 ");
Node parent = hole.parent();
Node sibling = hole.sibling();
if (parent.leftChild() == hole) {
Node leftChild = Node.newTwoNode(parent.val());
Node rightChild = Node.newTwoNode(sibling.rightVal());
parent.setVal(sibling.leftVal());
parent.replaceChild(hole, leftChild);
parent.replaceChild(sibling, rightChild);
leftChild.setLeftChild(hole.child());
leftChild.setRightChild(sibling.leftChild());
rightChild.setLeftChild(sibling.middleChild());
rightChild.setRightChild(sibling.rightChild());
} else {
Node leftChild = Node.newTwoNode(sibling.leftVal());
Node rightChild = Node.newTwoNode(parent.val());
parent.setVal(sibling.rightVal());
parent.replaceChild(sibling, leftChild);
parent.replaceChild(hole, rightChild);
leftChild.setLeftChild(sibling.leftChild());
leftChild.setRightChild(sibling.middleChild());
rightChild.setLeftChild(sibling.rightChild());
rightChild.setRightChild(hole.child());
}
unlinkNode(hole);
unlinkNode(sibling);
hole = null;
}
// Case 3. The hole has a 3-node as parent and 2-node as sibling.
else if (hole.parent().isThreeNode()) {
Node parent = hole.parent();
// subcase (a), hole is in the middle
if (parent.middleChild() == hole && parent.leftChild().isTwoNode()) {
//System.out.println("Case 3 (a) hole in the middle");
Node leftChild = parent.leftChild();
Node newParent = Node.newTwoNode(parent.rightVal());
Node newLeftChild = Node.newThreeNode(leftChild.val(), parent.leftVal());
newParent.setLeftChild(newLeftChild);
newParent.setRightChild(parent.rightChild());
if (parent != root) {
parent.parent().replaceChild(parent, newParent);
} else {
root = newParent;
}
newLeftChild.setLeftChild(leftChild.leftChild());
newLeftChild.setMiddleChild(leftChild.rightChild());
newLeftChild.setRightChild(hole.child());
unlinkNode(parent);
unlinkNode(leftChild);
unlinkNode(hole);
hole = null;
}
// subcase (b), hole is in the middle
else if (parent.middleChild() == hole && parent.rightChild().isTwoNode()) {
//System.out.println("Case 3(b) hole in the middle");
Node rightChild = parent.rightChild();
Node newParent = Node.newTwoNode(parent.leftVal());
Node newRightChild = Node.newThreeNode(parent.rightVal(), rightChild.val());
newParent.setLeftChild(parent.leftChild());
newParent.setRightChild(newRightChild);
if (parent != root) {
parent.parent().replaceChild(parent, newParent);
} else {
root = newParent;
}
newRightChild.setLeftChild(hole.child());
newRightChild.setMiddleChild(rightChild.leftChild());
newRightChild.setRightChild(rightChild.rightChild());
unlinkNode(parent);
unlinkNode(rightChild);
unlinkNode(hole);
hole = null;
}
else if (parent.middleChild().isTwoNode()) {
Node middleChild = parent.middleChild();
// subcase (a). hole is the left child.
if (parent.leftChild() == hole) {
//System.out.println("Case 3 (a) hole is left child");
Node newParent = Node.newTwoNode(parent.rightVal());
Node leftChild = Node.newThreeNode(parent.leftVal(), middleChild.val());
newParent.setLeftChild(leftChild);
newParent.setRightChild(parent.rightChild());
if (parent != root) {
parent.parent().replaceChild(parent, newParent);
} else {
root = newParent;
}
leftChild.setLeftChild(hole.child());
leftChild.setMiddleChild(middleChild.leftChild());
leftChild.setRightChild(middleChild.rightChild());
unlinkNode(parent);
unlinkNode(hole);
unlinkNode(middleChild);
hole = null;
}
// subcase (a). hole is the right child.
else if (parent.rightChild() == hole) {
//System.out.println("Case 3 (a) hole is right child");
Node newParent = Node.newTwoNode(parent.leftVal());
Node rightChild = Node.newThreeNode(middleChild.val(), parent.rightVal());
newParent.setRightChild(rightChild);
newParent.setLeftChild(parent.leftChild());
if (parent != root) {
parent.parent().replaceChild(parent, newParent);
} else {
root = newParent;
}
rightChild.setLeftChild(middleChild.leftChild());
rightChild.setMiddleChild(middleChild.rightChild());
rightChild.setRightChild(hole.child());
unlinkNode(parent);
unlinkNode(hole);
unlinkNode(middleChild);
hole = null;
}
}
// Case 4. The hole has a 3-node as parent and 3-node as sibling.
else if (parent.middleChild().isThreeNode()) {
Node middleChild = parent.middleChild();
// subcase (a) hole is the left child
if (hole == parent.leftChild()) {
//System.out.println("Case 4 (a) hole is left child");
Node newLeftChild = Node.newTwoNode(parent.leftVal());
Node newMiddleChild = Node.newTwoNode(middleChild.rightVal());
parent.setLeftVal(middleChild.leftVal());
parent.setLeftChild(newLeftChild);
parent.setMiddleChild(newMiddleChild);
newLeftChild.setLeftChild(hole.child());
newLeftChild.setRightChild(middleChild.leftChild());
newMiddleChild.setLeftChild(middleChild.middleChild());
newMiddleChild.setRightChild(middleChild.rightChild());
unlinkNode(hole);
unlinkNode(middleChild);
hole = null;
}
// subcase (b) hole is the right child
else if (hole == parent.rightChild()) {
// System.out.println("Case 4 (b) hole is right child");
Node newMiddleChild = Node.newTwoNode(middleChild.leftVal());
Node newRightChild = Node.newTwoNode(parent.rightVal());
parent.setRightVal(middleChild.rightVal());
parent.setMiddleChild(newMiddleChild);
parent.setRightChild(newRightChild);
newMiddleChild.setLeftChild(middleChild.leftChild());
newMiddleChild.setRightChild(middleChild.middleChild());
// newMiddleChild.setParent(middleChild.middleChild());
newRightChild.setLeftChild(middleChild.rightChild());
newRightChild.setRightChild(hole.child());
unlinkNode(hole);
unlinkNode(middleChild);
hole = null;
} else if (hole == parent.middleChild() && parent.leftChild().isThreeNode()) {
// System.out.println("Case 4 (a) hole is middle child, left is 3-node");
Node leftChild = parent.leftChild();
Node newLeftChild = Node.newTwoNode(leftChild.leftVal());
Node newMiddleChild = Node.newTwoNode(parent.leftVal());
parent.setLeftVal(leftChild.rightVal());
parent.setLeftChild(newLeftChild);
parent.setMiddleChild(newMiddleChild);
newLeftChild.setLeftChild(leftChild.leftChild());
newLeftChild.setRightChild(leftChild.middleChild());
newMiddleChild.setLeftChild(leftChild.rightChild());
newMiddleChild.setRightChild(hole.child());
unlinkNode(hole);
unlinkNode(leftChild);
hole = null;
} else {
assert (hole == parent.middleChild() && parent.rightChild().isThreeNode());
// System.out.println("Case 4 (b) hole is middle child, right is 3-node");
Node rightChild = parent.rightChild();
Node newRightChild = Node.newTwoNode(rightChild.rightVal());
Node newMiddleChild = Node.newTwoNode(parent.rightVal());
parent.setRightVal(rightChild.leftVal());
parent.setMiddleChild(newMiddleChild);
parent.setRightChild(newRightChild);
newRightChild.setRightChild(rightChild.rightChild());
newRightChild.setLeftChild(rightChild.middleChild());
newMiddleChild.setRightChild(rightChild.leftChild());
newMiddleChild.setLeftChild(hole.child());
unlinkNode(hole);
unlinkNode(rightChild);
hole = null;
}
}
}
}
size--;
return true;
}
private void unlinkNode(Node node) {
node.removeChildren();
node.setParent(null);
}
private Node successor(Node node, T value) {
if (node == null)
return null;
if (!node.isTerminal()) {
Node p;
if (node.isThreeNode() && node.leftVal().equals(value)) {
p = node.middleChild();
} else {
p = node.rightChild();
}
while (p.leftChild() != null) {
p = p.leftChild();
}
return p;
} else {
Node p = node.parent();
if (p == null) return null;
Node ch = node;
while (p != null && ch == p.rightChild()) {
ch = p;
p = p.parent();
}
return p != null ? p : null;
}
}
private Node predecessor(Node node, T value) {
if (node == null)
return null;
Node p;
if (!node.isTerminal()) {
if (node.isThreeNode() && node.rightVal().equals(value)) {
p = node.middleChild();
} else {
p = node.leftChild();
}
while (p.rightChild() != null) {
p = p.rightChild();
}
return p;
} else {
throw new UnsupportedOperationException("Implement predecessor parent is not terminal node");
}
}
private Node splitNode(Node threeNode, T value) {
T min;
T max;
T middle;
if (value.compareTo(threeNode.leftVal()) < 0) {
min = value;
middle = threeNode.leftVal();
max = threeNode.rightVal();
} else if (value.compareTo(threeNode.rightVal()) < 0) {
min = threeNode.leftVal();
middle = value;
max = threeNode.rightVal();
} else {
min = threeNode.leftVal();
max = value;
middle = threeNode.rightVal();
}
Node parent = Node.newTwoNode(middle);
parent.setLeftChild(Node.newTwoNode(min));
parent.setRightChild(Node.newTwoNode(max));
return parent;
}
public interface Function {
public void apply(T t);
}
/**
* Preorder search.
* Visit the node.
* Visit the left subtree
* Visit the middle subtree
*/
public void preOrder(Node node, Function f) {
if (node.isThreeNode()) {
f.apply(node.leftVal());
f.apply(node.rightVal());
}
if (node.isTerminal())
return;
preOrder(node.leftChild(), f);
if (node.isThreeNode()) {
assert node.middleChild() != null;
preOrder(node.middleChild(), f);
}
preOrder(node.rightChild(), f);
}
public void inorderSearch(Node node, Function func) {
if (node == null)
return;
inorderSearch(node.leftChild(), func);
if (node.isThreeNode()) {
Node threeNode = node;
func.apply(threeNode.leftVal());
inorderSearch(threeNode.middleChild(), func);
func.apply(threeNode.rightVal());
} else {
func.apply(node.val());
}
inorderSearch(node.rightChild(), func);
}
// Set operations.
/**
* The returning iterator does not support remove.
*/
public Iterator iterator() {
return new Iterator() {
Node nextNode;
// Stack to keep three nodes
Deque> threeNodes = new ArrayDeque>();
T next;
{
Node node = root;
while(node != null && node.leftChild() != null) {
node = node.leftChild();
}
nextNode = node;
}
public boolean hasNext() {
return next != null || nextNode != null;
}
public T next() {
T prev;
if (next != null) {
prev = next;
next = null;
nextNode = successor(nextNode, prev);
return prev;
}
if (nextNode.isThreeNode()) {
if (nextNode.isTerminal()) {
next = nextNode.rightVal();
prev = nextNode.leftVal();
} else {
if (threeNodes.peekFirst() == nextNode) {
threeNodes.pollFirst();
prev = nextNode.rightVal();
nextNode = successor(nextNode, prev);
} else {
prev = nextNode.leftVal();
threeNodes.addFirst(nextNode);
nextNode = successor(nextNode, prev);
}
}
} else {
prev = nextNode.val();
nextNode = successor(nextNode, prev);
}
return prev;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public Comparator super T> comparator() {
return null;
}
public SortedSet subSet(T fromElement, T toElement) {
throw new UnsupportedOperationException();
}
public SortedSet headSet(T toElement) {
throw new UnsupportedOperationException();
}
public SortedSet tailSet(T fromElement) {
throw new UnsupportedOperationException();
}
public T first() {
Node node = root;
while (node.leftChild() != null) {
node = node.leftChild();
}
return node.isThreeNode() ? node.leftVal() : node.val();
}
public T last() {
Node node = root;
while (node.rightChild() != null) {
node = node.rightChild();
}
return node.isThreeNode() ? node.rightVal() : node.val();
}
public int size() {
return size;
}
@Override
public boolean contains(Object o) {
try {
return contains ((T) o);
} catch (ClassCastException e) {
return false;
}
}
@Override
public boolean remove(Object o) {
try {
return remove((T) o);
} catch (ClassCastException e) {
return false;
}
}
@Override
public void clear() {
root = null;
}
@Override
public Object[] toArray() {
final Object arr[] = new Object[size];
inorderSearch(root, new Function() {
int index = 0;
public void apply(Object t) {
arr[index++] = (T) t;
}
});
return arr;
}
@Override
public T[] toArray(T[] a) {
T[] r = a.length >= size ? a :
(T[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
return _toArray(r);
}
public T[] _toArray(final T[] a) {
inorderSearch(root, new Function() {
int index = 0;
public void apply(Object t) {
a[index++] = (T) t;
}
});
return a;
}
@Override
public boolean removeAll(Collection> c) {
boolean removed = false;
for (Object o : c) {
removed |= remove(o);
}
return removed;
}
@Override
public String toString() {
if (size == 0)
return "[]";
final StringBuilder sb = new StringBuilder("[");
inorderSearch(root, new Function() {
public void apply(T t) {
sb.append(t);
sb.append(", ");
}
});
sb.deleteCharAt(sb.length() - 1);
sb.deleteCharAt(sb.length() - 1);
sb.append("]");
return sb.toString();
}
}