下面是代码,各种功能完成方法组
/**
* 实现一个二叉搜索树
*
* 使用者: 数据容器
* 数据结构: 二叉搜索树(特殊的二叉树)
* 底层结构: 链表
*/
public class MyBSTree <T extends Comparable<T>> {
private Node root; // 我们持有的树的根节点
private int size;
/**
* 二叉搜索树的添加方法
* @param value : 要添加的内容
* @return: 添加是否成功
*/
public boolean add(T value) {
// 判断存储的内容是否为null: null没有办法比较大小
if (value == null){
throw new IllegalArgumentException("parame is null");
}
// 树是否为空 --> 添加元素就是根节点
if (isEmpty()){
root = new Node(value);
size++;
return true;
}
// 树不空 : 比较大小找到添加位置(遍历) --> 添加
Node mid = root; // 定义一个遍历结点
Node midF = null; // 用来记录遍历结点的父结点
int com = -1;
while (mid != null){
// 让当前遍历结点存储的内容和 要存储的内容 比较大小
com = mid.value.compareTo(value);
if (com < 0){
// 意味着value值比当前遍历结点大, 如果要存储, 用该存储到mid的right方法
midF = mid;
mid = mid.right;
} else if (com > 0){
// 意味着value值比当前遍历结点小, 如果要存储, 用该存储到mid的left方法
midF = mid;
mid = mid.left;
}else {
// 当前遍历的结点, 和要存储的值, 一样大
// 如果在一个二叉搜索树, 添加的数据重复了, 在理论上有三种常见的处理手法
// 1, 计数法
// 2, 拉链法
// 3, 修正的BSTree
// 实际操作的时候, 我们一般不允许添加重复元素
return false;
}
}
// 上述循环走完
if (com > 0){
midF.left = new Node(value);
} else {
midF.right = new Node(value);
}
size++;
return true;
}
/**
* 二叉搜索树的删除方法
* @param value : 要删除的内容
* @return : 删除是否成功
*/
public boolean remove(T value){
// 判断参数是否为null, 二叉搜索树不允许存储null
if (value == null){
throw new IllegalArgumentException("parame is null");
}
// 二叉搜索树是否为空
if (isEmpty()){
throw new RuntimeException("tree is empty");
}
// 先根据提供value找到这个值, 是三种情况
Node mid = root; // 定义一个遍历结点
Node midF = null;
while (mid != null){
int com = value.compareTo(mid.value);
if (com < 0){
// 这个查找的值比mid当前遍历结点要小, 如果存在在left方向
midF = mid;
mid = mid.left;
}else if (com > 0){
// 这个查找的值比mid当前遍历结点要大, 如果存在在right方向
midF = mid;
mid = mid.right;
}else {
// 当前遍历的mid就是要找的value值 --- 相等
break;
}
}
// 上述循环, 有两个跳出条件
// 1, mid == null -> 没有存储这个数据
// 2, 找到了, mid是要删除的内容
if (mid == null){
// 没有存储这个数据
return false;
}
// 先判断这个要删除的结点mid是不是双分支
if (mid.left != null && mid.right != null){
// 左右孩子都有, 是双分支 --> 先替换再删除
// 选right的最小值 --> 选取right子树的最left结点
// 先标记right子树根节点
Node min = mid.right;
Node minF = mid;
// 在right子树上, 向left移动
while (min.left != null){
minF = min;
min = min.left;
}
// min 就是要找的right子树的最小值 ---> 替换
mid.value = min.value;
// min就是替换结点
// minF就是替换结点的父结点
mid = min;
midF = minF;
}
// 处理要么是叶子, 要么是单分支
Node ch = mid.left != null ? mid.left : mid.right;
// 特殊情况
if (midF == null){
// 如果只有一个根结点, 要删除的还是根节点
// 根节点是一个单分支, 要删除的还是根节点
root = ch;
size--;
return true;
}
if (midF.left == mid){
midF.left = ch;
}else {
midF.right = ch;
}
size--;
return true;
}
// ----------------------------------------------------------
// 层级遍历
public List<T> leOrder(){
// MyDBLinkedList<T> tMyDBLinkedList = new MyDBLinkedList<>();
// List<T> list = new LinkedList<>();
LinkedList<T> list = new LinkedList<>();
// 创建一个队列
MyArrayQueue<Node> queue = new MyArrayQueue<>();
// 1, 把根节点入队列
queue.offer(root);
// 2, 循环: 队列不空
while (!queue.isEmpty()){
// 出队列一个元素
Node poll = queue.poll();
// 遍历
list.add(poll.value);
// 左右孩子入队列
if (poll.left != null){
queue.offer(poll.left);
}
if (poll.right != null){
queue.offer(poll.right);
}
}
return list;
}
// 前序遍历
// 后序遍历
public List<T> postOrder(){
// 存储遍历结果的容器
List<T> list = new LinkedList<>();
// 创建一个栈
MyArrayStack<Node> stack = new MyArrayStack<>();
// 1, 根节点入栈
stack.push(root);
// 2, 循环: 栈不空
while (!stack.isEmpty()){
// 出栈元素
Node pop = stack.pop();
// 头插法遍历
list.add(0, pop.value);
// 把出栈结点左右子结点入栈
if (pop.left != null){
stack.push(pop.left);
}
if (pop.right != null){
stack.push(pop.right);
}
}
return list;
}
//后序遍历
public List<T> postOrder2(){
List<T> list = new LinkedList<>();
postOrder2(root, list);
return list;
}
// 后序遍历的递归方法
private void postOrder2(Node node, List<T> list){
// 出口
if (node == null){
return;
}
// 左 右 根
postOrder2(node.left, list);// 遍历左子树
postOrder2(node.right, list);// 遍历右子树
list.add(node.value);// 遍历当前的根
}
// 中序遍历
public List<T> inOrder(){
// 创建一个容器, 保存遍历结果
List<T> list = new LinkedList<>();
// 栈
MyArrayStack<Node> stack = new MyArrayStack<>();
// 标记结点
Node mid = root;
// 循环: 栈不空 或者 标记结点不是null
while (!stack.isEmpty() || mid != null){
// 标记结点left序列全入栈
while (mid != null){
stack.push(mid);
mid = mid.left;
}
// 出栈一个元素
Node pop = stack.pop();
// 遍历
list.add(pop.value);
// 标记结点指向出栈元素的right孩子
mid = pop.right;
}
return list;
}
//中序遍历
public List<T> inOrder2(){
List<T> list = new LinkedList<>();
inOrder2(root, list);
return list;
}
// 中序遍历的递归方法
private void inOrder2(Node node, List<T> list){
// 出口
if (node == null){
return;
}
// 左 根 右
inOrder2(node.left, list);// 遍历左子树
list.add(node.value);// 遍历当前的根
inOrder2(node.right, list);// 遍历右子树
}
// 前序+中序建树
// 中序+后序建树:
public void buildTreeByInAndPostOrder(List<T> inOrder, List<T> postOrder){
root = buildTreeByInAndPostOrder2(inOrder, postOrder);
size = inOrder.size();
}
/**
* 根据中序和后序递归建树
* @param inOrder : 给定的中序
* @param postOrder: 给定的后序
* @return : 根据中序和后序,建成的树的根节点
*/
private Node buildTreeByInAndPostOrder2(List<T> inOrder, List<T> postOrder) {
// 出口
if (inOrder.isEmpty()){
return null;
}
if (inOrder.size() == 1){
return new Node(inOrder.get(0));
}
// 先获得根结点
T value = postOrder.get(postOrder.size() - 1);
// 获得根结点在中序中的位置
int index = inOrder.indexOf(value);
// left子树:
// 中序: 0 - index -1
// 后序: 0 - index -1
// right子树
// 中序: index+1 ~ size -1
// 后序: index ~ size -2
// 从原本的中序和后序中切割出, left子树的中序和后序
List<T> listLeftInOrder = inOrder.subList(0, index);
List<T> listLeftPostOrder = postOrder.subList(0, index);
// 根据 left子树的中序和后序 --> 递归构建left子树
Node left = buildTreeByInAndPostOrder2(listLeftInOrder, listLeftPostOrder);
// 从原本的中序和后序中切割出, right子树的中序和后序
List<T> listRightInOrder = inOrder.subList(index+1, inOrder.size());
List<T> listRightPostOrder = postOrder.subList(index, postOrder.size() -1);
// 根据 right子树的中序和后序 --> 递归构建right子树
Node right = buildTreeByInAndPostOrder2(listRightInOrder, listRightPostOrder);
// 构建当前的根节点
Node node = new Node(value, left, right);
return node;
}
public boolean isEmpty() {
return size == 0;
}
class Node{
T value; // 值域
Node left ;// 左指针域
Node right; // 右指针域
public Node(T value) {
this.value = value;
}
public Node(T value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
}
}