1. 概念
二叉查找树(Binary Search Tree
)也称有序二叉树(Ordered Binary Tree
)、排序二叉树(Sorted Binary Tree
)。
二叉查找树是java的 TreeSet
和 TreeMap
类实现的基础。
二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log n)。
2. 特点
若任意结点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若任意结点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
任意结点的左、右子树也分别为二叉查找树。
没有键值相等的结点(no duplicate nodes)。
3. 实现
由于二叉查找树要求所有的节点都可以进行排序.所以编写时代码时需要一个 Comparable
泛型接口。
由于树的递归定义,二叉查找树的代码实现也基本上都是使用递归的函数,
3.1 继承关系
public class BinarySearchTree<T extends Comparable<T>>
3.2 定义节点
private static class TreeNode<T> {
T data;
TreeNode<T> left;
TreeNode<T> right;
public TreeNode(T data) {
this.data = data;
}
}
3.3 属性
//根节点
private TreeNode<T> root;
3.5 插入 void insert(T data)
public void insert(T data) {
root = insert(data, root);
}
private TreeNode<T> insert(T data, TreeNode<T> node) {
if (node == null) {
return new TreeNode<T>(data);
}
int result = node.data.compareTo(data);
if (result == 0) {
throw new IllegalArgumentException("has the same data :" + data.toString());
}
if (result > 0) {
node.left = insert(data, node.left);
} else if (result < 0) {
node.right = insert(data, node.right);
}
return node;
}
3.6 查找最小值 T min()
public T min() {
TreeNode<T> node = min(root);
return node == null ? null : node.data;
}
private TreeNode<T> min(TreeNode<T> node) {
if (node == null) {
return null;
}
if (node.left == null) {
return node;
}
return min(node.left);
}
3.7 查找最大值 T max()
public T max() {
TreeNode<T> node = max(root);
return node == null ? null : node.data;
}
private TreeNode<T> max(TreeNode<T> node) {
if (node == null) {
return null;
}
if (node.right == null) {
return node;
}
return max(node.right);
}
3.8 是否包含元素 boolean contains(T data)
public boolean contains(T data) {
return contains(data, root);
}
public boolean contains(T data, TreeNode<T> node) {
if (node == null) {
return false;
}
int result = node.data.compareTo(data);
if (result > 0) {
return contains(data, node.left);
} else if (result < 0) {
return contains(data, node.right);
}
return true;
}
3.9 删除元素 void remove(T data)
在二叉查找树种,删除是最复杂的实现。涉及三种情况:
被删除节点是树叶节点(没有子树):最简单,直接删除,将该节点置为null即可
被删除节点有一个子节点(左子树或右子树):是该节点的父节点指向该节点的子节点(左或右). 见图1
被删除节点有两个子节点:用其右子树中的最小值代替该节点上的值,删除其右子树上的最小值. 见图2
public void remove(T data) {
remove(data, root);
}
public TreeNode<T> remove(T data, TreeNode<T> node) {
if (data == null) {
return null;
}
int result = node.data.compareTo(data);
if (result > 0) {
node.left = remove(data, node.left);
} else if (result < 0) {
node.right = remove(data, node.right);
} else {
//如果被删除节点有两个儿子
if (node.left != null && node.right != null) {
TreeNode<T> minRight = find(node.right, true);
node.data = minRight.data; // 当前节点值被其右子树的最小值代替
node.right = remove(minRight.data, node.right); // 将右子树的最小值删除
} else if (node.left == null && node.right == null) {
node = null; // 如果被删除的节点只是一个叶子
} else if (node.left == null || node.right == null) { // 如果被删除节点只有一个儿子
node = (node.left != null) ? node.left : node.right;
}
}
return node;
}