提供添加,删除,搜索,和三种遍历方式,可重点看这些方法的注释
package bst;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class BST<E extends Comparable<E>> {
//封装私有内部类,Node类不向用户提供
private class Node {
private E e;
private Node left;
private Node right;
public Node(E e) {
this.e = e;
left = null;
right = null;
}
}
private Node rootnode;
private int size;
// 构造函数
public BST() {
rootnode = null;
size = 0;
}
// 获取当前二叉树有多少个节点
public int getSize() {
return size;
}
// 判断当前二分搜索树是否为空
public boolean isEmpty() {
return size == 0;
}
// 向二叉树中添加元素,提供给用户的公共接口,内部封装了一个添加的私有方法
public void add(E e) {
rootnode = add(rootnode, e);
}
// 从根节点为node的二分搜索树中添加元素e
private Node add(Node node, E e) {
// 如果当前的搜索树为空,则创建一个节点,将e赋值给该节点
if (node == null) {
size++;
return new Node(e);
}
// 如果当前e小于当前节点的值,则在以node的左孩子节点为根节点的搜索树进行递归添加
else if (e.compareTo(node.e) < 0) {
node.left = add(node.left, e);
// 如果当前e大于当前节点的值,则在以node的右孩子节点为根节点的搜索树进行递归添加
} else if (e.compareTo(node.e) > 0) {
node.right = add(node.right, e);
}
// 最后返回已经添加完元素e的以node为根节点的二分搜索树
return node;
}
// 搜索元素e,该方法为提供给用户的公共接口,内部封装了搜索的私有方法
public boolean search(E e) {
return search(rootnode, e);
}
// 从根节点为node的搜索树中搜索元素e
private boolean search(Node node, E e) {
// 如果用户传进来的搜索树为空,则直接返回false
if (node == null)
return false;
// 如果当前节点的值等于e,则直接返回true
if (e.compareTo(node.e) == 0)
return true;
// 如果当前节点的值大于e,则在node节点的右子树中递归搜索
if (e.compareTo(node.e) > 0)
return search(node.right, e);
// 如果当前节点的值小于e,则在node节点的左子树中递归搜索
else
return search(node.left, e);
}
// 前序遍历搜索树
public void preNode() {
preNode(rootnode);
}
// 前序遍历从以根节点为node的搜索树
private void preNode(Node node) {
// 如果搜索树为空,直接返回,此为递归的出口
if (node == null) {
return;
}
// 打印根节点
System.out.println(node.e);
// 继续遍历根节点的左子树
preNode(node.left);
// 继续遍历根节点的右子树
preNode(node.right);
}
// 前序遍历非递归的方式
public void preNodeNR() {
preNode(rootnode);
}
// 非递归遍历以node为根节点的搜索树(用栈来消除递归)
private void preNodeNR(Node node) {
// 定义一个栈
Stack<Node> stack = new Stack<>();
// 将当前节点node传入到栈中
stack.push(node);
// 当栈不为空时
while (!stack.isEmpty()) {
// 取出栈顶元素,并且打印
Node cur = stack.pop();
System.out.println(cur.e);
// 判断取出的当前节点的子右树是否为空,如果为空,则将其右子树放入栈中,因为栈是先进后出的结构,所以先放入右子树
if (node.right != null)
stack.push(node.right);
// 判断取出的当前节点的左子树是否为空,如果为空,则将其左子树放入栈中
if (node.left != null)
stack.push(node.left);
}
}
// 中序遍历
public void inNode() {
inNode(rootnode);
}
private void inNode(Node node) {
if (node == null) {
return;
}
inNode(node.left);
System.out.println(node.e);
inNode(node.right);
}
// 后续遍历
public void lastNode() {
lastNode(rootnode);
}
private void lastNode(Node node) {
// TODO Auto-generated method stub
if (node == null) {
return;
}
lastNode(node.left);
lastNode(node.right);
System.out.println(node.e);
}
// 层序遍历
public void levelNode() {
levelNode(rootnode);
}
// 层序遍历是借助队列这种数据结构,先进先出,一层一层地遍历
private void levelNode(Node node) {
// 初始化一个队列
Queue<Node> queue = new LinkedList<>();
// 将搜索树添加到队列
queue.add(rootnode);
// 当队列不为空时
while (!queue.isEmpty()) {
// 取出队首的节点,删除并且打印该节点的值
Node top = queue.remove();
System.out.println(top.e);
// 如果队首节点的左子树不为空,则将其左子树添加到队列
if (top.left != null)
queue.add(top.left);
// 如果队首节点的右子树不为空,则将其右子树添加到队列
if (top.right != null)
queue.add(top.right);
}
}
// 找出二分搜索树中元素值最小的节点,由于二分搜索树的特点,最左侧的节点即为元素值最小的节点
public E minimum() {
// minnode为元素值最小的节点
Node minnode = minimum(rootnode);
E min = minnode.e;
return min;
}
private Node minimum(Node node) {
// 如果当前节点的左孩子为空,则返回该节点
if (node.left == null)
return node;
// 如果当前节点的左孩子不为空,则递归node的左孩子
return minimum(node.left);
}
// 找出二分搜索树中元素值最大的节点,由于二分搜索树的特点,最右侧的节点即为元素值最大的节点
public E maxmum() {
Node maxnode = maxmum(rootnode);
E max = maxnode.e;
return max;
}
private Node maxmum(Node node) {
if (node.right == null)
return node;
return maxmum(node.right);
}
// 删除元素值最小的节点,返回该节点的值
public E delMinmum() {
E res = minimum();
delMinmum(rootnode);
return res;
}
private Node delMinmum(Node node) {
// 如果当前节点的左孩子为空,则将其右子树取出,并将node的右孩子的引用置为空,返回已经删除最小元素的右子树
if (node.left == null) {
Node rightnode = node.right;
node.right = null;
size--;
return rightnode;
}
// 从宏观的角度来看,delMinmum(node.left)返回的是已经删除了最小节点的子树,则最后将该子树作为根节点的左子树进行拼接
node.left = delMinmum(node.left);
// 返回以node为根节点,且已经删除了最小节点的搜索树
return node;
}
// 删除元素值最大的节点,返回该节点的值,该方法与上一个方法原理是类似的。
public E delMaxmum() {
E res = maxmum();
delMaxmum(rootnode);
return res;
}
private Node delMaxmum(Node node) {
if (node.right == null) {
Node leftnode = node.left;
node.left = null;
size--;
return leftnode;
}
node.right = delMinmum(node.right);
return node;
}
// 删除某一个节点
public E remove(E e) {
removeE(rootnode, e);
return e;
}
// 在根节点为node的搜索树中删除元素值为e的这个节点
private Node removeE(Node node, E e) {
// 如果node为空,则直接返回空
if (node == null)
return null;
// 如果e大于当前节点的值,则递归搜索其右子树
if (e.compareTo(node.e) > 0) {
// 从宏观的角度来看,removeE(node.right,e)返回的是已经删除了元素值为e的节点的右子树,直接与根节点进行拼接
node.right = removeE(node.right, e);
// 返回以node为根节点,且已经删除了最小节点的搜索树
return node;
}
// 左子树的原理与右子树的递归相似
else if (e.compareTo(node.e) < 0) {
node.left = removeE(node.left, e);
return node;
}
// 如果以上两种情况都不是,即e的值与node的元素值相等,此时还有三种情况需要讨论
else {
// 递归遍历发现当前node的左子树为空,则返回node的右子树
if (node.left == null) {
Node right = node.right;
node.right = null;
size--;
return right;
}
// 递归遍历发现当前node的右子树为空,则返回node的左子树
else if (node.right == null) {
Node left = node.left;
node.left = null;
size--;
return left;
}
// 递归遍历发现当前node的左右孩子都不为空,此时将右子树中最小的节点successor替代node,因为该节点一定比node的左子树大,比node的
// 右子树小
else {
// 取出当前node右子树中最小的节点
Node successor = minimum(node.right);
// delMinmum(node.right)返回删除了successor的右子树
Node rightnode = delMinmum(node.right);
// 将rightnode拼接到successor的右孩子
successor.right = rightnode;
// 将node的左子树拼接到successor的左孩子
successor.left = node.left;
// 删除node
node.left = node.right = null;
// 返回以successor为根节点的搜索树
return successor;
}
}
}
// 判断搜索树中有没有元素值为e的节点
public boolean contains(E e) {
return contains(rootnode, e);
}
private boolean contains(Node node, E e) {
if (node == null)
return false;
else {
if (e.compareTo(node.e) > 0)
return contains(node.right, e);
else if (e.compareTo(node.e) > 0)
return contains(node.left, e);
else if (e.compareTo(node.e) == 0)
return true;
}
return false;
}
}