Skip to content

Instantly share code, notes, and snippets.

@isaacsanders
Created December 7, 2012 00:47
Show Gist options
  • Save isaacsanders/4229801 to your computer and use it in GitHub Desktop.
Save isaacsanders/4229801 to your computer and use it in GitHub Desktop.
This is my eternal shame.
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Stack;
public class AVLTree<T extends Comparable<T>> implements Iterable<T> {
public class BoolWrapper {
public boolean value;
public BoolWrapper(boolean value) {
this.value = value;
}
}
public class BinaryNode {
public T getElement() {
return this.value;
}
public BinaryNode getRightChild() {
return this.rightChild;
}
public void setRightChild(BinaryNode rightChild) {
this.rightChild = rightChild;
}
public BinaryNode getLeftChild() {
return this.leftChild;
}
public void setLeftChild(BinaryNode leftChild) {
this.leftChild = leftChild;
}
private static final int BALANCE_FACTOR_ON_RIGHT_IMBALANCES = -2;
private static final int BALANCE_FACTOR_ON_LEFT_IMBALANCES = 2;
private static final String ELEMENT_STRING_DELIMITER = ", ";
private BinaryNode rightChild;
private BinaryNode leftChild;
private T value;
private int height = 0;
public BinaryNode(T value) {
this.value = value;
}
private int leftHeight() {
if (this.hasLeftChild()) {
return this.leftChild.height;
} else {
return -1;
}
}
private int rightHeight() {
if (this.hasRightChild()) {
return this.rightChild.height;
} else {
return -1;
}
}
public boolean hasLeftChild() {
return this.leftChild != null;
}
public boolean hasRightChild() {
return this.rightChild != null;
}
@Override
public String toString() {
return this.leftChildString() + this.value + this.rightChildString();
}
private String rightChildString() {
if (this.hasRightChild()) {
return ELEMENT_STRING_DELIMITER + this.rightChild.toString();
} else {
return "";
}
}
private String leftChildString() {
if (this.hasLeftChild()) {
return this.leftChild.toString() + ELEMENT_STRING_DELIMITER;
} else {
return "";
}
}
public ArrayList<T> toArrayList() {
ArrayList<T> arrayList = new ArrayList<T>();
arrayList.add(this.value);
if (this.hasLeftChild()) {
for(T value : this.leftChild.toArrayList()) {
arrayList.add(value);
}
}
if (this.hasRightChild()) {
for(T value : this.rightChild.toArrayList()) {
arrayList.add(value);
}
}
return arrayList;
}
public int balanceFactor() {
return this.leftHeight() - this.rightHeight();
}
public BinaryNode insert(T object, BoolWrapper anElementWasInserted) {
boolean insertObjectToTheLeft = object.compareTo(this.value) < 0;
boolean insertObjectToTheRight = object.compareTo(this.value) > 0;
BinaryNode newThis = this;
if (insertObjectToTheLeft) {
newThis.leftChild = this.insertLeft(object, anElementWasInserted);
} else if (insertObjectToTheRight) {
newThis.rightChild = this.insertRight(object, anElementWasInserted);
}
if (anElementWasInserted.value) {
newThis.resetHeight();
if (newThis.hasLeftChild()) {
newThis.leftChild.resetHeight();
}
if (newThis.hasRightChild()) {
newThis.rightChild.resetHeight();
}
}
if (this.balanceFactor() == BALANCE_FACTOR_ON_LEFT_IMBALANCES) {
newThis = this.balanceLeft();
}
if (this.balanceFactor() == BinaryNode.BALANCE_FACTOR_ON_RIGHT_IMBALANCES) {
newThis = this.balanceRight();
}
return newThis;
}
private void resetHeight() {
if (this.leftHeight() > this.rightHeight()) {
this.height = 1 + this.leftHeight();
} else {
this.height = 1 + this.rightHeight();
}
}
private BinaryNode balanceLeft() {
if (this.leftChild.balanceFactor() == -1) {
this.leftChild = this.leftChild.performLeftRotation();
}
return this.performRightRotation();
}
private BinaryNode balanceRight() {
if (this.rightChild.balanceFactor() == 1) {
this.rightChild = this.rightChild.performRightRotation();
}
return this.performLeftRotation();
}
private BinaryNode insertLeft(T object, BoolWrapper anElementWasInserted) {
if (this.hasLeftChild()) {
return this.leftChild.insert(object, anElementWasInserted);
} else {
anElementWasInserted.value = true;
return new BinaryNode(object);
}
}
private BinaryNode insertRight(T object, BoolWrapper anElementWasInserted) {
if (this.hasRightChild()) {
return this.rightChild.insert(object, anElementWasInserted);
} else {
anElementWasInserted.value = true;
return new BinaryNode(object);
}
}
public BinaryNode performRightRotation() {
AVLTree.this.rotations++;
BinaryNode newRight = new BinaryNode(this.value);
newRight.rightChild = this.rightChild;
if (this.leftChild.hasRightChild()) {
newRight.leftChild = this.leftChild.rightChild;
}
BinaryNode newLeft = this.leftChild.leftChild;
BinaryNode node = new BinaryNode(this.leftChild.value);
node.rightChild = newRight;
node.leftChild = newLeft;
node.resetHeight();
return node;
}
public BinaryNode performLeftRotation() {
AVLTree.this.rotations++;
BinaryNode newLeft = new BinaryNode(this.value);
newLeft.leftChild = this.leftChild;
if (this.rightChild.hasLeftChild()) {
newLeft.rightChild = this.rightChild.leftChild;
}
BinaryNode newRight = this.rightChild.rightChild;
BinaryNode node = new BinaryNode(this.rightChild.value);
node.leftChild = newLeft;
node.rightChild = newRight;
node.resetHeight();
return node;
}
private boolean isGreaterValue(T object) {
return object.compareTo(this.value) > 0;
}
private boolean isLesserValue(T object) {
return object.compareTo(this.value) < 0;
}
public BinaryNode remove(T object, BoolWrapper anElementWasRemoved) {
BinaryNode newThis = this;
if (this.isGreaterValue(object)) {
if (this.hasRightChild()) {
newThis.rightChild = this.rightChild.remove(object, anElementWasRemoved);
}
} else if (this.isLesserValue(object)) {
if (this.hasLeftChild()) {
newThis.leftChild = this.leftChild.remove(object, anElementWasRemoved);
}
} else {
newThis = this.removeSelf(anElementWasRemoved);
}
if (anElementWasRemoved.value && newThis != null) {
newThis.resetHeight();
if (newThis.hasLeftChild()) {
newThis.leftChild.resetHeight();
}
if (newThis.hasRightChild()) {
newThis.rightChild.resetHeight();
}
}
if (this.balanceFactor() == BALANCE_FACTOR_ON_LEFT_IMBALANCES) {
newThis = this.balanceLeft();
}
if (this.balanceFactor() == BinaryNode.BALANCE_FACTOR_ON_RIGHT_IMBALANCES) {
newThis = this.balanceRight();
}
return newThis;
}
private BinaryNode removeSelf(BoolWrapper anElementWasRemoved) {
anElementWasRemoved.value = true;
AVLTree.this.modifications++;
if (this.hasBothChildren()) {
return this.removeFromNodeWithTwoChildren(anElementWasRemoved);
} else if (this.hasLeftChild()) {
return this.leftChild;
} else if (this.hasRightChild()) {
return this.rightChild;
} else {
return null;
}
}
private BinaryNode removeFromNodeWithTwoChildren(BoolWrapper anElementWasRemoved) {
BinaryNode greatestNodeInLeftSubTree = this.leftChild;
while (greatestNodeInLeftSubTree.hasRightChild()) {
greatestNodeInLeftSubTree = greatestNodeInLeftSubTree.rightChild;
}
this.value = greatestNodeInLeftSubTree.value;
this.leftChild = this.leftChild.remove(this.value, anElementWasRemoved);
return this;
}
private boolean hasBothChildren() {
return this.hasLeftChild() && this.hasRightChild();
}
public T get(T object) {
if (this.isGreaterValue(object)) {
if (this.hasRightChild()) {
return this.rightChild.get(object);
}
} else if (this.isLesserValue(object)) {
if (this.hasLeftChild()) {
return this.leftChild.get(object);
}
} else {
return this.value;
}
return null;
}
}
public class LazyPreOrderTreeIterator implements Iterator<T> {
protected int localModifications;
protected Stack<BinaryNode> stack;
protected BinaryNode lastReturnedNode = null;
public LazyPreOrderTreeIterator() {
this.stack = new Stack<BinaryNode>();
if (AVLTree.this.hasRoot()) {
this.push(AVLTree.this.root);
}
this.localModifications = AVLTree.this.modifications;
}
protected void push(BinaryNode node) {
this.stack.push(node);
}
protected BinaryNode pop() {
return this.stack.pop();
}
@Override
public T next() {
if (this.localModifications != AVLTree.this.modifications) {
throw new ConcurrentModificationException();
}
if (this.hasNext()) {
this.lastReturnedNode = this.pop();
this.pushRightChild(this.lastReturnedNode);
this.pushLeftChild(this.lastReturnedNode);
return this.lastReturnedNode.value;
} else {
throw new NoSuchElementException();
}
}
protected void pushLeftChild(BinaryNode node) {
if (node.hasLeftChild()) {
this.push(node.leftChild);
}
}
protected void pushRightChild(BinaryNode node) {
if (node.hasRightChild()) {
this.push(node.rightChild);
}
}
@Override
public void remove() {
if (this.lastReturnedNode == null) {
throw new IllegalStateException();
} else {
T object = this.lastReturnedNode.value;
AVLTree<T> tree = AVLTree.this;
tree.remove(object);
this.lastReturnedNode = null;
}
}
@Override
public boolean hasNext() {
return !this.stack.empty();
}
}
private static final String RIGHT_STRING_DELIMITER = "]";
private static final String LEFT_STRING_DELIMITER = "[";
private static final String EMPTY_TREE_STRING = LEFT_STRING_DELIMITER + RIGHT_STRING_DELIMITER;
public BinaryNode root;
private int modifications;
private int rotations = 0;
public AVLTree(BinaryNode root) {
this.root = root;
}
public AVLTree() {}
public int height() {
if (this.hasRoot()) {
return this.root.height;
} else {
return -1;
}
}
private boolean hasRoot() {
return this.root != null;
}
public boolean isEmpty() {
return !this.hasRoot();
}
@Override
public String toString() {
if (this.hasRoot()) {
return LEFT_STRING_DELIMITER + this.root.toString() + RIGHT_STRING_DELIMITER;
} else {
return EMPTY_TREE_STRING;
}
}
@Override
public Iterator<T> iterator() {
return new LazyPreOrderTreeIterator();
}
public ArrayList<T> toArrayList() {
if (this.hasRoot()) {
return this.root.toArrayList();
} else {
return new ArrayList<T>();
}
}
public Object[] toArray() {
return this.toArrayList().toArray();
}
public boolean insert(T object) {
if (object == null) {
throw new IllegalArgumentException();
}
BoolWrapper anElementWasInserted = new BoolWrapper(false);
if (this.hasRoot()) {
this.root = this.root.insert(object, anElementWasInserted);
return anElementWasInserted.value;
} else {
this.root = new BinaryNode(object);
return true;
}
}
public boolean remove(T object) {
if (object == null) {
throw new IllegalArgumentException();
}
BoolWrapper anElementWasRemoved = new BoolWrapper(false);
if (this.hasRoot()) {
this.root = this.root.remove(object, anElementWasRemoved);
} else {
return false;
}
if (anElementWasRemoved.value) {
this.modifications++;
}
return anElementWasRemoved.value;
}
public T get(T object) {
if (this.hasRoot()) {
return this.root.get(object);
} else {
return null;
}
}
public int getRotationCount() {
return this.rotations;
}
}
@leviwilson
Copy link

Something like this be an improvement?

public ArrayList<T> toArrayList() {
  eitherOr(root.toArrayList(), new ArrayList<T>());
}

private <EitherOrType> EitherOrType eitherOr(final EitherOrType hasRootValue, final EitherOrType hasNoRootValue) {
  if( hasRoot() ) {
    return hasRootValue;
  }

  return hasNoRootValue;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment