查询二叉树是平衡树->红黑树的基础,红黑树是TreeMap和TreeSet实现的基础。
深度:根到任意节点的唯一路径长,根节点的深度是零
高度:从节点到一片树叶的最长路径长,树叶的高度是零
二叉树:每个节点都不能有多余两个的儿子
public class BinarySearchTree<T extends Comparable<? super T>> {
// 树的每个节点都是一个Node
private static class Node<T> {
/**
* 构造方法
*/
Node(T element) {
this(element, null, null);
}
/**
* 构造方法
*/
Node(T element, Node<T> lt, Node<T> rt) {
this.element = element;
this.left = lt;
this.right = rt;
}
// 每个节点的3个属性
T element; // 要存储的值
Node<T> left; // 左节点
Node<T> right; // 右节点
}
/**
* 根节点
*/
private Node<T> root;
/**
* 构造方法
*/
public BinarySearchTree() {
root = null;
}
/**
* 设置树为空树
*/
public void makeEmpty() {
root = null;
}
/**
* 判断树是否是空树
*/
public boolean isEmpty() {
return root == null;
}
/**
* 判断当前树中是否包含元素为t的节点
*/
public boolean contains(T t) {
return contains(root, t);
}
private boolean contains(Node<T> root, T t) {
if (root == null)
return false;// 空树返回false
int i = t.compareTo(root.element);
if (i > 0) // 比较节点右儿子
return contains(root.right, t);
else if (i < 0)// 比较节点左儿子
return contains(root.left, t);
else
return true;
}
/**
* 查找最小值
*/
public T findMin() {
if (isEmpty()) {
throw new NullPointerException();
}
return findMin(root).element;
}
/**
* 递归 :比较耗资源
*/
private Node<T> findMin(Node<T> root) {
if (root.left == null)
return root;
return findMin(root.left);
}
/**
* 查找最大值
*/
public T findMax() {
if (isEmpty()) {
throw new NullPointerException();
}
return findMax(root).element;
}
/**
* 建议方式
*/
private Node<T> findMax(Node<T> root) {
while (root.right != null) {
root = root.right;
}
return root;
}
/**
* 添加元素
*/
public void add(T t) {
root = add(root, t);
}
/**
* 过程
* 这里不考虑重复元素
* 重复元素,可以在Node<T>中加一个计数的域来处理,节省空间
* 还可以保存在一个辅助数据结构中,树||表?
*/
private Node<T> add(Node<T> node, T t) {
if (node == null) {
return new Node<T>(t);
}
int i = t.compareTo(node.element);
if (i > 0)
node.right = add(node.right, t);
else if (i < 0)
node.left = add(node.left, t);
else
; // 相等的不考虑
return node;
}
/**
* 删除元素
*/
public void remove(T t) {
remove(root, t);
}
/**
* 过程 删除节点只有一个儿子,直接删除节点, 用其儿子替换
* 删除节点有两个儿子,取右儿子节点下的最小值 替换删除节点
*/
private Node<T> remove(Node<T> node, T t) {
if (node == null) {
return node;
}
int i = t.compareTo(node.element);
if (i > 0) {
node.right = remove(node.right, t);
} else if (i < 0) {
node.left = remove(node.left, t);
} else if (node.right != null && node.left != null) {// 删除节点有两个儿子
node.element = findMin(node.right).element;
node.right = remove(node.right, node.element);
} else {// 删除节点有一个儿子,或者没有儿子
node = node.left == null ? node.right : node.left;
}
return node;
}
/**
* 打印
*/
public void printTree() {
printTree(root);
}
/**
* 中序遍历:从小到大
*/
private void printTree(Node<T> node) {
if (node != null) {
printTree(node.left);// 先打印小的
System.out.println(node.element); // 打印自己
printTree(node.right);// 打印大的
}
}
public static void main(String[] args) {
BinarySearchTree<Integer> inter = new BinarySearchTree<Integer>();
System.err.println(inter.isEmpty());
inter.add(7);
inter.add(4);
inter.add(11);
inter.add(2);
inter.add(1);
inter.add(3);
inter.add(6);
inter.add(5);
inter.add(9);
inter.add(10);
inter.add(8);
System.err.println(inter.isEmpty());
System.err.println(inter.contains(4));
System.err.println(inter.findMax());
System.err.println(inter.findMin());
inter.remove(7);
inter.printTree();
}
}
输出:true
false
true
11
1
1
2
3
4
5
6
8
9
10
11
后续遍历:1、3、2、5、6、4 、8、10、9、11、7
先序便利:7、4、2、1、3、6、5、11、9、8、10
如果删除次数不多,通常使用懒删除,即删除元素时它仍然留在树中,只是被标记删除。这特别在重复的时候特别有用,可以对计数域 -1
如果树中实际节点和删除节点一样多,那么树的深度预计只上升一个小的常数。
如果被删除的项是重新插入的,那么分配一个新单元的开销就避免了。