二叉排序樹上,刪除二叉樹節點,有三種情況需要考慮
1、如果刪除的是葉子節點(需要考慮兩種情況,左節點和右節點)如果是左節點,則把父節點的左節點設爲null,同理是父節點右節點設爲null
2、如果刪除的節點只有一個子節點,那麼需要考慮子節點是在左邊還是右邊
如果子節點是在左邊,還要考慮被刪除的節點是在左邊還是右邊,如果是左邊,則父節點左孩子節點直接指向子節點,否則是父節點右孩子節點指向子節點
3、如果刪除的節點有兩個子節點,需要找到該節點的中序遍歷的後繼節點,也就是查找後繼的最左邊節點,找到後讓父節點指向中序後繼節點,
中序後繼的父節點指向中序後繼的右子節點,中序後繼節點的左孩子指向被刪除節點父節點的左孩子節點,中序後繼節點的右孩子節點指向被刪除節點的父節點的右孩子節點
實現過程如下所示:
package cn.edu.nwu.structs.tree;
/**
* @author jcm
* 二叉排序樹上,刪除二叉樹節點,有三種情況需要考慮
* 1、如果刪除的是葉子節點(需要考慮兩種情況,左節點和右節點)如果是左節點,則把父節點的左節點設爲null,同理是父節點右節點設爲null
* 2、如果刪除的節點只有一個子節點,那麼需要考慮子節點是在左邊還是右邊
* 如果子節點是在左邊,還要考慮被刪除的節點是在左邊還是右邊,如果是左邊,則父節點左孩子節點直接指向子節點,否則是父節點右孩子節點指向子節點
* 3、如果刪除的節點有兩個子節點,需要找到該節點的中序遍歷的後繼節點,也就是查找後繼的最左邊節點,找到後讓父節點指向中序後繼節點,
* 中序後繼的父節點指向中序後繼的右子節點,中序後繼節點的左孩子指向被刪除節點父節點的左孩子節點,中序後繼節點的右孩子節點指向被刪除節點的父節點的右孩子節點。
* 時間 2016年9月2日
*/
public class DeleteBinaryTreeNode {
public static void main(String[] args) {
BinaryTreeNode root = null;
root = InsertBinaryTreeNode.insertBinaryTNode(root,24);
root = InsertBinaryTreeNode.insertBinaryTNode(root,53);
root = InsertBinaryTreeNode.insertBinaryTNode(root,90);
root = InsertBinaryTreeNode.insertBinaryTNode(root,12);
root = InsertBinaryTreeNode.insertBinaryTNode(root,28);
root = InsertBinaryTreeNode.insertBinaryTNode(root,45);
show(root,1);
root = deleteBinaryTreeNode(root,24);
show(root,1);
}
/**
* @author jcm
* 刪除一個節點,需要考慮被刪除的節點是葉子節點還是存在一個子節點還是兩個子節點
* @param root 樹根
* @param data 被刪除的節點的數據項
* @return 返回樹根的引用
*/
public static BinaryTreeNode deleteBinaryTreeNode(BinaryTreeNode root,int data){
if(root == null){
return null;
}
BinaryTreeNode currentTNode = root;
BinaryTreeNode parentTNode = root;
//定義要刪除的節點是否在左邊
boolean isLeftTNode = true;
while(currentTNode.data != data){
parentTNode = currentTNode;
if(currentTNode.data > data){
currentTNode = currentTNode.leftTreeNode;
isLeftTNode = true;
}else{
currentTNode = currentTNode.rightTreeNode;
isLeftTNode = false;
}
if(currentTNode == null){
return null;
}
}
//被刪除的節點是葉子節點,沒有子節點
if(currentTNode.leftTreeNode == null && currentTNode.rightTreeNode == null){
if(currentTNode == root){
root = null;
}else if(isLeftTNode){
parentTNode.leftTreeNode = null;//要刪除的節點是在左邊
}else{
parentTNode.rightTreeNode = null;
}
}
//如果被刪除的節點有一個子節點,且只有一個左孩子節點
if(currentTNode.rightTreeNode == null){
if(currentTNode == root){//如果刪除的是樹根
root = currentTNode.leftTreeNode;
}else if(isLeftTNode){//被刪除的節點在左邊
parentTNode.leftTreeNode = currentTNode.leftTreeNode;
}else{//被刪除的節點在右邊
parentTNode.rightTreeNode = currentTNode.leftTreeNode;
}
}
//如果被刪除的節點有一個子節點,且只有一個右孩子節點
if(currentTNode.leftTreeNode == null){
if(currentTNode == root){//刪除的是樹根
root = currentTNode.rightTreeNode;
}else if(isLeftTNode){
parentTNode.leftTreeNode = currentTNode.rightTreeNode;
}else{
parentTNode.rightTreeNode = currentTNode.rightTreeNode;
}
}else{
//如果被刪除的節點有兩個子節點,那麼需要用他的中序後繼來替代該節點
//找到中序後續節點
BinaryTreeNode houJiTNode = findHouJiTNode(currentTNode);
if(root == currentTNode){//如果是樹根,直接把樹根重新指向後繼節點
root = houJiTNode;
}else if(isLeftTNode){//如果被刪除的節點是在左邊
parentTNode.leftTreeNode = houJiTNode;
}else{
parentTNode.rightTreeNode = houJiTNode;
}
//一定別忘了中序後繼的左孩子節點引用指向當前節點的左節點引用
//爲什麼中序後繼的右孩子節點引用指向當前節點的右孩子節點引用,因爲找中序後續節點已經做了這方面的工作
houJiTNode.leftTreeNode = currentTNode.leftTreeNode;
}
return root;
}
/**
* 找中序後續節點
* @param deleteTNode
* @return
*/
public static BinaryTreeNode findHouJiTNode(BinaryTreeNode deleteTNode){
BinaryTreeNode houJiTNode = deleteTNode;
BinaryTreeNode parentTNode = deleteTNode;
BinaryTreeNode currentTNode = deleteTNode.rightTreeNode;
while(currentTNode != null){
parentTNode = houJiTNode;
houJiTNode = currentTNode;
currentTNode = currentTNode.leftTreeNode;
}
if(houJiTNode != deleteTNode.rightTreeNode){
//中序後繼節點可能會存在右孩子節點,所以要這樣指向
parentTNode.leftTreeNode = houJiTNode.rightTreeNode;
//中序後繼節點右孩子節點指向被刪除的節點的右孩子節點
houJiTNode.rightTreeNode = deleteTNode.rightTreeNode;
}
return houJiTNode;
}
//中序遍歷,通過n控制層數
public static void show(BinaryTreeNode root,int n){
if(root == null){
return ;
}else{
show(root.leftTreeNode,n+1);
for (int i=0;i<n;i++){
System.out.print(" ");
}
System.out.println(root.data);
show(root.rightTreeNode,n+1);
}
}
}