本章内容基于数据结构与算法分析 java语言描述(原书第3版)
二叉查找树性质:对于树中的每个节点X,它的左子树中所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项。
所以二叉查找树要求所有的项都能够排序,在我实现的二叉查找树数据结构中,存储的元素均需实现比较器接口,实现其中的compareTo方法,这里我使用到Integer,它内部已经实现了compareTo方法。
BinarySearchTree.java
平衡二叉树中要有根节点作为初始节点,且类中定义了操作平衡二叉树的公共方法和其私有方法,其中比较核心的是定义了静态私有类BinaryNode,这个类是节点数据结构,其中有节点存储的元素element,左子节点left和右子节点right。
package tree;
import java.nio.BufferUnderflowException;
public class BinarySearchTree<E extends Comparable<? super E>> {
//根节点
private BinaryNode<E> root;
//构造函数初始化,设置root为null
public BinarySearchTree(){
root = null;
}
//设置二叉查找树为空(设置根节点为null)
public void makeEmpty(){
root = null;
}
//判断树是否为空(根节点是否为null)
public boolean isEmpty(){
return root == null;
}
//判断节点是否存在
public boolean contains(E element){
return contains(element,root);
}
//寻找最小节点
public E findMin(){
if(isEmpty()){
throw new BufferUnderflowException();
}
return findMin(root).element;
}
//寻找最大节点
public E findMax(){
if(isEmpty()){
throw new BufferUnderflowException();
}
return findMax(root).element;
}
//插入节点
public void insert(E element){
root = insert(element,root);
}
//删除节点
public void remove(E element){
root = remove(element,root);
}
//先序遍历打印出树所有节点
public void printTree(){
if(isEmpty()){
return;
}
printTree(this.root);
}
//contains的内部私有重载方法,element为要查找的节点,node为当前遍历到的节点
private boolean contains(E element,BinaryNode<E> node){
//判断当前遍历到节点是否为null
if(node == null){
return false;
}
//当前遍历节点的元素和要查询的元素进行比较
int compareResult = element.compareTo(node.element);
//如果结果小于0,则说明要查找的元素可能在当前遍历元素的左子节点
if(compareResult < 0){
return contains(element,node.left);
}
//或者在其右子节点
else if(compareResult > 0){
return contains(element,node.right);
}
//否则就相等,找到了匹配的节点元素
else{
return true;
}
}
//finMin的私有重载方法,入参node为当前遍历到的节点,因为二叉查找树的特殊性质,它左边的节点一定比右边的节点要小,所以一直递归循环找左子节点
private BinaryNode<E> findMin(BinaryNode<E> node){
//若节点为null
if(node == null){
return null;
}
//若左子节点为null,说明当前节点是最小的左子节点
else if(node.left == null){
return node;
}
//递归调用findMin,沿着左子节点进行查询
return findMin(node.left);
}
//findMax的私有重载方法,入参node为当前遍历到的节点,使用非递归方法一直向右去查找右子树最大的一个节点
private BinaryNode<E> findMax(BinaryNode<E> node){
//若节点不为null,使用非递归方式循环查找右子节点,直到找到有为空的右子节点,返回循环到的当前节点
if(node != null){
while(node.right != null){
node = node.right;
}
}
return node;
}
//插入节点
private BinaryNode<E> insert(E element,BinaryNode<E> node){
//找到左子节点或者右子节点为null时,实例化节点且返回
if(node == null){
return new BinaryNode<E>(element,null,null);
}
//使用入参的compareTo比较方法与当前遍历到的节点进行比较
int compareResult = element.compareTo(node.element);
//结果小于0,说明要插入的节点比当前遍历到的节点小
if(compareResult < 0){
//继续向其左子节点进行插入
node.left = insert(element,node.left);
}
//结果大于0,说明要插入的节点比当前遍历到的节点大
else if(compareResult > 0){
//继续向其右子节点插入
node.right = insert(element,node.right);
}
//返回当前遍历到的节点
return node;
}
//删除节点
private BinaryNode<E> remove(E element,BinaryNode<E> node){
if(node == null){
return node;
}
//要删除的元素与当前遍历到节点的元素进行比较
int compareResult = element.compareTo(node.element);
//若要删除的元素小于当前遍历到元素
if(compareResult < 0) {
//向其左子节点进行递归
node.left = remove(element, node.left);
}
//若要删除的元素大于当前遍历到元素
else if(compareResult > 0){
//向其右子节点进行递归
node.right = remove(element,node.right);
}
//当要删除的元素就是当前遍历到的节点的元素且当前节点的左右子节点都存在
else if(node.left != null && node.right != null){
//因为本树是平衡二叉树,要删除当前迭代到的节点且双子节点都存在则需用子节点来顶替当前位置,而右子节点及其下所有节点都比当前要删除的节点大,所以要找到右子节点中最小的一个来顶替位置
node.element = findMin(node.right).element;
//找到右子节点中最小节点顶替位置后要删除该最小节点之前的节点
node.right = remove(node.element,node.right);
}
//当递归遍历到的节点只有一侧子节点,直接让被删除节点等于其子节点,完成删除操作
else{
node = (node.left != null) ? node.left : node.right;
}
return node;
}
//先序遍历
private void printTree(BinaryNode<E> node){
//若当前遍历到的节点为null则啥事都不干
if(null == node){
return;
}
//打印出当前遍历到的节点元素
System.out.println(node.element);
//优先遍历其左子节点
printTree(node.left);
//再遍历其右子节点
printTree(node.right);
}
//静态内部节点实体类
private static class BinaryNode<E>{
//节点元素
E element;
//左子节点
BinaryNode<E> left;
//右子节点
BinaryNode<E> right;
BinaryNode(E theElement,BinaryNode<E> lt,BinaryNode<E> rt){
element = theElement;
left = lt;
right = rt;
}
BinaryNode(E theElement){
this(theElement,null,null);
}
}
}
BinarySearchTreeTest.java
package tree;
public class BinarySearchTreeTest {
public static void main(String[] args) {
BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<Integer>();
binarySearchTree.insert(6);
binarySearchTree.insert(2);
binarySearchTree.insert(3);
binarySearchTree.insert(4);
binarySearchTree.insert(5);
binarySearchTree.insert(1);
binarySearchTree.insert(8);
binarySearchTree.printTree();
System.out.println("是否包含数字2:"+binarySearchTree.contains(2));
System.out.println("开始删除元素2");
binarySearchTree.remove(2);
System.out.println("是否包含数字2"+binarySearchTree.contains(2));
System.out.println("最大值:"+binarySearchTree.findMax());
System.out.println("最小值:"+binarySearchTree.findMin());
System.out.println("当前平衡树是否为空:"+binarySearchTree.isEmpty());
System.out.println("设置树为空");
binarySearchTree.makeEmpty();
System.out.println("当前平衡树是否为空:"+binarySearchTree.isEmpty());
}
}