二分搜索树是在二叉树的基础上定义:
所有节点的左子节点需要小于(不大于)该节点,右子节点需要大于(不小于)该节点
实现代码如下:
注意:这里实现的二分搜索树会去重,如果允许重复节点,则在添加元素时,定义值相等的元素存放在节点的左子节点或右子节点中。
public class BST<E extends Comparable<E>> {
private class Node<E> {
public E val;
public Node<E> left, right;
public Node(E e) {
val = e;
left = right = null;
}
}
private Node<E> root;
private int size;
public BST() {
root = null;
size = 0;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void inOrder() {
inOrder(root);
}
private void inOrder(Node<E> node) {
if (node == null) {
return;
}
inOrder(node.left);
System.out.println(node.val);
inOrder(node.right);
}
public void add(E e) {
// version 1
// if (root == null) {
// root = new Node<>(e);
// size++;
// } else {
// addElementToTree(root, e);
// }
// version 2
root = addElementToTreeAndReturnRoot(root, e);
}
/**
* 将元素加入以指定节点为根的子树中
* @param node 子树的根节点,调用前需要判空
* @param e
*/
private void addElementToTree(Node<E> node, E e) {
int comp = e.compareTo(node.val);
if (comp == 0) {
return;
}
if (comp < 0) {
// 需要放入左子树
if (node.left == null) {
// 左子树为空,新建左子树并完成创建
node.left = new Node<>(e);
size++;
return;
} else {
// 左子树不为空,将元素添加在左子树上
addElementToTree(node.left, e);
}
} else {
// 需要放入右子树
if (node.right == null) {
// 右子树为空,新建右子树并完成创建
node.right = new Node<>(e);
size++;
return;
} else {
// 左子树不为空,将元素添加在左子树上
addElementToTree(node.right, e);
}
}
}
/**
* 将元素加入以指定节点为根的子树,并返回该子树的根节点
* @param node 子树的根节点
* @param e 元素
* @return
*/
private Node<E> addElementToTreeAndReturnRoot(Node<E> node, E e) {
if (node == null) {
size++;
return new Node<>(e);
}
int comp = e.compareTo(node.val);
if (comp < 0) {
// 放入左子树
node.left = addElementToTreeAndReturnRoot(node.left, e);
} else if (comp > 0) {
// 放入右子树
node.right = addElementToTreeAndReturnRoot(node.right, e);
}
return node;
}
public boolean contains(E e) {
return contains(root, e);
}
/**
* 在以指定节点为根节点的子树上搜索元素是否存在
* @param node
* @param e
* @return
*/
private boolean contains(Node<E> node, E e) {
if (node == null) {
return false;
}
int comp = e.compareTo(node.val);
if (comp < 0) {
return contains(node.left, e);
}
if (comp > 0) {
return contains(node.right, e);
}
return true;
}
public E getMin() {
if (isEmpty()) {
throw new IllegalArgumentException("BST is empty!");
}
return getMin(root).val;
}
private Node<E> getMin(Node<E> node) {
if (node.left == null) {
return node;
} else {
return getMin(node.left);
}
}
public E getMax() {
if (isEmpty()) {
throw new IllegalArgumentException("BST is empty!");
}
return getMax(root).val;
}
private Node<E> getMax(Node<E> node) {
if (node.right == null) {
return node;
} else {
return getMax(node.right);
}
}
public E removeMin() {
E ret = getMin();
root = removeMin(root);
return ret;
}
/**
* 删除以指定节点为根的子树中的最小节点
* @param node
* @return 返回删除后的子树的根节点
*/
private Node<E> removeMin(Node<E> node) {
if (node.left == null) {
// 如果子树没有左子树,删除node节点,返回node节点的右子树为删除后的子树
Node<E> right = node.right;
node.right = null;
size--;
return right;
} else {
// 如果子树有左子树,递归
node.left = removeMin(node.left);
return node;
}
}
public E removeMax() {
E ret = getMax();
root = removeMax(root);
return ret;
}
/**
* 删除以指定节点为根的子树中的最大节点
* @param node
* @return 返回删除后的子树的根节点
*/
private Node<E> removeMax(Node<E> node) {
if (node.right == null) {
// 如果子树没有右子树,删除node节点,返回node节点的左子树为删除后的子树
Node<E> left = node.left;
node.left = null;
size--;
return left;
} else {
// 如果子树有右子树,递归
node.right = removeMax(node.right);
return node;
}
}
public void remove(E e) {
root = remove(root, e);
}
private Node<E> remove(Node<E> node, E e) {
if (node == null) {
return null;
}
int comp = e.compareTo(node.val);
if (comp < 0) {
node.left = remove(node.left, e);
return node;
}
if (comp > 0) {
node.right = remove(node.right, e);
return node;
}
if (node.left == null) {
size--;
return node.right;
}
if (node.right == null) {
size--;
return node.left;
}
// Node<E> successor = getMin(node.right);
// node.right = removeMin(node.right);
//
// successor.left = node.left;
// successor.right = node.right;
Node<E> predecessor = getMax(node.left);
node.left = removeMax(node.left);
predecessor.left = node.left;
predecessor.right = node.right;
return predecessor;
}
/**
* 比指定元素小的最大值(地板)
* @param e
* @return
*/
public E floor(E e) {
return floor(root, e).val;
}
/**
* 比较子树根节点Node与指定元素e的大小
* 如果 Node 更大
* ----在Node的左子树中继续找
* 如果 Node 更小
* ----如果Node的右子树不存在
* --------返回 Node
* ----如果Node的右子树存在
* --------搜索右子树的最小值
* --------如果该最小值比 e 大,返回 Node
* --------如果该最小值没有 e 大,在Node的右子树中继续找
* 如果 相等
* ----返回 Node
* @param node
* @param e
* @return
*/
private Node<E> floor(Node<E> node, E e) {
if (node == null) {
throw new IllegalArgumentException("no found!");
}
int comp = node.val.compareTo(e);
if (comp > 0) {
return floor(node.left, e);
}
if (comp < 0) {
Node<E> right = node.right;
if (right == null) {
return node;
} else {
Node<E> min = getMin(right);
if (min.val.compareTo(e) > 0) {
return node;
} else {
return floor(right, e);
}
}
}
return node;
}
/**
* 比指定元素大的最小值(天花板)
* @param e
* @return
*/
public E ceil(E e) {
return ceil(root, e).val;
}
/**
* 比较子树根节点Node与指定元素e的大小
* 如果 Node 更小
* ----在Node的右子树中继续找
* 如果 Node 更大
* ----如果Node的左子树不存在
* --------返回 Node
* ----如果Node的左子树存在
* --------搜索左子树的最大值
* --------如果该最大值比 e 大,或相等,在Node的左子树中继续找
* --------如果该最大值比 e 小,返回Node
* 如果 相等
* ----返回 Node
* @param node
* @param e
* @return
*/
private Node<E> ceil(Node<E> node, E e) {
if (node == null) {
throw new IllegalArgumentException("not found!");
}
int comp = node.val.compareTo(e);
if (comp < 0) {
return ceil(node.right, e);
}
if (comp > 0) {
Node<E> left = node.left;
if (left == null) {
return node;
} else {
Node<E> max = getMax(left);
if (max.val.compareTo(e) >= 0) {
return ceil(left, e);
} else {
return node;
}
}
}
return node;
}
private static <E extends Comparable<E>> BST<E> fromArray(E... arr) {
BST<E> bst = new BST<>();
for (E e : arr) {
bst.add(e);
}
return bst;
}
public static void main(String[] args) {
/**
* 10
* ......... .........
* 4 90
* ...
* 29
* ... ...
* 19 55
* ... .... ....
* 28 33 76
* ... ...
* 48 75
*/
BST<Integer> bst = fromArray(10, 4, 90, 29, 55, 33, 19, 76, 48, 75, 28);
bst.inOrder();
System.out.println(56 + " floor " + bst.floor(56));
System.out.println(40 + " ceil " + bst.ceil(40));
}
}
二分搜索树的一个性质:
中序遍历的结果是有序的。