package org.exist.dom;
import org.exist.numbering.NodeId;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.SequenceIterator;
import java.util.Iterator;
import java.util.Stack;
public class AVLTreeNodeSet extends AbstractNodeSet {
private Node root;
private int size = 0;
private int state = 0;
public AVLTreeNodeSet() {
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#iterate()
*/
public SequenceIterator iterate() throws XPathException {
return new InorderTraversal();
}
public SequenceIterator unorderedIterator() throws XPathException {
return new InorderTraversal();
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#addAll(org.exist.dom.NodeSet)
*/
public void addAll(NodeSet other) {
for (Iterator i = other.iterator(); i.hasNext();)
add((NodeProxy) i.next());
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#getLength()
*/
public int getLength() {
return size;
}
//TODO : evaluate both semantics
public int getItemCount() {
return size;
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#item(int)
*/
public org.w3c.dom.Node item(int pos) {
int i = 0;
for(Iterator it = iterator(); it.hasNext(); i++) {
NodeProxy p = (NodeProxy) it.next();
if(i == pos)
return p.getNode();
}
return null;
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#get(int)
*/
public NodeProxy get(int pos) {
return (NodeProxy)itemAt(pos);
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#get(org.exist.dom.NodeProxy)
*/
public final NodeProxy get(NodeProxy p) {
Node n = searchData(p);
return n == null ? null : n.getData();
}
public boolean isEmpty() {
return (size == 0);
}
public boolean hasOne() {
return (size == 1);
}
/* (non-Javadoc)
* @see org.exist.xquery.value.Sequence#itemAt(int)
*/
public Item itemAt(int pos) {
int i = 0;
for(Iterator it = iterator(); it.hasNext(); i++) {
NodeProxy p = (NodeProxy) it.next();
if(i == pos)
return p;
}
return null;
}
public final void add(NodeProxy proxy) {
if(proxy == null)
return;
setHasChanged();
if (root == null) {
root = new Node(proxy);
++size;
return;
}
Node tempNode = root;
while (true) {
int c = tempNode.data.compareTo(proxy);
if (c == 0) {
return;
}
if (c > 0) { // inserts s into left subtree.
if (tempNode.hasLeftChild()) {
tempNode = tempNode.leftChild;
continue;
} else {
Node newNode = tempNode.addLeft(proxy);
balance(newNode);
++size;
return;
}
} else { // inserts s to right subtree
if (tempNode.hasRightChild()) {
tempNode = tempNode.rightChild;
continue;
} else {
Node newNode = tempNode.addRight(proxy);
balance(newNode);
++size;
return;
}
}
}
}
public Node getMinNode() {
if (root == null)
return null;
Node tempNode = root;
while (tempNode.hasLeftChild())
tempNode = tempNode.getLeftChild();
return tempNode;
}
public Node getMaxNode() {
if (root == null)
return null;
Node tempNode = root;
while (tempNode.hasRightChild())
tempNode = tempNode.getRightChild();
return tempNode;
}
private void balance(Node node) {
Node currentNode, currentParent;
currentNode = node;
currentParent = node.parent;
while (currentNode != root) {
int h = currentParent.height;
currentParent.setHeight();
if (h == currentParent.height)
return; // Case 1
if (currentParent.balanced()) {
currentNode = currentParent;
currentParent = currentNode.parent;
continue;
}
if (currentParent.leftHeight() - currentParent.rightHeight()
== 2) {
Node nodeA = currentParent,
nodeB = nodeA.getLeftChild(),
//nodeC = nodeB.getLeftChild(),
nodeD = nodeB.getRightChild();
if (nodeB.leftHeight() > nodeB.rightHeight()) {
// right rotation for Case 2
nodeA.addLeftChild(nodeD);
if (nodeA != root) {
if (nodeA.isLeftChild())
nodeA.parent.addLeftChild(nodeB);
else
nodeA.parent.addRightChild(nodeB);
} else {
root = nodeB;
};
nodeB.addRightChild(nodeA);
nodeA.setHeight();
nodeB.setHeight();
currentNode = nodeB;
currentParent = currentNode.parent;
continue;
}
// Case 3 and Case 4
Node nodeE = null, nodeF = null;
if (nodeD.hasLeftChild()) {
nodeE = nodeD.getLeftChild();
nodeB.addRightChild(nodeE);
} else
nodeB.removeRightChild();
if (nodeD.hasRightChild()) {
nodeF = nodeD.getRightChild();
nodeA.addLeftChild(nodeF);
} else
nodeA.removeLeftChild();
if (currentParent != root) {
if (nodeA.isLeftChild())
nodeA.parent.addLeftChild(nodeD);
else
nodeA.parent.addRightChild(nodeD);
} else
root = nodeD;
nodeD.addLeftChild(nodeB);
nodeD.addRightChild(nodeA);
nodeB.setHeight();
nodeA.setHeight();
nodeD.setHeight();
currentNode = nodeD;
currentParent = currentNode.parent;
continue;
}
if (currentParent.leftHeight() - currentParent.rightHeight()
== -2) {
Node nodeA = currentParent;
Node nodeB = nodeA.getRightChild();
Node nodeC = nodeB.getLeftChild();
//Node nodeD = nodeB.getRightChild();
if (nodeB.leftHeight() < nodeB.rightHeight()) {
// left rotation for Case 2
nodeA.addRightChild(nodeC);
if (nodeA != root) {
if (nodeA.isLeftChild())
nodeA.parent.addLeftChild(nodeB);
else
nodeA.parent.addRightChild(nodeB);
} else {
root = nodeB;
};
nodeB.addLeftChild(nodeA);
nodeA.setHeight();
nodeB.setHeight();
currentNode = nodeB;
currentParent = currentNode.parent;
continue;
}
// Case 3 and Case 4
Node nodeE = null, nodeF = null;
if (nodeC.hasLeftChild()) {
nodeE = nodeC.getLeftChild();
nodeA.addRightChild(nodeE);
} else
nodeA.removeRightChild();
if (nodeC.hasRightChild()) {
nodeF = nodeC.getRightChild();
nodeB.addLeftChild(nodeF);
} else
nodeB.removeLeftChild();
if (nodeA != root) {
if (nodeA.isLeftChild())
nodeA.parent.addLeftChild(nodeC);
else
nodeA.parent.addRightChild(nodeC);
} else
root = nodeC;
nodeC.addLeftChild(nodeA);
nodeC.addRightChild(nodeB);
nodeB.setHeight();
nodeA.setHeight();
nodeC.setHeight();
currentNode = nodeC;
currentParent = currentNode.parent;
continue;
}
}
}
public final Node searchData(NodeProxy proxy) {
if (root == null)
return null;
Node tempNode = root;
while (tempNode != null) {
int c = tempNode.data.compareTo(proxy);
if (c == 0)
return tempNode;
if (c < 0)
tempNode = tempNode.rightChild;
else
tempNode = tempNode.leftChild;
}
return null;
}
public final NodeProxy get(DocumentImpl doc, NodeId nodeId) {
if (root == null)
return null;
Node tempNode = root;
int cmp;
while (tempNode != null) {
if (tempNode.data.getDocument().getDocId() == doc.getDocId()) {
cmp = tempNode.data.getNodeId().compareTo(nodeId);
if (cmp == 0)
return tempNode.data;
else if (cmp < 0)
tempNode = tempNode.rightChild;
else
tempNode = tempNode.leftChild;
} else if (tempNode.data.getDocument().getDocId() < doc.getDocId())
tempNode = tempNode.rightChild;
else
tempNode = tempNode.leftChild;
}
return null;
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#contains(org.exist.dom.NodeProxy)
*/
public final boolean contains(NodeProxy proxy) {
return searchData(proxy) != null;
}
public void removeNode(Node node) {
--size;
Node tempNode = node;
while (tempNode.hasLeftChild() || tempNode.hasRightChild()) {
if (tempNode.hasLeftChild()) {
tempNode = tempNode.getLeftChild();
while (tempNode.hasRightChild())
tempNode = tempNode.getRightChild();
} else {
tempNode = tempNode.getRightChild();
while (tempNode.hasLeftChild())
tempNode = tempNode.getLeftChild();
}
node.setData(tempNode.getData());
}
if (tempNode == root) {
root = null;
return;
}
if (tempNode.isLeftChild()) {
node = tempNode.parent;
node.removeLeftChild();
if (node.hasRightChild())
balance(node.getRightChild());
else
balance(node);
} else {
node = tempNode.parent;
node.removeRightChild();
if (node.hasLeftChild())
balance(node.getLeftChild());
else
balance(node);
}
}
public NodeSetIterator iterator() {
return (this.new InorderTraversal());
}
/*
* (non-Javadoc)
*
* @see org.exist.dom.AbstractNodeSet#hasChanged(int)
*/
public boolean hasChanged(int previousState) {
return state != previousState;
}
/*
* (non-Javadoc)
*
* @see org.exist.dom.AbstractNodeSet#getState()
*/
public int getState() {
return state;
}
public boolean isCacheable() {
return true;
}
private void setHasChanged() {
state = (state == Integer.MAX_VALUE ? state = 0 : state + 1);
}
class InorderTraversal implements NodeSetIterator, SequenceIterator {
private Stack nodes;
public InorderTraversal() {
nodes = new Stack();
if (root != null) {
Node tempNode = root;
do {
nodes.push(tempNode);
tempNode = tempNode.leftChild;
} while (tempNode != null);
}
}
public boolean hasNext() {
if (nodes.size() == 0)
return false;
else
return true;
}
public Object next() {
if(nodes.isEmpty())
return null;
Node currentNode = (Node) nodes.peek();
nodes.pop();
if (currentNode.hasRightChild()) {
Node tempNode = currentNode.rightChild;
do {
nodes.push(tempNode);
tempNode = tempNode.leftChild;
} while (tempNode != null);
}
return currentNode.getData();
}
public NodeProxy peekNode() {
if(nodes.isEmpty())
return null;
Node currentNode = (Node) nodes.peek();
return currentNode.getData();
}
public void setPosition(NodeProxy proxy) {
Node n = searchData(proxy);
nodes.clear();
if (n != null) {
Node tempNode = n;
do {
nodes.push(tempNode);
tempNode = tempNode.leftChild;
} while (tempNode != null);
}
}
/* (non-Javadoc)
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new RuntimeException("Method remove is not implemented");
}
/* (non-Javadoc)
* @see org.exist.xquery.value.SequenceIterator#nextItem()
*/
public Item nextItem() {
if(nodes.isEmpty())
return null;
Node currentNode = (Node) nodes.peek();
nodes.pop();
if (currentNode.hasRightChild()) {
Node tempNode = currentNode.rightChild;
do {
nodes.push(tempNode);
tempNode = tempNode.leftChild;
} while (tempNode != null);
}
return currentNode.getData();
}
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("AVLTree#").append(super.toString());
return result.toString();
}
private final static class Node {
public Node(NodeProxy data) {
this.data = data;
}
public void setData(NodeProxy data) {
this.data = data;
}
public NodeProxy getData() {
return data;
}
public boolean hasLeftChild() {
return (leftChild != null);
}
public boolean hasRightChild() {
return (rightChild != null);
}
public Node getLeftChild() {
return leftChild;
}
public Node getRightChild() {
return rightChild;
}
public boolean balanced() {
return (Math.abs(leftHeight() - rightHeight()) <= 1);
}
public Node addLeft(NodeProxy data) {
Node tempNode = new Node(data);
leftChild = tempNode;
tempNode.parent = this;
return tempNode;
}
public Node addLeftChild(Node node) {
leftChild = node;
if (node != null)
node.parent = this;
return node;
}
public Node addRight(NodeProxy data) {
Node tempNode = new Node(data);
rightChild = tempNode;
tempNode.parent = this;
return tempNode;
}
public Node addRightChild(Node node) {
rightChild = node;
if (node != null)
node.parent = this;
return node;
}
public Node removeLeftChild() {
Node tempNode = leftChild;
leftChild = null;
return tempNode;
}
public Node removeRightChild() {
Node tempNode = rightChild;
rightChild = null;
return tempNode;
}
public int degree() {
int i = 0;
if (leftChild != null)
i++;
if (rightChild != null)
i++;
return i;
}
public void setHeight() {
height = Math.max(leftHeight(), rightHeight());
}
public boolean isLeftChild() {
return (this == parent.leftChild);
}
public boolean isRightChild() {
return (this == parent.rightChild);
}
public int leftHeight() {
if (hasLeftChild())
return (1 + leftChild.height);
else
return 0;
}
public int rightHeight() {
if (hasRightChild())
return (1 + rightChild.height);
else
return 0;
}
public int height() {
return height;
}
NodeProxy data;
Node parent;
Node leftChild;
Node rightChild;
int height;
}
}