二叉樹最復雜的步驟即為刪除操作,此處只簡單介紹一下具體思路:
(1)如果待刪除的節點是一片樹葉,那么它可以被立即刪除。然后將其父節點的相應子節點(左節點或右節點)至空。
(2)如果被刪除的節點有一個子節點,那么把它的子節點直接連到它的父節點上即可。(Node:current,parent)
(3)如果被刪除的節點(a)有兩個子節點,就不能簡單的用它的一個子節點代替它。一般找到(a)的右子樹中key最小的節點(c)代替它,如果c不為葉子節點,那么遞歸對c進行相應的刪除操作。(Node:successorParent,successor,current)
package com.donghao.erchashu;
public class Node {
public int iData;
public Node leftChild;
public Node rightChild;
public void displayNode(){
System.out.println('{' + iData + ',' + '}');
}
}
package com.donghao.erchashu;
public class Tree {
private Node root;
public Tree() {
root = null;
}
public Node find(int key) {
Node current = root;
while (current.iData != key) {
if (key < current.iData) {
current = current.leftChild;
} else {
current = current.rightChild;
}
if (current == null)
return null;
}
return current;
}
public void insert(int id) {
Node newNode = new Node();
newNode.iData = id;
if (root == null)
root = newNode;
else {
Node current = root;
Node parent;
while (true) {
parent = current;
if (id < current.iData) {
current = current.leftChild;
if (current == null) {
parent.leftChild = newNode;
return;
}
} else {
current = current.rightChild;
if (current == null) {
parent.rightChild = newNode;
return;
}
}
}
}
}
public boolean delete(int key) {
Node current = root;
Node parent = root;
boolean isLeftChild = true;
while (current.iData != key) {
parent = current;
if (key < current.iData) {
isLeftChild = true;
current = current.leftChild;
} else {
isLeftChild = false;
current = current.rightChild;
}
if (current == null)
return false;
}
// 葉子節點
if (current.leftChild == null && current.rightChild == null) {
if (current == root)
root = null;
else if (isLeftChild)
parent.leftChild = null;
else
parent.rightChild = null;
// 只有一個子節點
} else if (current.rightChild == null) {
if (current == root)
root = current.leftChild;
else if (isLeftChild)
parent.leftChild = current.leftChild;
else
parent.rightChild = current.leftChild;
} else if (current.leftChild == null) {
if (current == root)
root = current.rightChild;
else if (isLeftChild)
parent.leftChild = current.rightChild;
else
parent.rightChild = current.rightChild;
}
// 兩個子節點
else {
Node successor = getSuccessor(current);
//步驟三
if (current == root) {
root = successor;
} else if (isLeftChild) {
parent.leftChild = successor;
} else
parent.rightChild = successor;
//步驟四
successor.leftChild = current.leftChild;
}
return true;
}
private Node getSuccessor(Node delNode) {
Node successorParent = delNode;
Node successor = delNode;
Node current = delNode.rightChild;
while (current != null) {
successorParent = successor;
successor = current;
current = current.leftChild;
}
if (successor != delNode.rightChild) {
//步驟一
successorParent.leftChild = successor.rightChild;
//步驟二
successor.rightChild = delNode.rightChild;
}
return successor;
}
}
重點解釋:
getSuccessor方法找到a的直接后繼c(即以a的右節點為根的子樹中的最左孩子)
<1>如果c為a的右節點:步驟一:將a的parent.rightChild置換為c
步驟二:將c的左子樹置換為a的parent.leftChild
<2>如果c為a的右節點的左后代:步驟一:將c的parent.leftChild置換為c.rightChild(getSuccessor()方法中實現)
步驟二:將c的rightChild置換為a的parent.rightChild(getSuccessor()方法中實現)
步驟三:將a(即current節點)的parent.rightChild置換為c節點
步驟四:將最新的a節點(已被c置換掉)的leftChild置換為原a節點的左孩子(current.leftChild)
