二叉树的删除
简单二叉树删除的思路
简单删除的规定
- 如果删除的是叶子节点,则删除该节点
- 如果删除的节点是非叶子节点,则将该节点的子树一起删除
简单删除的思路
- 先判断是是不是空树,是空树则直接返回,
- 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
- 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
- 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
- 如果第3,4步没有删除节点,则将左子树进行递归删除
- 如果第5步也没有删除节点,则应当向右子树进行递归删除
简单删除的代码实现(以删除4号节点为例)
找到4号节点并且删除4号节点时,在进行前序遍历时应该是1-2-3:下面进行仿真
在节点中的简单删除
public void delete(int no){
//* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
if(this.left!=null&&this.left.no==no){
this.left=null;
return;
}
//4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
if(this.right!=null&this.right.no==no){
this.right=null;
return;
}
//5如果第3,4步没有删除节点,则将左子树进行递归删除
if(this.left!=null){
this.left.delete(no);
}
//6. 如果第5步也没有删除节点,则应当向右子树进行递归删除
if(this.right!=null){
this.right.delete(no);
}
}
在二叉树的结构中进行删除的步骤实现
public void delete(int no){
//先判断该树的根节点是否为空
if(root!=null){
//判断该根节点是否和目标一致,如果一致则直接删除,置为空
if(root.no==no){
root=null;
//如果当前根节点不是要删除的节点,则需要递归删除
}else {
root.delete(no);
}
//如果为空则直接返回啦!
}else {
System.out.println("该树为空不能删除!");
return;
}
}
测试代码
package com.njupt.binaryTree;
/**
* Creat with IntelliJ IDEA
*
* @Auther:倔强的加瓦
* @Date:2021/07/23/11:16
* @Description:
*/
public class SimpleDelete {
public static void main(String[] args) {
BinaryTr binary = new BinaryTr();
NodeND node1 = new NodeND(1, "吴吴");
NodeND node2 = new NodeND(2, "亦亦");
NodeND node3 = new NodeND(3, "凡凡");
NodeND node4 = new NodeND(4, "签签");
NodeND node5 = new NodeND(5, "word");
NodeND node6 = new NodeND(6, "very big");
node1.left = node2;
node1.right = node4;
node2.left = node3;
node4.left = node5;
node4.right = node6;
//给根节点赋值
binary.root = node1;
System.out.println("没删除4号节点之前的前序遍历:");
binary.preSearch();
binary.delete(4);
System.out.println("删除4号节点之后的前序遍历");
binary.preSearch();
}
}
class BinaryTr {
public NodeND root;
//前序遍历的方法
public void preSearch() {
if (root == null) {
System.out.println("当前树为空");
return;
} else {
this.root.pre();
}
}
//删除节点的方法
public void delete(int no) {
//先判断该树的根节点是否为空
if (root != null) {
//判断该根节点是否和目标一致,如果一致则直接删除,置为空
if (root.no == no) {
root = null;
//如果当前根节点不是要删除的节点,则需要递归删除
} else {
root.delete(no);
}
//如果为空则直接返回啦!
} else {
System.out.println("该树为空不能删除!");
return;
}
}
}
class NodeND {
public int no;
public String name;
public NodeND left;
public NodeND right;
public NodeND(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Node1{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
/**
* 1. 先判断是是不是空树,是空树则直接返回,
* 2. 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
* 4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
* 5. 如果第3,4步没有删除节点,则将左子树进行递归删除
* 6. 如果第5步也没有删除节点,则应当向右子树进行递归删除
*/
public void delete(int no) {
//* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
//4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
if (this.right != null & this.right.no == no) {
this.right = null;
return;
}
if (this.left != null) {
this.left.delete(no);
}
if (this.right != null) {
this.right.delete(no);
}
}
//前序遍历
public void pre() {
//跟
System.out.println(this);
//左
if (this.left != null) {
this.left.pre();
}
//右
if (this.right != null) {
this.right.pre();
}
}
}
测试结果:
没删除4号节点之前的前序遍历:
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Node1{no=4, name='签签'}
Node1{no=5, name='word'}
Node1{no=6, name='very big'}
删除4号节点之后的前序遍历
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Process finished with exit code 0
复杂二叉树的删除
复杂二叉树的删除规定
规定:
如果删除的是叶子节点,则直接删除。
如果删除的是非叶子节点,则:
- 若非叶子节点的子节点只有一个,则将该子节点直接代替删除的节点
- 若非叶子结点的子节点有两个,则让左子节点代替原来删除的节点
复杂二叉树的删除思路
- 先判断是是不是空树,是空树则直接返回,
- 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
- 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则
1. 先判断是否为叶子节点,如果是叶子节点,则将this.left=null并且返回(结束递归删除)
2. 如果不是叶子节点,则有三种情况:
a. 有右子节点没有左子节点:将删除的节点置为该节点的右子节点:结束递归
b.有左子节点没有右子节点:将删除的节点置为该节点的左子节点:结束递归
c.左右子节点都有 :将删除的节点置为该节点的左子节节点:结束递归 - 如果当前节点的右子节点不为空,且就是要删除的节点则
1. 先判断是否为叶子节点,如果是叶子节点,则将this.right=null并且返回(结束递归删除)
2. 如果不是叶子节点,则有三种情况:
a. 有右子节点没有左子节点:将删除的节点置为该节点的右子节点
b.有左子节点没有右子节点:将删除的节点置为该节点的左子节点
c.左右子节点都有 :将删除的节点置为该节点的左子节节 - 如果第3,4步没有删除节点,则将左子树进行递归删除
- 如果第5步也没有删除节点,则应当向右子树进行递归删除
复杂删除的代码实现(以删除5号节点为例)
主要的核心代码实现:
public void betterDelete(int no) {
//1假设在左边找到了,先遍历左子节点,如果左边不为空,并且左边就是要删除的节点,则需要判断删除节点的左边是否为空
if (this.left != null && this.left.no == no) {
//1如果删除的就是叶子节点,即删除节点的左右都为空,则直接置空即可
if (this.left.left == null && this.left.right == null) {
this.left = null;
return;
//2如果删除的节点是非叶子节点,只有一个的情况,即左子节点为空,右子节点不为空
} else if (this.left.left == null && this.left.right != null) {
this.left = this.left.right;
return;
//剩下的情况是左子节点不为空右子节点为空和左右子节点都不为空,此时这两种情况都是将此删除节点的左子节点代替原来删除的节点
} else {
this.left = this.left.left;
return;
}
}
//如果左子树没有找到,假设找右子树找到了
if (this.right != null && this.right.no == no) {
//如果要删除的就是叶子节点,则将删除的节点直接置空
if (this.right.left == null && this.right.right == null) {
this.right = null;
return;
//如果删除的不是叶子节点,则有三种情况,第一种是左子节点没有,右子节点有
} else if (this.right.left == null && this.right.right != null) {
//将右子节点直接放到删除的位置
this.right = this.right.right;
return;
//按照规则,剩下的都是把左子节点的值放到要删除的节点
} else {
this.right = this.right.left;
return;
}
}
//如果左节点和右节点都不是,则递归查找目标节点
if (this.left != null) {
this.left.betterDelete(no);
}
if (this.right != null) {
this.right.betterDelete(no);
}
}
测试代码
package com.njupt.binaryTree;
/**
* Creat with IntelliJ IDEA
*
* @Auther:倔强的加瓦
* @Date:2021/07/23/11:16
* @Description:
*/
public class SimpleDelete {
public static void main(String[] args) {
BinaryTr binary = new BinaryTr();
NodeND node1 = new NodeND(1, "吴吴");
NodeND node2 = new NodeND(2, "亦亦");
NodeND node3 = new NodeND(3, "凡凡");
NodeND node4 = new NodeND(4, "签签");
NodeND node5 = new NodeND(5, "word");
NodeND node6 = new NodeND(6, "very big");
NodeND node7 = new NodeND(7, "55");
NodeND node8 = new NodeND(8, "11");
NodeND node9 = new NodeND(9, "烦烦");
NodeND node10 = new NodeND(10, "签签");
node1.left = node2;
node1.right = node4;
node2.left = node3;
node4.left = node5;
node4.right = node6;
node5.left=node7;
node5.right=node10;
node7.left=node8;
node7.right=node9;
//给根节点赋值
binary.root = node1;
/*
System.out.println("没删除4号节点之前的前序遍历:");
binary.preSearch();
binary.delete(4);
System.out.println("利用简单删除4号节点之后的前序遍历");
binary.preSearch();*/
System.out.println("没删除5号节点之前的前序遍历:");
binary.preSearch();
binary.betterDelete(5);
System.out.println("利用复杂规则删除5号节点之后的前序遍历");
binary.preSearch();
}
}
class BinaryTr {
public NodeND root;
//前序遍历的方法
public void preSearch() {
if (root == null) {
System.out.println("当前树为空");
return;
} else {
this.root.pre();
}
}
//删除节点的方法
public void delete(int no) {
//先判断该树的根节点是否为空
if (root != null) {
//判断该根节点是否和目标一致,如果一致则直接删除,置为空
if (root.no == no) {
root = null;
//如果当前根节点不是要删除的节点,则需要递归删除
} else {
root.delete(no);
}
//如果为空则直接返回啦!
} else {
System.out.println("该树为空不能删除!");
return;
}
}
//按照第二个规则删除的方法
public void betterDelete(int no){
//先判断该树的根节点是否为空
if (root != null) {
//判断该根节点是否和目标一致,如果一致则直接删除,置为空
if (root.no == no) {
root = null;
//如果当前根节点不是要删除的节点,则需要递归删除
} else {
root.betterDelete(no);
}
//如果为空则直接返回啦!
} else {
System.out.println("该树为空不能删除!");
return;
}
}
}
class NodeND {
public int no;
public String name;
public NodeND left;
public NodeND right;
public NodeND(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Node1{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
/**
* 1. 先判断是是不是空树,是空树则直接返回,
* 2. 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
* 4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
* 5. 如果第3,4步没有删除节点,则将左子树进行递归删除
* 6. 如果第5步也没有删除节点,则应当向右子树进行递归删除
*/
public void delete(int no) {
//* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
//4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
if (this.left != null) {
this.left.delete(no);
}
if (this.right != null) {
this.right.delete(no);
}
}
/**
* 规定:
* 如果删除的是叶子节点,则直接删除。
* 如果删除的是非叶子节点,则:
* 1. 若非叶子节点的子节点只有一个,则将该子节点直接代替删除的节点
* 2. 若非叶子结点的子节点有两个,则让左子节点代替原来删除的节点
*
* */
public void betterDelete(int no) {
//1假设在左边找到了,先遍历左子节点,如果左边不为空,并且左边就是要删除的节点,则需要判断删除节点的左边是否为空
if (this.left != null && this.left.no == no) {
//1如果删除的就是叶子节点,即删除节点的左右都为空,则直接置空即可
if (this.left.left == null && this.left.right == null) {
this.left = null;
return;
//2如果删除的节点是非叶子节点,只有一个的情况,即左子节点为空,右子节点不为空
} else if (this.left.left == null && this.left.right != null) {
this.left = this.left.right;
return;
//剩下的情况是左子节点不为空右子节点为空和左右子节点都不为空,此时这两种情况都是将此删除节点的左子节点代替原来删除的节点
} else {
this.left = this.left.left;
return;
}
}
//如果左子树没有找到,假设找右子树找到了
if (this.right != null && this.right.no == no) {
//如果要删除的就是叶子节点,则将删除的节点直接置空
if (this.right.left == null && this.right.right == null) {
this.right = null;
return;
//如果删除的不是叶子节点,则有三种情况,第一种是左子节点没有,右子节点有
} else if (this.right.left == null && this.right.right != null) {
//将右子节点直接放到删除的位置
this.right = this.right.right;
return;
//按照规则,剩下的都是把左子节点的值放到要删除的节点
} else {
this.right = this.right.left;
return;
}
}
//如果左节点和右节点都不是,则递归查找目标节点
if (this.left != null) {
this.left.betterDelete(no);
}
if (this.right != null) {
this.right.betterDelete(no);
}
}
//前序遍历
public void pre() {
//跟
System.out.println(this);
//左
if (this.left != null) {
this.left.pre();
}
//右
if (this.right != null) {
this.right.pre();
}
}
}
测试结果:
从图中可以看出,按照规则删除5号节点和后,左边子节点7就代替了5号节点的位置。
没删除5号节点之前的前序遍历:
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Node1{no=4, name='签签'}
Node1{no=5, name='word'}
Node1{no=7, name='55'}
Node1{no=8, name='11'}
Node1{no=9, name='烦烦'}
Node1{no=10, name='签签'}
Node1{no=6, name='very big'}
利用复杂规则删除5号节点之后的前序遍历
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Node1{no=4, name='签签'}
Node1{no=7, name='55'}
Node1{no=8, name='11'}
Node1{no=9, name='烦烦'}
Node1{no=6, name='very big'}
Process finished with exit code 0