二叉搜尋樹的構建,遍歷,查詢,刪除
轉載請註明出處:
百度面試很喜歡問樹,直接被虐慘。有必要對資料結構中的各種樹進行仔細的研究。本篇部落格重點研究二叉搜尋樹。
資料結構中為了儲存和查詢的方便,用各種樹結構來儲存資料,下面就淺談一下各種樹的表示方法、特點及各自的用途,涉及的樹結構包括:二叉搜尋樹(二叉查詢樹,二叉排序樹)、平衡二叉樹(AVL樹)、紅黑樹、B-樹、B+樹、字典樹(trie樹)、字尾樹、廣義字尾樹。
① 二叉搜尋樹(二叉查詢樹,二叉排序樹)
二叉查詢樹是一種動態查詢表,具有這些性質:
(1)若它的左子樹不為空,則左子樹上的所有節點的值都小於它的根節點的值;
(2)若它的右子樹不為空,則右子樹上所有節點的值都大於它的根節點的值;
(3)其他的左右子樹也分別為二叉查詢樹;
(4)二叉查詢樹是動態查詢表,在查詢的過程中可見新增和刪除相應的元素,在這些操作中需要保持二叉查詢樹的以上性質。
② 平衡二叉樹(AVL樹)
含有相同節點的二叉查詢樹可以有不同的形態,而二叉查詢樹的平均查詢長度與樹的深度有關,所以需要找出一個查詢平均長度最小的一棵,那就是平衡二叉樹,具有以下性質:
(1)要麼是棵空樹,要麼其根節點左右子樹的深度之差的絕對值不超過1;
(2)其左右子樹也都是平衡二叉樹;
(3)二叉樹節點的平衡因子定義為該節點的左子樹的深度減去右子樹的深度。則平衡二叉樹的所有節點的平衡因子只可能是-1,0,1。
③ 紅黑樹
紅黑樹是一種自平衡二叉樹,在平衡二叉樹的基礎上每個節點又增加了一個顏色的屬性,節點的顏色只能是紅色或黑色。具有以下性質:
(1)根節點只能是黑色;
(2)紅黑樹中所有的葉子節點後面再接上左右兩個空節點,這樣可以保持演算法的一致性,而且所有的空節點都是黑色;
(3)其他的節點要麼是紅色,要麼是黑色,紅色節點的父節點和左右孩子節點都是黑色,及黑紅相間;
(4)在任何一棵子樹中,從根節點向下走到空節點的路徑上所經過的黑節點的數目相同,從而保證了是一個平衡二叉樹。
④ B-樹
B-樹是一種平衡多路查詢樹,它在檔案系統中很有用。一棵m階B-樹,具有下列性質:
(1)樹中每個節點至多有m棵子樹;
(2)若根節點不是葉子節點,則至少有2棵子樹;
(3)除根節點之外的所有非終端節點至少有棵子樹;
(4)每個節點中的資訊結構為(A0,K1,A1,K2……Kn,An),其中n表示關鍵字個數,Ki為關鍵字,Ai為指標;
(5)所有的葉子節點都出現在同一層次上,且不帶任何資訊,也是為了保持演算法的一致性。
⑤ B+樹
B+數是B-樹的一種變形,它與B-樹的差別在於:
(1)有n棵子樹的節點含有n個關鍵字;
(2)所有的葉子節點包含了全部關鍵字的資訊,及指向這些關鍵字記錄的指標,且葉子節點本身按關鍵字大小自小到大順序連結;
(3)所有非終端節點可以看成是索引部分,節點中僅含有其子樹(根節點)中最大(或最小)關鍵字,所有B+樹更像一個索引順序表;
(4)對B+樹進行查詢運算,一是從最小關鍵字起進行順序查詢,二是從根節點開始,進行隨機查詢。
⑥ 字典樹(trie樹)
字典樹是一種以樹形結構儲存大量字串。以便於字串的統計和查詢,經常被搜尋引擎系統用於文字詞頻統計。它的優點是:利用字串的公共字首來節約儲存空間,最大限度地減少無謂的字串比較,查詢效率比雜湊表高。具有以下特點:
(1)根節點為空;
(2)除根節點外,每個節點包含一個字元;
(3)從根節點到某一節點,路徑上經過的字元連線起來,為該節點對應的字串。
(4)每個字串在建立字典樹的過程中都要加上一個區分的結束符,避免某個短字串正好是某個長字串的字首而淹沒。
⑦ 字尾樹
字尾樹則是一個字串的所有後綴組成的字典樹。
⑧ 廣義字尾樹
廣義字尾樹是好幾個字串的的所有後綴組成的字典樹,同樣每個字串的所有後綴都具有一個相同的結束符,不同字串的結束符不同。
二叉搜尋樹和二分查詢法類似,可以在O(logN)的時間裡查詢到想要的元素,同時又具有連結串列的優點,插入,刪除節點快。
下面從插入,查詢,刪除,前序遍歷,中序遍歷,後序遍歷,深度優先遍歷,廣度優先遍歷,求深度,求最小值,求最大值,這些方面來深入對二叉搜尋樹這種高效的資料結構的理解。
先來定義二叉搜尋樹的資料結構
class Node
{
int value;
Node leftChild;
Node rightChild;
Node(int value)
{
this.value = value;
}
}
插入(遞迴)
/**
* 插入元素,構造二叉查詢樹
*
* @param value
* 整數
* @param node
*/
public void insert(int value, Node node)
{
if (value < node.value)
{
if (node.leftChild != null)
{
insert(value, node.leftChild);
}
else
{
node.leftChild = new Node(value);
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
insert(value, node.rightChild);
}
else
{
node.rightChild = new Node(value);
}
}
}
插入(非遞迴)
/**
* 插入元素,構造二叉查詢樹(非遞迴)
*
* @param value
* 整數
* @param node
*/
public void insertNoRecursion(int value, Node node)
{
while (true)
{
if (value < node.value)
{
if (node.leftChild != null)
{
node = node.leftChild;
}
else
{
node.leftChild = new Node(value);
return;
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
node = node.rightChild;
}
else
{
node.rightChild = new Node(value);
return;
}
}
}
}
查詢(遞迴)
/**
* 查詢元素,從二叉查詢樹中查詢某個元素
*
* @param value
* 整數
* @param node
*/
public boolean search(int value, Node node)
{
if (value < node.value)
{
if (node.leftChild != null)
{
return search(value, node.leftChild);
}
else
{
return false;
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
return search(value, node.rightChild);
}
else
{
return false;
}
}
else
{
return true;
}
}
查詢(非遞迴)
/**
* 查詢元素,從二叉查詢樹中查詢某個元素(非遞迴)
*
* @param value
* 整數
* @param node
*/
public boolean searchNoRecursion(int value, Node node)
{
while (true)
{
if (value < node.value)
{
if (node.leftChild != null)
{
node = node.leftChild;
}
else
{
return false;
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
node = node.rightChild;
}
else
{
return false;
}
}
else
{
return true;
}
}
}
刪除
// 刪除節點分三種方式刪除節點
// 1、刪除沒有子節點的節點,直接讓該節點的父節點的左節點或右節點指向空
// 2、刪除有一個子節點的節點,直接讓該節點的父節點指向被刪除節點的剩餘節點
// 3、刪除有三個節點的子節點,找到要刪除節點的後繼節點, 用該節點替代刪除的節點
public Node delete(int Key, Node root) throws Exception
{
// 首先查詢節點,並記錄該節點的父節點引用
Node current = root;
Node parent = root;
boolean isLeftNode = true;
while (current != null && current.value != Key)
{
parent = current;
if (Key < current.value)
{
isLeftNode = true;
current = current.leftChild;
}
else
{
isLeftNode = false;
current = current.rightChild;
}
}
if (current == null)
{
System.out.println("沒有找到要刪除的節點!");
throw new Exception("沒有找到要刪除的節點!");
}
// 下面分三種情況刪除節點
if (current.leftChild == null && current.rightChild == null)
{ // 要刪除的節點沒有子節點
if (current == root)
{ // 根節點就刪除整棵樹
root = null;
}
else if (isLeftNode)
{ // 如果是左節點,做節點指向空
parent.leftChild = null;
}
else
{ // 如果是右節點,右節點指向空
parent.rightChild = null;
}
}
else if (current.leftChild == null)
{ // 要刪除的節點只有右節點
if (current == root)
{
root = current.rightChild;
}
else if (isLeftNode)
{
parent.leftChild = current.rightChild;
}
else
{
parent.rightChild = current.rightChild;
}
}
else if (current.rightChild == null)
{ // 要刪除的節點只有左節點
if (current == root)
{
root = current.leftChild;
}
else if (isLeftNode)
{
parent.leftChild = current.leftChild;
}
else
{
parent.rightChild = current.leftChild;
}
}
else
{ // 要刪除的節點有兩個節點
Node successor = findSuccessor(current);
if (current == root)
{
root = successor;
}
else if (isLeftNode)
{
parent.leftChild = successor;
}
else
{
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
return root;
}
private Node findSuccessor(Node delNode)
{
Node parent = delNode;
Node successor = delNode;
Node current = delNode.rightChild;
while (current != null)
{
parent = successor;
successor = current;
current = current.leftChild;
}
if (successor != delNode.rightChild)
{
parent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;
}
return successor;
}
前序遍歷(遞迴)
/**
* 遞迴先序遍歷
*
* @param node
*/
public void preTraverse(Node node)
{
if (node == null)
{
return;
}
System.out.print(node.value + " ");
preTraverse(node.leftChild);
preTraverse(node.rightChild);
}
前序遍歷(非遞迴)
/**
* 非遞迴先序遍歷(用棧來實現,先將右節點壓入棧,再將左節點壓入棧)
*
* @param node
*/
public void preTraverseNoRecursion(Node node)
{
Stack<Node> stack = new Stack<Node>();
if (node != null)
{
stack.push(node);
}
while (!stack.isEmpty())
{
node = stack.pop();
System.out.print(node.value + " ");
if (node.rightChild != null)
{
stack.push(node.rightChild);
}
if (node.leftChild != null)
{
stack.push(node.leftChild);
}
}
}
/**
* 非遞迴先序遍歷2(先輸出自身,再向左走到底,在返回來輸出右節點)
*
* @param node
*/
public void preTraverseNoRecursion2(Node node)
{
Stack<Node> stack = new Stack<Node>();
while (node != null || stack.size() > 0)
{
while (node != null)
{
System.out.print(node.value + " ");
stack.push(node);
node = node.leftChild;
}
if (stack.size() > 0)
{
node = stack.pop();
node = node.rightChild;
}
}
}
中序遍歷(遞迴)
/**
* 遞迴中序遍歷
*
* @param node
*/
public void midTraverse(Node node)
{
if (node.leftChild != null)
{
midTraverse(node.leftChild);
}
System.out.print(node.value + " ");
if (node.rightChild != null)
{
midTraverse(node.rightChild);
}
}
中序遍歷(非遞迴)
/**
* 非遞迴中序遍歷
*
* @param node
*/
public void midTraverseNoRecursion(Node node)
{
Stack<Node> stack = new Stack<Node>();
while (node != null || stack.size() > 0)
{
while (node != null)
{
stack.push(node);
node = node.leftChild;
}
if (stack.size() > 0)
{
node = stack.pop();
System.out.print(node.value + " ");
node = node.rightChild;
}
}
}
後序遍歷(遞迴)
/**
* 遞迴後序遍歷
*
* @param node
*/
public void postTraverse(Node node)
{
if (node.leftChild != null)
{
postTraverse(node.leftChild);
}
if (node.rightChild != null)
{
postTraverse(node.rightChild);
}
System.out.print(node.value + " ");
}
後序遍歷(非遞迴)
/**
* 非遞迴後序遍歷
*
* @param node
*/
public void postTraverseNoRecursion(Node node)
{
Stack<Node> stack = new Stack<Node>();
Stack<Node> temp = new Stack<Node>();
while (node != null || stack.size() > 0)
{
while (node != null)
{
stack.push(node);
temp.push(node);
node = node.rightChild;
}
if (stack.size() > 0)
{
node = stack.pop();
node = node.leftChild;
}
}
while (temp.size() > 0)
{
node = temp.pop();
System.out.print(node.value + " ");
}
}
深度優先遍歷(遞迴)
和前序遍歷的遞迴實現一樣。
深度優先遍歷(非遞迴)
/**
* 深度優先遍歷(用棧實現)
*
* @param node
*/
public void depthTraverse(Node node)
{
Stack<Node> stack = new Stack<Node>();
stack.push(node);
while (!stack.isEmpty())
{
node = stack.pop();
System.out.print(node.value + " ");
if (node.rightChild != null)
{
stack.push(node.rightChild);
}
if (node.leftChild != null)
{
stack.push(node.leftChild);
}
}
}
廣度優先遍歷(遞迴)
廣度優先遍歷怎麼用遞迴實現,暫時還想不出來,等找到方法了再加進來。
廣度優先遍歷(非遞迴)
/**
* 廣度優先遍歷(用佇列實現)
*
* @param node
*/
public void breadthTraverse(Node node)
{
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
while (!queue.isEmpty())
{
node = queue.remove();
System.out.print(node.value + " ");
if (node.leftChild != null)
{
queue.add(node.leftChild);
}
if (node.rightChild != null)
{
queue.add(node.rightChild);
}
}
}
求深度(遞迴)
/**
* 遞迴求深度(分治法,交給左右子樹分別去計算深度,然後在合併計算結果)
*
* @param node
* @return
*/
public int depthRecursion(Node node)
{
if (node == null)
{
return 0;
}
int leftChildDepth = depthRecursion(node.leftChild);
int rightChildDepth = depthRecursion(node.rightChild);
return leftChildDepth >= rightChildDepth ? leftChildDepth + 1 : rightChildDepth + 1;
}
求深度(非遞迴)
/**
* 非遞迴求深度(利用廣度優先遍歷的思維,每次將下一層的節點加進來,直到下一層沒有節點為止)
*
* @param node
*/
public void depthNoRecursion(Node node)
{
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
int level = 1;
System.out.print(node.value + " ");
while (!queue.isEmpty())
{
List<Node> list2 = new ArrayList<Node>();
boolean flag = false;
while (!queue.isEmpty())
{
list2.add(queue.remove());
}
for (int i = 0; i < list2.size(); i++)
{
Node temp = list2.get(i);
if (temp.leftChild != null)
{
queue.add(temp.leftChild);
System.out.print(temp.leftChild.value + " ");
flag = true;
}
if (temp.rightChild != null)
{
queue.add(temp.rightChild);
System.out.print(temp.rightChild.value + " ");
flag = true;
}
}
if (flag)
{
level++;
}
}
System.out.println("深度為:" + level);
}
求最小值(遞迴)
/**
* 最小值
*
* @param node
* @return
*/
public int min(Node node)
{
if (node.leftChild == null)
{
return node.value;
}
else
{
return min(node.leftChild);
}
}
求最小值(非遞迴)
/**
* 最小值(非遞迴,使用while迴圈)
*
* @param node
* @return
*/
public int minNoRecursion(Node node)
{
Node parent = null;
while (node != null)
{
parent = node;
node = node.leftChild;
}
return parent.value;
}
求最大值(遞迴)
/**
* 最大值
*
* @return
*/
public int max(Node node)
{
if (node.rightChild == null)
{
return node.value;
}
else
{
return max(node.rightChild);
}
}
求最大值(非遞迴)
/**
* 最大值(非遞迴,使用while迴圈)
*
* @return
*/
public int maxNoRecursion(Node node)
{
Node parent = null;
while (node != null)
{
parent = node;
node = node.rightChild;
}
return parent.value;
}
全部原始碼
import java.util.*;
public class BinaryTree
{
static class Node
{
int value;
Node leftChild;
Node rightChild;
Node(int value)
{
this.value = value;
}
}
/**
* 插入元素,構造二叉查詢樹
*
* @param value
* 整數
* @param node
*/
public void insert(int value, Node node)
{
if (value < node.value)
{
if (node.leftChild != null)
{
insert(value, node.leftChild);
}
else
{
node.leftChild = new Node(value);
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
insert(value, node.rightChild);
}
else
{
node.rightChild = new Node(value);
}
}
}
/**
* 插入元素,構造二叉查詢樹(非遞迴)
*
* @param value
* 整數
* @param node
*/
public void insertNoRecursion(int value, Node node)
{
while (true)
{
if (value < node.value)
{
if (node.leftChild != null)
{
node = node.leftChild;
}
else
{
node.leftChild = new Node(value);
return;
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
node = node.rightChild;
}
else
{
node.rightChild = new Node(value);
return;
}
}
}
}
/**
* 查詢元素,從二叉查詢樹中查詢某個元素
*
* @param value
* 整數
* @param node
*/
public boolean search(int value, Node node)
{
if (value < node.value)
{
if (node.leftChild != null)
{
return search(value, node.leftChild);
}
else
{
return false;
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
return search(value, node.rightChild);
}
else
{
return false;
}
}
else
{
return true;
}
}
/**
* 查詢元素,從二叉查詢樹中查詢某個元素(非遞迴)
*
* @param value
* 整數
* @param node
*/
public boolean searchNoRecursion(int value, Node node)
{
while (true)
{
if (value < node.value)
{
if (node.leftChild != null)
{
node = node.leftChild;
}
else
{
return false;
}
}
else if (value > node.value)
{
if (node.rightChild != null)
{
node = node.rightChild;
}
else
{
return false;
}
}
else
{
return true;
}
}
}
/**
* 遞迴先序遍歷
*
* @param node
*/
public void preTraverse(Node node)
{
if (node == null)
{
return;
}
System.out.print(node.value + " ");
preTraverse(node.leftChild);
preTraverse(node.rightChild);
}
/**
* 非遞迴先序遍歷(用棧來實現,先將右節點壓入棧,再將左節點壓入棧)
*
* @param node
*/
public void preTraverseNoRecursion(Node node)
{
Stack<Node> stack = new Stack<Node>();
if (node != null)
{
stack.push(node);
}
while (!stack.isEmpty())
{
node = stack.pop();
System.out.print(node.value + " ");
if (node.rightChild != null)
{
stack.push(node.rightChild);
}
if (node.leftChild != null)
{
stack.push(node.leftChild);
}
}
}
/**
* 非遞迴先序遍歷2(先輸出自身,再向左走到底,在返回來輸出右節點)
*
* @param node
*/
public void preTraverseNoRecursion2(Node node)
{
Stack<Node> stack = new Stack<Node>();
while (node != null || stack.size() > 0)
{
while (node != null)
{
System.out.print(node.value + " ");
stack.push(node);
node = node.leftChild;
}
if (stack.size() > 0)
{
node = stack.pop();
node = node.rightChild;
}
}
}
/**
* 遞迴中序遍歷
*
* @param node
*/
public void midTraverse(Node node)
{
if (node.leftChild != null)
{
midTraverse(node.leftChild);
}
System.out.print(node.value + " ");
if (node.rightChild != null)
{
midTraverse(node.rightChild);
}
}
/**
* 非遞迴中序遍歷
*
* @param node
*/
public void midTraverseNoRecursion(Node node)
{
Stack<Node> stack = new Stack<Node>();
while (node != null || stack.size() > 0)
{
while (node != null)
{
stack.push(node);
node = node.leftChild;
}
if (stack.size() > 0)
{
node = stack.pop();
System.out.print(node.value + " ");
node = node.rightChild;
}
}
}
/**
* 遞迴後序遍歷
*
* @param node
*/
public void postTraverse(Node node)
{
if (node.leftChild != null)
{
postTraverse(node.leftChild);
}
if (node.rightChild != null)
{
postTraverse(node.rightChild);
}
System.out.print(node.value + " ");
}
/**
* 非遞迴後序遍歷
*
* @param node
*/
public void postTraverseNoRecursion(Node node)
{
Stack<Node> stack = new Stack<Node>();
Stack<Node> temp = new Stack<Node>();
while (node != null || stack.size() > 0)
{
while (node != null)
{
stack.push(node);
temp.push(node);
node = node.rightChild;
}
if (stack.size() > 0)
{
node = stack.pop();
node = node.leftChild;
}
}
while (temp.size() > 0)
{
node = temp.pop();
System.out.print(node.value + " ");
}
}
/**
* 深度優先遍歷(用棧實現)
*
* @param node
*/
public void depthTraverse(Node node)
{
Stack<Node> stack = new Stack<Node>();
stack.push(node);
while (!stack.isEmpty())
{
node = stack.pop();
System.out.print(node.value + " ");
if (node.rightChild != null)
{
stack.push(node.rightChild);
}
if (node.leftChild != null)
{
stack.push(node.leftChild);
}
}
}
/**
* 廣度優先遍歷(用佇列實現)
*
* @param node
*/
public void breadthTraverse(Node node)
{
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
while (!queue.isEmpty())
{
node = queue.remove();
System.out.print(node.value + " ");
if (node.leftChild != null)
{
queue.add(node.leftChild);
}
if (node.rightChild != null)
{
queue.add(node.rightChild);
}
}
}
/**
* 遞迴求深度(分治法,交給左右子樹分別去計算深度,然後在合併計算結果)
*
* @param node
* @return
*/
public int depthRecursion(Node node)
{
if (node == null)
{
return 0;
}
int leftChildDepth = depthRecursion(node.leftChild);
int rightChildDepth = depthRecursion(node.rightChild);
return leftChildDepth >= rightChildDepth ? leftChildDepth + 1 : rightChildDepth + 1;
}
/**
* 非遞迴求深度(利用廣度優先遍歷的思維,每次將下一層的節點加進來,直到下一層沒有節點為止)
*
* @param node
*/
public void depthNoRecursion(Node node)
{
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
int level = 1;
System.out.print(node.value + " ");
while (!queue.isEmpty())
{
List<Node> list2 = new ArrayList<Node>();
boolean flag = false;
while (!queue.isEmpty())
{
list2.add(queue.remove());
}
for (int i = 0; i < list2.size(); i++)
{
Node temp = list2.get(i);
if (temp.leftChild != null)
{
queue.add(temp.leftChild);
System.out.print(temp.leftChild.value + " ");
flag = true;
}
if (temp.rightChild != null)
{
queue.add(temp.rightChild);
System.out.print(temp.rightChild.value + " ");
flag = true;
}
}
if (flag)
{
level++;
}
}
System.out.println("深度為:" + level);
}
/**
* 最大值(非遞迴,使用while迴圈)
*
* @return
*/
public int maxNoRecursion(Node node)
{
Node parent = null;
while (node != null)
{
parent = node;
node = node.rightChild;
}
return parent.value;
}
/**
* 最大值
*
* @return
*/
public int max(Node node)
{
if (node.rightChild == null)
{
return node.value;
}
else
{
return max(node.rightChild);
}
}
/**
* 最小值(非遞迴,使用while迴圈)
*
* @param node
* @return
*/
public int minNoRecursion(Node node)
{
Node parent = null;
while (node != null)
{
parent = node;
node = node.leftChild;
}
return parent.value;
}
/**
* 最小值
*
* @param node
* @return
*/
public int min(Node node)
{
if (node.leftChild == null)
{
return node.value;
}
else
{
return min(node.leftChild);
}
}
// 刪除節點分三種方式刪除節點
// 1、刪除沒有子節點的節點,直接讓該節點的父節點的左節點或右節點指向空
// 2、刪除有一個子節點的節點,直接讓該節點的父節點指向被刪除節點的剩餘節點
// 3、刪除有三個節點的子節點,找到要刪除節點的後繼節點, 用該節點替代刪除的節點
public Node delete(int Key, Node root) throws Exception
{
// 首先查詢節點,並記錄該節點的父節點引用
Node current = root;
Node parent = root;
boolean isLeftNode = true;
while (current != null && current.value != Key)
{
parent = current;
if (Key < current.value)
{
isLeftNode = true;
current = current.leftChild;
}
else
{
isLeftNode = false;
current = current.rightChild;
}
}
if (current == null)
{
System.out.println("沒有找到要刪除的節點!");
throw new Exception("沒有找到要刪除的節點!");
}
// 下面分三種情況刪除節點
if (current.leftChild == null && current.rightChild == null)
{ // 要刪除的節點沒有子節點
if (current == root)
{ // 根節點就刪除整棵樹
root = null;
}
else if (isLeftNode)
{ // 如果是左節點,做節點指向空
parent.leftChild = null;
}
else
{ // 如果是右節點,右節點指向空
parent.rightChild = null;
}
}
else if (current.leftChild == null)
{ // 要刪除的節點只有右節點
if (current == root)
{
root = current.rightChild;
}
else if (isLeftNode)
{
parent.leftChild = current.rightChild;
}
else
{
parent.rightChild = current.rightChild;
}
}
else if (current.rightChild == null)
{ // 要刪除的節點只有左節點
if (current == root)
{
root = current.leftChild;
}
else if (isLeftNode)
{
parent.leftChild = current.leftChild;
}
else
{
parent.rightChild = current.leftChild;
}
}
else
{ // 要刪除的節點有兩個節點
Node successor = findSuccessor(current);
if (current == root)
{
root = successor;
}
else if (isLeftNode)
{
parent.leftChild = successor;
}
else
{
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
return root;
}
private Node findSuccessor(Node delNode)
{
Node parent = delNode;
Node successor = delNode;
Node current = delNode.rightChild;
while (current != null)
{
parent = successor;
successor = current;
current = current.leftChild;
}
if (successor != delNode.rightChild)
{
parent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;
}
return successor;
}
public static void main(String[] args)
{
Node root = new Node(5);
BinaryTree btree = new BinaryTree();
btree.insertNoRecursion(4, root);
btree.insertNoRecursion(7, root);
btree.insertNoRecursion(1, root);
btree.insert(3, root);
btree.insert(8, root);
btree.insert(6, root);
btree.insert(9, root);
btree.preTraverse(root);
System.out.println();
btree.preTraverseNoRecursion(root);
System.out.println();
btree.preTraverseNoRecursion2(root);
System.out.println();
btree.midTraverse(root);
System.out.println();
btree.midTraverseNoRecursion(root);
System.out.println();
btree.postTraverse(root);
System.out.println();
btree.postTraverseNoRecursion(root);
System.out.println();
btree.depthTraverse(root);
System.out.println();
btr