~~接着实现搜索二叉树,BST继承了BinaryTree(写在另一篇中了),由于是继承二叉树,搜索二叉树中只写了其特有的方法。本文章仅供学习参考使用,转载附明出处。
__方法包括:添加方法,删除方法,判断结点是否存在的方法。代码中BST的一个构造方法中需要加入比较器。为了防止是对引用数据类型进行比较多次比较。
意思大概是这样的,如果你在树的初始化中添加比较器,那么我们就按照比较器的比较逻辑来对比。如果你没加入比较器,我们就用引用类型自带(继承Comparable后)的比较逻辑来对比。这样的好处是可以灵活的改变比较的逻辑。比如一棵树你想比较年龄,另一棵树你想比较价格。此代码中你只要在传入的比较器中改变比较逻辑即可。想一想如果别人没有这个需求(需要不同的比较逻辑),那我们就不用传比较器。直接使用引用类型自带的比较逻辑即可。
除此之外还有一些给子类使用的的接口,比如afterAdd,afterRemove 这些都是为了下面写AVL树做铺垫。
代码如下
import java.util.Comparator;
import tree.BinaryTree.Node;
public class BST<E> extends BinaryTree<E> {
//引用类型的比较器
private Comparator<E> comparator;
//无参构造方法
public BST() {
}
//有比较器的构造方法
public BST(Comparator<E> comparator) {
this.comparator = comparator;
}
/*
添加方法
*/
public void add(E element) {
elementNotNullCheck(element);
//添加第一个节点
if (root == null) {
root = createNode(element, null);
size ++;
afterAdd(root);
return;
}
//添加的不是第一个节点
//用来记录 父节点位置
Node<E> parent = root;
//比较是从父节点开始的
Node<E> node = root;
//我们还要记下方向(左节点 or 右节点)
int cmp = 0;
while(node != null) {
//记录父节点和方向
cmp = compare(element, node.element);
parent = node;
if (cmp > 0) {
node = node.right;
}else if (cmp < 0) {
node = node.left;
}else {
//相等覆盖
//防止是引用类型 除了年龄还有别的属性
node.element = element;
return;
}
}
//创建新节点
Node<E> newNode = createNode(element, parent);
//插入父节点左右
if (cmp > 0) {
parent.right = newNode;
}else {
parent.left = newNode;
}
size ++;
afterAdd(newNode);
}
/*
创建节点的接口
*/
protected Node<E> createNode(E element, Node<E> parent){
return new Node<>(element, parent);
}
/*
添加node之后调整的接口
*/
protected void afterAdd(Node<E> node) {}
/*
删除后恢复平衡的方法
*/
protected void afterRemove(Node<E> node) {}
/*
删除元素方法
*/
public void remove(E element) {
//删除元素对应的结点
remove(node(element));
}
/*
分三大情况讨论
我们线讨论度为2的结点 有原因的 可以简化代码
*/
private void remove(Node<E> node) {
//结点为空
if(node == null) return;
size --;
//删除结点是度为2的结点
if (node.hasTwoChildren()) {
//找后继结点
Node<E> s = successor(node);
//后继节点的值覆盖原来结点
node.element = s.element;
//下面还要删除后继结点
node = s;
}
//删除node 结点(现在node的度必然为0 或者1)
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null) {//node 是度为1的结点
if (node == node.parent.left) {//node是左子节点
replacement.parent = node.parent;
node.parent.left = replacement;
}else {//node是右子节点
replacement.parent = node.parent;
node.parent.right = replacement;
}
afterRemove(node);
}else if (node.parent == null) {//node是叶子结点并且是根结点
root = null;
afterRemove(node);
}else {//是叶子结点 且不是根结点 直接删除
if (node == node.parent.left) {
node.parent.left = null;
}else {
node.parent.right = null;
}
afterRemove(node);
}
}
/*
查找一个节点是否存在
*/
private Node<E> node(E element){
//查找从根节点开始
Node<E> node = root;
while(node != null) {
int cmp = compare(element, node.element);
if (cmp == 0) {
//找到了
return node;
}else if (cmp > 0) {
node = node.right;
}else {
node = node.left;
}
}
//循环出来就是没找到啊
return null;
}
/*
是否包含元素方法
*/
public boolean contains(E element) {
return node(element) != null;
}
/*
搜索树 节点不能为空的判断方法
*/
public void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
/*
比较函数
*/
private int compare(E e1,E e2) {
if (comparator != null) {
return compare(e1, e2);
}
return ((Comparable<E>)e1).compareTo(e2);
}
}