import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/*
二叉搜索树非递归/递归实现增删查,递归/栈实现前中后序遍历,队列实现层级遍历,递归根据前中序值或中后序值建树
*/
//测试
class MyBSTDemo {
public static void main(String[] args) {
MyBST<Integer> myBST = new MyBST<>();
List<Integer> inOrder = new ArrayList<>();
inOrder.add(-8);
inOrder.add(-4);
inOrder.add(-2);
inOrder.add(-1);
inOrder.add(3);
inOrder.add(5);
inOrder.add(6);
inOrder.add(7);
inOrder.add(15);
inOrder.add(20);
List<Integer> preOrder = new ArrayList<>();
preOrder.add(5);
preOrder.add(-4);
preOrder.add(-8);
preOrder.add(-1);
preOrder.add(-2);
preOrder.add(3);
preOrder.add(15);
preOrder.add(6);
preOrder.add(7);
preOrder.add(20);
myBST.piBuildBST(preOrder, inOrder);//调用建树的方法
System.out.println(myBST.inOrder_Stack());
myBST.removeD(7);
myBST.addD(7);
System.out.println(myBST.inOrder_Stack());
// myBST.add(5);
// myBST.add(15);
// myBST.add(-4);
// myBST.add(-1);
// myBST.add(-8);
// myBST.add(3);
// myBST.add(6);
// myBST.add(20);
// myBST.add(7);
// myBST.add(-2);
// myBST.remove(5);
// System.out.println(myBST.preOrder_Stack());
// System.out.println(myBST.inOrder_Stack());
// System.out.println(myBST.postOrder_Stack());
// System.out.println(myBST.preOrder());
// System.out.println(myBST.inOrder());
// System.out.println(myBST.PostOrder());
// myBST.contains(5);
// myBST.remove(5);
}
}
public class MyBST<T extends Comparable<T>> {
private Node root;
private int size;
public int size() {
return size;
}
/**
* 判断树是否为空的方法
*
* @return true 树为空
*/
public boolean isEmpty() {
return size == 0 || root == null;
}
/**
* 添加一个值的节点的方法
*
* @param t 要添加的节点的值
* @return true 添加成功
*/
public boolean add(T t) {
if (t == null) throw new IllegalArgumentException("param is null");
if (isEmpty()) {
root = new Node(t);
size++;
return true;
}
Node mid = root;
Node midPar = null;
int comp = 0;
while (mid != null) {
comp = t.compareTo(mid.value);
//左边遍历
if (comp < 0) {
midPar = mid;
mid = mid.left;
//右边遍历
} else if (comp > 0) {
midPar = mid;
mid = mid.right;
} else {
//禁止存储重复值
return false;
}
}
//到这里了,mid代表要添加节点的位置,midPar标识要添加节点的父节点
//添加在左边
if (t.compareTo(midPar.value) < 0) {
midPar.left = new Node(t);
//添加在右边
} else {
midPar.right = new Node(t);
}
size++;
return true;
}
/**
* 递归增加一个结点的方法
*
* @param t 增加的结点的值
* @return true 增加成功
*/
public boolean addD(T t) {
if (t == null) throw new IllegalArgumentException("param is null");
int oldSize = size;
root = addD(root, t);
return size > oldSize;
}
private Node addD(Node root, T t) {
if (root == null) {
size++;
return new Node(t);
}
int comp = t.compareTo(root.value);
if (comp < 0) {
root.left = addD(root.left, t);
} else if (comp > 0) {
root.right = addD(root.right, t);
} else {
throw new RuntimeException("param is exist");
}
return root;
}
/**
* 判断一个值的节点是否存在的方法
*
* @param t 要判断的值
* @return true 存在
*/
public boolean contains(T t) {
if (t == null) throw new IllegalArgumentException("param is null");
if (isEmpty()) return false;
Node mid = root;
//没找到,没找完就一直找
while (mid != null) {
int com = t.compareTo(mid.value);
//继续左边找
if (com < 0) {
mid = mid.left;
//继续左边找
} else if (com > 0) {
mid = mid.right;
//找到了
} else {
return true;
}
}
//找完了,没找到
return false;
}
/**
* 递归删除一个结点的方法
*
* @param t 删除的值
* @return true 删除成功;
*/
public boolean removeD(T t) {
if (t == null) throw new IllegalArgumentException("param is null");
//树为空
if (isEmpty()) throw new RuntimeException("Tree is empty");
int oldSize = size;
root = removeD(root, t);
return size < oldSize;
}
private Node removeD(Node root, T t) {
if (root == null) {
//递归出口,一直找都没找到,知道找到空
return null;
}
int comp = t.compareTo(root.value);
//左子树递归删除
if (comp < 0) {
root.left = removeD(root.left, t);
} else if (comp > 0) {
//右子树递归删除
root.right = removeD(root.right, t);
} else {
//双分支,找到右子树最小结点替换再删除
if (root.left != null && root.right != null) {
Node min = root.right;
while (min.left != null) {
min = min.left;
}
root.value = min.value;
removeD(root, min.value);
} else {
//要删除的节点为单分支或者叶子节点,将要删除的节点的子节点返回给它的父节点
Node child = root.left != null ? root.left : root.right;
size--;
return child;
}
}
return root;
}
/**
* 删除一个节点的方法
*
* @param t 要删除的节点值
* @return true 删除成功
*/
public boolean remove(T t) {
if (t == null) throw new IllegalArgumentException("param is null");
//树为空
if (isEmpty()) throw new RuntimeException("Tree is empty");
//树不为空,分三种情况操作
Node mid = root;
Node midPar = null;
while (mid != null) {
int com = t.compareTo(mid.value);
if (com < 0) {
midPar = mid;
mid = mid.left;
} else if (com > 0) {
midPar = mid;
mid = mid.right;
} else {
break;
}
}
//如果mid为null,整个数都找完了,还没有找到要删除的值
if (mid == null) return false;
//第一:删除的节点为双分支,先找右子数的最小节点,
//将要删除的分支节点(只会是单分支或者叶子节点),进行替换再删除
if (mid.left != null && mid.right != null) {
Node minPar = mid;
Node min = mid.right;
//右子树的最小节点在最左侧的节点
while (min.left != null) {
minPar = min;
min = min.left;
}
//找到了右子树的最小节点,进行替换,删除放在后面,此时要删除的节点是右子树的最小节点
mid.value = min.value;
midPar = minPar;
mid = min;
}
//删除的节点为叶子节点或者单分支节点
//第二:要删除的节点是单分支节点
//获取要删除的分支的子节点
//如果是单分支,child直接获得对应的节点
//如果是叶子节点,child就是null
Node child = mid.left != null ? mid.left : mid.right;
//如果要删除的是根节点,根节点没有父节点,且根节点为单分支
if (midPar == null) {
root = child;
size--;
return true;
}
//判断要删除的节点是在父节点的位置
if (midPar.left == mid) {
midPar.left = child;
size--;
} else {
midPar.right = child;
size--;
}
return true;
}
//以上为集合类正常提供的方法
//---------------------------------------
//以下为树特有的方法
/**
* 栈实现前序遍历的方法(根-左-右)
*
* @return 存储遍历后的值的链表
*/
public List<T> preOrder_Stack() {
if (isEmpty()) throw new RuntimeException("Tree is empty");
//存储遍历值的链表
List<T> list = new ArrayList<>();
//用于深度遍历的栈
Stack<Node> stack = new Stack<>();
//根结点入栈
stack.push(root);
//栈不为空,就循环
while (!stack.isEmpty()) {
Node pop = stack.pop();//弹栈
list.add(pop.value);//将弹栈的节点的值存入链表
if (pop.right != null) stack.push(pop.right);//先将右节点压栈
if (pop.left != null) stack.push(pop.left);//再将左节点压栈
}
return list;
}
/**
* 栈实现中序遍历的方法(左-根-右)
*
* @return 存储遍历后的值的链表
*/
public List<T> inOrder_Stack() {
if (isEmpty()) throw new RuntimeException("Tree is empty");
List<T> list = new ArrayList<>();
Stack<Node> stack = new Stack<>();
Node mid = root;//标记根节点
//栈不为空或者标记节点不为空
while (!stack.isEmpty() || mid != null) {
//标记根节点有左节点就一直把所有的左节点压栈
while (mid != null) {
stack.push(mid);
mid = mid.left;
}
//左节点都压完栈了就弹栈一次
Node pop = stack.pop();
//存储弹出结点的值
list.add(pop.value);
//将根节点标记为弹出的结点的右节点
mid = pop.right;
}
return list;
}
/**
* 栈实现后续遍历的方法(左-右-根)
*
* @return 存储遍历后的值的链表
*/
public List<T> postOrder_Stack() {
if (isEmpty()) throw new RuntimeException("Tree is empty");
List<T> list = new ArrayList<>();
Stack<Node> stack = new Stack<>();
stack.push(root);
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;
}
/**
* 递归前序遍历的方法
*
* @return 存储前序遍历值的链表
*/
public List<T> preOrder() {
List<T> list = new ArrayList<>();
preOrder(root, list);
return list;
}
private void preOrder(Node root, List<T> list) {
if (root == null) return;
list.add(root.value);
preOrder(root.left, list);
preOrder(root.right, list);
}
/**
* 递归中序遍历的方法
*
* @return 存储中序遍历值的链表
*/
public List<T> inOrder() {
List<T> list = new ArrayList<>();
inOrder(root, list);
return list;
}
private void inOrder(Node root, List<T> list) {
if (root == null) return;
inOrder(root.left, list);
list.add(root.value);
inOrder(root.right, list);
}
/**
* 递归后序遍历的方法
*
* @return 存储后序遍历值的链表
*/
public List<T> PostOrder() {
List<T> list = new ArrayList<>();
PostOrder(root, list);
return list;
}
private void PostOrder(Node root, List<T> list) {
if (root == null) return;
PostOrder(root.left, list);
PostOrder(root.right, list);
list.add(root.value);
}
/**
* 利用队列对数进行层级遍历
*
* @return 层级遍历值的链表
*/
public List<T> levelOrder() {
List<T> list = new ArrayList<>();
MyListQueen<Node> queen = new MyListQueen<>();//自己实现的线性队列
queen.offer(root);//根节点入队列
while (!queen.isEmpty()) {
//队列不为空就出队列一个
Node poll = queen.poll();
list.add(poll.value);
//从左至右入队列
if (poll.left != null) queen.offer(poll.left);
if (poll.right != null) queen.offer(poll.right);
}
return list;
}
/**
* 根据二叉搜索树的中序和后序遍历值来新建一个树
*
* @param inOrder 中序遍历值:确定根的位置和左右子树的成员
* @param postOrder 后序遍历:尾值确认根节点
*/
public void ipBuildBST(List<T> inOrder, List<T> postOrder) {
root = ipBuildRoot(inOrder, postOrder);
size = inOrder.size();
}
//inOrder [-8, -4, -2, -1, 3, 5, 6, 7, 15, 20]
//postOrder[-8, -2, 3, -1, -4, 7, 6, 20, 15, 5]
private Node ipBuildRoot(List<T> inOrder, List<T> postOrder) {
//递归出口,切割后的序列如果为空就是没有节点了,如果为1就是一个叶子节点
if (inOrder.size() == 0) return null;
if (inOrder.size() == 1) return new Node(postOrder.get(0));
//后序的最后一个值就是根节点的值
T nodeValue = postOrder.get(postOrder.size() - 1);
//根节点所在中序遍历中的下标
int index = inOrder.indexOf(nodeValue);
//切割得左子树的中序,切割方法左闭右开
List<T> leftInOrder = inOrder.subList(0, index);
//切割得左子树的后序
List<T> leftPostOrder = postOrder.subList(0, index);
//切割得右子树的中序
List<T> rightInOrder = inOrder.subList(index + 1, inOrder.size());
//切割得右子树的后序
List<T> rightPostOrder = postOrder.subList(index, postOrder.size() - 1);
//根据根节点的值创建根节点
Node node = new Node(nodeValue);
//递归创建根节点的左子树所有节点
node.left = ipBuildRoot(leftInOrder, leftPostOrder);
//递归创建根节点的右子树的所有节点
node.right = ipBuildRoot(rightInOrder, rightPostOrder);
//返回根节点
return node;
}
/**
* 根据二叉树的前序和中序来建树
*
* @param preOrder 前序链表
* @param inOrder 中序链表
*/
public void piBuildBST(List<T> preOrder, List<T> inOrder) {
root = piBuildRoot(preOrder, inOrder);
size = inOrder.size();
}
//preOrder [5, -4, -8, -1, -2, 3, 15, 6, 7, 20]
//inOrder [-8, -4, -2, -1, 3, 5, 6, 7, 15, 20]
private Node piBuildRoot(List<T> preOrder, List<T> inOrder) {
//递归出口
if (inOrder.size() == 0) return null;
if (inOrder.size() == 1) return new Node(preOrder.get(0));
//获取根节点的值,前序的首元素
T rootValue = preOrder.get(0);
//根据中序的得出根节点的位置
int index = inOrder.indexOf(rootValue);
//切割得左子树的中序,切割方法左闭右开
List<T> leftInOrder = inOrder.subList(0, index);
//切割得左子树的前序
List<T> leftPreOrder = preOrder.subList(1, index + 1);
//切割得右子树的中序
List<T> rightInOrder = inOrder.subList(index + 1, inOrder.size());
//切割得右子树的前序
List<T> rightPreOrder = preOrder.subList(index + 1, preOrder.size());
Node node = new Node(rootValue);
//递归求子节点
node.left = piBuildRoot(leftPreOrder, leftInOrder);
node.right = piBuildRoot(rightPreOrder, rightInOrder);
return node;
}
//节点类
private class Node {
private T value;//数据域
private Node left;//左分支
private Node right;//右分支
private Node(T value) {
this.value = value;
}
}
}
Java实现: 二叉搜索树非递归/递归增删查,栈和递归实现前中后序遍历,队列实现层级遍历,递归根据前中序值或中后序值建树
最新推荐文章于 2021-07-12 23:53:08 发布
该代码实现了一个二叉搜索树(BST),包括非递归和递归方式的增删查操作,以及前中后序遍历。此外,还提供了根据前序和中序遍历值重建二叉树的功能。代码中使用栈实现了各种遍历方法,并提供了层级遍历。测试部分展示了如何使用这些功能。
摘要由CSDN通过智能技术生成