删除节点是二叉树中最复杂的一部分,所以放在此处单独说明。
基本思路:
1. 首先,在删除之前我们需要查找到需要删除的节点。这一点可以借鉴find()方法。
2. 找到之后,我们需要了解该如何删除此节点。首先我们知道,要删除的节点可能出现的情况有三种:
①该节点是叶子节点,即没有子节点。
那么要删除它,自然可以直接删除啦,只需要改变父节点的引用值就行,即将指向该节点的引用设置为null
②该节点有一个子节点
那么要改变父节点的引用,将父节点的引用设置成要删除节点的子节点
③该节点有两个子节点
这种情况要考虑的情况最为复杂。若要删除此类节点,则需要使用它的中序后继来替代该节点。
其中,中序后继指的是:比该节点大,但是是数值最为接近该节点的节点,这个节点即为中序后继。
下面给出删除节点的方法以及寻找中序后继的方法:
/**
* 删除节点
* @param data
*/
public void delete(int data) {
//引用当前节点,从根节点开始
Node current = root;
//引用当前节点的父节点
Node parent = root;
//是否为左孩子
boolean isLeftChild = true;
//先找到该节点
while(current.data != data) {
parent = current;
//进行比较,比较查找值和当前节点的大小
if(current.data>data) {
current = parent.leftChild;
isLeftChild = true;
} else {
current = parent.rightChild;
isLeftChild = false;
}
//若树中无要删除的节点
if(current == null) {
System.out.println("对不起,未查找到要删除的节点!");
return;
}
}
//删除节点
//1.若该节点是叶子节点,即没有孩子
if(current.leftChild == null && current.rightChild == null) {
//注意!记得考虑要删除节点为root的情况
if(current == this.root) {
this.root = null;
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功!");
return;
}
//如果要删除的节点是父节点的左孩子
if(isLeftChild)
parent.leftChild = null;
else
parent.rightChild = null;
//如果要删除的节点是父节点的左孩子
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功!");
return;
} else if(current.rightChild == null) {// 若要删除的节点只要一个左孩子
//注意!记得考虑要删除节点为root的情况
if(current == this.root) {
this.root = current.leftChild;
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功!");
return;
}
if(isLeftChild)
parent.leftChild = current.leftChild;
else
parent.rightChild = current.leftChild;
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功!");
} else if(current.leftChild == null) {//若要删除的节点只有一个右孩子
//注意!记得考虑要删除节点为root的情况
if(current == this.root) {
this.root = current.rightChild;
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功!");
return;
}
if(isLeftChild)
parent.leftChild = current.rightChild;
else
parent.rightChild = current.rightChild;
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功!");
} else { //最后一种情况,即要删除节点有两个孩子
Node successor = getSuccessor(current);
if(current == root) {
this.root = successor;
} else if(isLeftChild) {
// 若要删除节点是一个左子节点
parent.leftChild = successor;
} else {
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
System.out.println("要删除的数据: " + current.data + ", " + current.sdata);
System.out.println("删除成功");
}
}
/**
* 用来寻找中序后继节点
* @param delNode
* @return 返回中序后继节点
*/
public Node getSuccessor(Node delNode) {
//先建立一个引用
Node successor = delNode;
//建立一个父节点
Node successorParent = delNode;
//这里因为是循环中序后继,所以是从要删除节点的右子树开始寻找
Node current = delNode.rightChild;
//假设要删除节点为P,P的右孩子为P1,则中序后继只可能存在于P1的左子树上或者是P1本身
while(current != null) {
successorParent = successor;
successor = current;
current = current.leftChild;
}
if(successor != delNode.rightChild) {
successorParent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;
}
return successor;
}