一:删除节点
删除节点比较复杂
步骤:
1.找到需要被删除的节点
2.判断该节点的类型
2.1该节点是叶子节点,直接修改父节点的引用值为null即可
2.2该节点有一个子节点,修改父节点得引用,将该节点的父节点的应用指向该节点的子节点(相当于隔开该节点)
2.3该节点有两个子节点,需要是由该节点的中序后继来替代该节点
节点的中序后继:
指的是比该节点大的且是最接近该节点的节点
二:代码实现
1.创建节点Node
public class Node {
//数据项
long data;
//左子节点
Node leftChild;
//右子节点
Node rightChild;
//构造
public Node(long value){
this.data = value;
}
}
2.删除节点
//删除二叉树节点
public class Tree {
//根节点
public Node root;
//插入节点
public void insert(long value){
//1.新建准备插入的节点
Node newNode = new Node(value);
//2.当前节点
Node current = root;
//3.父节点
Node parent;
//首次插入,根节点 = null
if (root == null){
root = newNode;
return;
}else{
while (true){
//非首次插入
//父节点指向当前节点
parent = current;
//比较根节点和value的值大小
if (current.data > value){
//根节点 > value , 向左走
current = current.leftChild;
//当走到叶子节点的时候
if (current == null){
//新节点插入 父节点的左子节点
parent.leftChild = newNode;
return;
}
}else{
//向右走
current = current.rightChild;
//走到叶子节点
if (current == null){
//新节点插入 父节点的右子节点
parent.rightChild = newNode;
return;
}
}
}
}
}
//删除节点
public boolean deleteNode(long value){
//引用当前节点
Node current = root;
//引用父节点
Node parent = root;
//判断是否为左子节点,默认true
boolean isLeftChild = true;
//1.查找节点
while (current.data != value){
parent = current;
if (current.data > value){
current = current.leftChild;
isLeftChild = true;
}else{
current = current.rightChild;
isLeftChild = false;
}
//如果找不到
if (current == null){
return false;
}
}
//2.删除节点
//2.1如果被删除的节点是叶子节点的情况
if (current.leftChild == null && current.rightChild == null){
//如果只有一个根节点,且刚好找到
if (current == root){
root = null;
}
if (isLeftChild){
//如果是左子节点
parent.leftChild = null;
}else{
//如果是右子节点
parent.rightChild = null;
}
}
//2.2如果被删除的节点有一个子节点的情况
else if (current.leftChild != null && current.rightChild == null){
//只有左子节点
//如果找到的节点是根节点
if (current == root){
root = current.leftChild;
}
//还要判断是在根节点的左边还是右边
else if (current.data < root.data){
//被删除的节点在根节点的左边
parent.leftChild = current.leftChild;
}else{
//被删除的节点在根节点的右边
parent.rightChild = current.leftChild;
}
}else if (current.leftChild == null && current.rightChild != null){
//只有右子节点
//如果找到的节点是根节点
if (current == root){
root = current.rightChild;
}
//还要判断是在根节点的左边还是右边
else if (current.data < root.data){
//被删除的节点在根节点的左边
parent.leftChild = current.rightChild;
}else{
//被删除的节点在根节点的右边
parent.rightChild = current.rightChild;
}
}
//2.3如果被删除的节点有两个子节点的情况
else {
//先找到该节点的中序后继节点:
Node tmp = getReplaceNode(current);
//现在tmp 就是中序后继节点
//如果删除的是root节点
if (current == root){
root = tmp;
}
//不是根节点 , 那就判断该节点是在其父节点的左子节点还是在其父节点的右子节点
else if (isLeftChild){
//是左子节点
parent.leftChild = tmp;
}else{
//是右子节点
parent.rightChild = tmp;
}
//注意: 替换完成后,还需要引用回旧节点的左节点数据
//其右节点数据已经在中序后继方法中引用回来了,这里无需再写
tmp.leftChild = current.leftChild;
}
return true;
}
//查找中序后继方法
public static Node getReplaceNode(Node deleteNode){
Node replaceNode = deleteNode;
Node replaceParentNode = deleteNode;
Node current = deleteNode.rightChild;
while (current != null){
replaceParentNode = replaceNode;
replaceNode = current;
current = current.leftChild;
}
//判断中序后继节点是否是deleteNode的右子节点(这种情况是因为删除节点的右子节点没有左子节点)
if (replaceNode != deleteNode.rightChild){
//中序后继节点的右子节点成了中序后继节点的父节点的左子节点
replaceParentNode.leftChild = replaceNode.rightChild;
//同时被删除节点的右子节点成了中序后继节点的右节点
replaceNode.rightChild = deleteNode.rightChild;
}
return replaceNode;
}
//中序遍历
//参数localNode 代表根节点
public void inOrder(Node localNode){
if (localNode != null){
//1.中序遍历左子树
inOrder(localNode.leftChild);
//2.访问根节点
System.out.println(localNode.data);
//3.中序遍历右子树
inOrder(localNode.rightChild);
}
}
}
3.测试
public class Test {
public static void main(String[] args) {
Tree tree = new Tree();
//插入数据
tree.insert(8);
tree.insert(3);
tree.insert(6);
tree.insert(10);
tree.insert(1);
tree.insert(9);
tree.insert(100);
//中序遍历
tree.inOrder(tree.root); // 1 3 6 8 9 10 100
//1.第一种情况:被删除的节点是叶子节点
boolean b = tree.deleteNode(1);
if (b){
System.out.println("删除成功");
}else{
System.out.println("找不到节点");
}
//中序遍历
tree.inOrder(tree.root); // 3 6 8 9 10 100
//2.第二种情况:被删除的节点有一个子节点
boolean b1 = tree.deleteNode(3);
if (b1){
System.out.println("删除成功");
}else{
System.out.println("找不到节点");
}
//中序遍历
tree.inOrder(tree.root); // 6 8 9 10 100
//3.第三种情况:被删除的节点有两个子节点
boolean b2 = tree.deleteNode(10);
if (b2){
System.out.println("删除成功");
}else{
System.out.println("找不到节点");
}
//中序遍历
tree.inOrder(tree.root); //
}
}