import java.util.Stack;
|
|
import java.util.List;
|
|
|
|
|
|
public class BinarySearchTree<E extends Comparable<E>> {
|
|
class Node {
|
|
E value;
|
|
Node leftChild = null;
|
|
Node rightChild = null;
|
|
Node(E value) {
|
|
this.value = value;
|
|
}
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if ((obj instanceof BinarySearchTree.Node) == false)
|
|
return false;
|
|
@SuppressWarnings("unchecked")
|
|
Node other = (BinarySearchTree<E>.Node)obj;
|
|
return other.value.compareTo(value) == 0 &&
|
|
other.leftChild == leftChild && other.rightChild == rightChild;
|
|
}
|
|
}
|
|
|
|
protected Node root = null;
|
|
|
|
protected void visit(Node n) {
|
|
System.out.println(n.value);
|
|
}
|
|
|
|
public boolean contains(E val) {
|
|
return contains(root, val);
|
|
}
|
|
|
|
protected boolean contains(Node n, E val) {
|
|
if (n == null) return false;
|
|
|
|
if (n.value.equals(val)) {
|
|
return true;
|
|
} else if (n.value.compareTo(val) > 0) {
|
|
return contains(n.leftChild, val);
|
|
} else {
|
|
return contains(n.rightChild, val);
|
|
}
|
|
}
|
|
|
|
public boolean add(E val) {
|
|
if (root == null) {
|
|
root = new Node(val);
|
|
return true;
|
|
}
|
|
return add(root, val);
|
|
}
|
|
|
|
protected boolean add(Node n, E val) {
|
|
if (n == null) {
|
|
return false;
|
|
}
|
|
int cmp = val.compareTo(n.value);
|
|
if (cmp == 0) {
|
|
return false; // this ensures that the same value does not appear more than once
|
|
} else if (cmp < 0) {
|
|
if (n.leftChild == null) {
|
|
n.leftChild = new Node(val);
|
|
return true;
|
|
} else {
|
|
return add(n.leftChild, val);
|
|
}
|
|
} else {
|
|
if (n.rightChild == null) {
|
|
n.rightChild = new Node(val);
|
|
return true;
|
|
} else {
|
|
return add(n.rightChild, val);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean remove(E val) {
|
|
return remove(root, null, val);
|
|
}
|
|
|
|
protected boolean remove(Node n, Node parent, E val) {
|
|
if (n == null) return false;
|
|
|
|
if (val.compareTo(n.value) == -1) {
|
|
return remove(n.leftChild, n, val);
|
|
} else if (val.compareTo(n.value) == 1) {
|
|
return remove(n.rightChild, n, val);
|
|
} else {
|
|
if (n.leftChild != null && n.rightChild != null){
|
|
n.value = maxValue(n.leftChild);
|
|
remove(n.leftChild, n, n.value);
|
|
} else if (parent == null) {
|
|
root = n.leftChild != null ? n.leftChild : n.rightChild;
|
|
} else if (parent.leftChild == n){
|
|
parent.leftChild = n.leftChild != null ? n.leftChild : n.rightChild;
|
|
} else {
|
|
parent.rightChild = n.leftChild != null ? n.leftChild : n.rightChild;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected E maxValue(Node n) {
|
|
if (n.rightChild == null) {
|
|
return n.value;
|
|
} else {
|
|
return maxValue(n.rightChild);
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************
|
|
*
|
|
* IMPLEMENT THE METHODS BELOW!
|
|
*
|
|
*********************************************/
|
|
|
|
|
|
// Method #1.
|
|
public Node findNode(E val) {
|
|
Node node = this.root;
|
|
if(val == null) return null;
|
|
while(!node.value.equals(val)){
|
|
if(node.value.compareTo(val) > 0) node = node.leftChild;
|
|
else node = node.rightChild;
|
|
if(node == null) return null;
|
|
}
|
|
return node;
|
|
|
|
}
|
|
|
|
// Method #2.
|
|
protected int depth(E val) { // Basically the same method as findNode
|
|
int depth = 0;
|
|
Node node = this.root;
|
|
if(val == null) return -1;
|
|
while(!node.value.equals(val)){
|
|
if(node.value.compareTo(val) > 0) node = node.leftChild;
|
|
else node = node.rightChild;
|
|
if(node == null) return -1;
|
|
depth++;
|
|
}
|
|
return depth;
|
|
}
|
|
|
|
// Method #3.
|
|
protected int height(E val) {
|
|
int leftHeight, rightHeight;
|
|
Node node = this.findNode(val);
|
|
if(val == null) return -1;
|
|
if(node == null) return -1;
|
|
|
|
if(node.leftChild == null && node.rightChild == null) return 0;
|
|
|
|
leftHeight = node.leftChild == null ? 0 : this.height(node.leftChild.value);
|
|
rightHeight = node.rightChild == null ? 0 : this.height(node.rightChild.value);
|
|
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
|
|
}
|
|
|
|
// Method #4.
|
|
protected boolean isBalanced(Node n) {
|
|
|
|
if(n == null) return false;
|
|
if(this.findNode(n.value) == null) return false;
|
|
|
|
int diff = Math.abs(this.height(n.leftChild == null ? null : n.leftChild.value) - this.height(n.rightChild == null ? null : n.rightChild.value));
|
|
return diff == 0 || diff == 1;
|
|
}
|
|
|
|
// Method #5. .
|
|
public boolean isBalanced() {
|
|
Stack<Node> explored = new Stack<Node>();
|
|
|
|
explored.push(this.root);
|
|
Node node;
|
|
while(!explored.isEmpty()){
|
|
node = explored.pop();
|
|
if(!this.isBalanced(node)) return false;
|
|
if(node.leftChild != null){
|
|
explored.push(node.leftChild);
|
|
}
|
|
if(node.rightChild != null){
|
|
explored.push(node.rightChild);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|