07.Java数据结构与算法之~二叉树的查找与删除
本文是上一篇文章的后续,详情请点击该链接
二叉树-查找指定结点
使用前序,中序,后序的方式来查询指定的结点
前序查找思路:
1.先判断当前结点是否等于要查找的,如果是相等,则返回当前结点
2.如果不等,则判断当前结点的左子结点是否为空,如果不为空,则递归前序查找
3.如果左递归前序查找,找到结点,则返回。否则继续判断当前结点的右子结点是否为空,如果不空,则继续向右递归前序
中序查找思路:
1.判断当前结点的左子结点是否为空,如果不为空,则递归中序查找
2.如果找到则返回,如果没找到,就和当前结点比较,如果是则返回当前结点,否则继续进行右递归的中序查找
3.如果右递归中序查找找到,就返回,否则返回null
后序查找思路:
1.判断当前节点的左子结点是否为空,如果不为空,则递归后序查找
2.如果找到就返回,如果没有找到,就判断当前结点的右子结点是否为空。如果不为空,则右递归进行后序查找,如果找到就返回。
3.如果左右结点都没有找到,就和当前结点进行比较,找到就返回,否则返回Null。
代码实现:
补充Tree接口
注:遍历方法在上一篇文章已经实现了,详情请点击上方链接,这篇文章就不重复叙述了。
不过在文章的最下面,会把完整的代码最终再发一次
public interface Tree {
//构建树
void CreateBinaryTree(Object tree, Object left, Object right);
//先序遍历
void PreOrder();
//中序遍历
void InfixOrder();
//后序遍历
void PostOrder();
//前序查找
Object preOrderSearch(Object root);
//中序查找
Object infixOrderSearch(Object root);
//后序查找
Object postOrder(Object root);
}
BinaryTree实现类
//前序查找
@Override
public Object preOrderSearch(Object root) {
Object res = null;
//判断二叉树是否为空
if(root != null) {
//比较当前是不是
if (this.root == root) {
return this;
}
//判断当前节点左子结点是否为空,如果不为空,则递归前序查找
//如果左递归找到则返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判断左递归是否找到,找到就返回,没找到就继续右递归
if(res != null){
return res;
}
//如果左递归没找到,就继续右递归查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//中序查找
@Override
public Object infixOrderSearch(Object root) {
Object res = null;
//判断二叉树是否为空
if(root != null) {
//判断当前节点左子结点是否为空,如果不为空,则递归前序查找
//如果左递归找到则返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判断左递归是否找到,找到就返回,没找到就继续比较当前结点
if(res != null){
return res;
}
//比较当前是不是
if (this.root == root) {
return this;
}
//如果左递归没找到,就继续右递归查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//后序查找
@Override
public Object postOrderSearch(Object root) {
Object res = null;
//判断二叉树是否为空
if(root != null) {
//左递归查找,如果左递归找到则返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判断左递归是否找到,找到就返回,没找到就继续右递归
if(res != null){
return res;
}
//如果左递归没找到,就继续右递归查找
if(this.right != null){
res = right.preOrderSearch(root);
}
//比较当前是不是
if (this.root == root) {
return this;
}
}else{
throw new NullPointerException();
}
return res;
}
//重写toString
@Override
public String toString() {
return (String) root;
}
测试类
//前序查找
Object preOrderSearch = A.preOrderSearch("E");
System.out.println(preOrderSearch);
//中序查找
Object infixOrderSearch = A.infixOrderSearch("G");
System.out.println(infixOrderSearch);
//后序查找
Object postOrderSearch = A.postOrderSearch("A");
System.out.println(postOrderSearch);
二叉树-删除结点
思路:
1.因为我们的二叉树是单向的,所以我们是判断当前节点的子结点是否需要删除节点,而不能去判断当前这个结点是不是需要删除的节点
2.如果当前结点的左子树不为空,并且左子结点就是需要删除的结点,就将this.left=null
3.如果当前结点的右子结点不为空,并且右子结点就是要删除的结点,就将this.right=null
4.如果2,3都没有删除结点,那么就需要向左子树进行递归删除
5.如果左子树没有成功,就递归右子树
补充Tree接口
//删除结点
void remove(Object root);
BinaryTree实现类
//递归删除结点
//1.如果删除的结点是叶子结点,则删除该结点
//2.如果删除的结点是非叶子结点,则删除该子树
@Override
public void remove(Object root) {
//判断二叉树是否为空
if(root != null){
//如果当前结点的左子结点不为空,并且左子结点就是要删除的结点,那么就置空并返回
if(left != null && left.root == root){
left = null;
return;
}
//如果当前结点的右子结点不为空,并且右子结点就是要删除的结点,那么就置空并返回
if(right != null && right.right == root){
right = null;
return;
}
//如果都没有就向左子树递归进行删除
if(left != null){
left.remove(root);
}
//如果左子树递归没删除就向右子树递归删除
if(right != null){
right.remove(root);
}
}else{
throw new NullPointerException();
}
}
最终代码
Tree接口
public interface Tree {
//构建树
void CreateBinaryTree(Object tree, Object left, Object right);
//先序遍历
void PreOrder();
//中序遍历
void InfixOrder();
//后序遍历
void PostOrder();
//前序查找
Object preOrderSearch(Object root);
//中序查找
Object infixOrderSearch(Object root);
//后序查找
Object postOrderSearch(Object root);
//删除结点
void remove(Object root);
}
BinaryTree实现类
public class BinaryTree implements Tree{
private BinaryTree left; //左子树
private BinaryTree right; //右子树
private Object root; //根结点
int count = 0;
//-------构造传值-------
public BinaryTree(Object data){
root = data;
}
@Override
//-------构建树------- 为了兼容接口统一Object
public void CreateBinaryTree(Object tree, Object left, Object right){
//强制转换
BinaryTree Tree = (BinaryTree) tree;
Tree.left = (BinaryTree)left;
Tree.right = (BinaryTree)right;
}
//-------先序遍历-------
@Override
public void PreOrder() {
//判断二叉树是否为空
if(root != null){
System.out.print(root + " ");
//判断左子节点是否为空
if(left != null){
left.PreOrder();
}
if(right != null){
right.PreOrder();
}
}else{
//说明树为空,空指针异常
throw new NullPointerException();
}
}
//-------中序遍历-------
@Override
public void InfixOrder() {
//判断二叉树是否为空
if(root != null){
//判断左子节点是否为空
if(left != null){
left.InfixOrder();
}
System.out.print(root + " ");
if(right != null){
right.InfixOrder();
}
}else{
//说明树为空,空指针异常
throw new NullPointerException();
}
}
//-------后序遍历-------
@Override
public void PostOrder() {
//判断二叉树是否为空
if(root != null){
//判断左子节点是否为空
if(left != null){
left.PostOrder();
}
if(right != null){
right.PostOrder();
}
System.out.print(root + " ");
}else{
//说明树为空,空指针异常
throw new NullPointerException();
}
}
//前序查找
@Override
public Object preOrderSearch(Object root) {
Object res = null;
//判断二叉树是否为空
if(root != null) {
//比较当前是不是
if (this.root == root) {
return this;
}
//判断当前节点左子节点是否为空,如果不为空,则递归前序查找
//如果左递归找到则返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判断左递归是否找到,找到就返回,没找到就继续右递归
if(res != null){
return res;
}
//如果左递归没找到,就继续右递归查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//中序查找
@Override
public Object infixOrderSearch(Object root) {
Object res = null;
//判断二叉树是否为空
if(root != null) {
//判断当前节点左子节点是否为空,如果不为空,则递归前序查找
//如果左递归找到则返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判断左递归是否找到,找到就返回,没找到就继续比较当前节点
if(res != null){
return res;
}
//比较当前是不是
if (this.root == root) {
return this;
}
//如果左递归没找到,就继续右递归查找
if(this.right != null){
res = right.preOrderSearch(root);
}
}else{
throw new NullPointerException();
}
return res;
}
//后序查找
@Override
public Object postOrderSearch(Object root) {
Object res = null;
//判断二叉树是否为空
if(root != null) {
//左递归查找,如果左递归找到则返回
if(this.left != null){
res = left.preOrderSearch(root);
}
//判断左递归是否找到,找到就返回,没找到就继续右递归
if(res != null){
return res;
}
//如果左递归没找到,就继续右递归查找
if(this.right != null){
res = right.preOrderSearch(root);
}
//比较当前是不是
if (this.root == root) {
return this;
}
}else{
throw new NullPointerException();
}
return res;
}
//递归删除结点
//1.如果删除的结点是叶子结点,则删除该结点
//2.如果删除的结点是非叶子结点,则删除该子树
@Override
public void remove(Object root) {
//判断二叉树是否为空
if(root != null){
//如果当前结点的左子结点不为空,并且左子结点就是要删除的结点,那么就置空并返回
if(left != null && left.root == root){
left = null;
return;
}
//如果当前结点的右子结点不为空,并且右子结点就是要删除的结点,那么就置空并返回
if(right != null && right.right == root){
right = null;
return;
}
//如果都没有就向左子树递归进行删除
if(left != null){
left.remove(root);
}
//如果左子树递归没删除就向右子树递归删除
if(right != null){
right.remove(root);
}
}else{
throw new NullPointerException();
}
}
//重写toString
@Override
public String toString() {
return (String) root;
}
}
Test测试类
public class Test {
public static void main(String[] args) {
Tree A = new BinaryTree("A");
Tree B = new BinaryTree("B");
Tree C = new BinaryTree("C");
Tree D = new BinaryTree("D");
Tree E = new BinaryTree("E");
Tree F = new BinaryTree("F");
Tree G = new BinaryTree("G");
A.CreateBinaryTree(A,B,C); //定义A的两个子节点
A.CreateBinaryTree(B,D,E); //定义B的两个子节点
A.CreateBinaryTree(C,F,G); //定义C的两个子节点
//前序遍历
A.PreOrder(); System.out.println();
//中序遍历
A.InfixOrder(); System.out.println();
//后序遍历
A.PostOrder(); System.out.println();
//前序查找
Object preOrderSearch = A.preOrderSearch("E");
System.out.println(preOrderSearch);
//中序查找
Object infixOrderSearch = A.infixOrderSearch("G");
System.out.println(infixOrderSearch);
//后序查找
Object postOrderSearch = A.postOrderSearch("A");
System.out.println(postOrderSearch);
//删除测试
A.remove("D");
A.PreOrder();
}
}