資料結構與演算法篇 二叉樹(Binary Tree)(二)
今天要講的是二叉查詢樹(Binary Search Tree),是一種最常用的二叉搜尋樹,支援快速查詢,刪除,插入資料。
它是如何實現的呢?,其實它依靠的它的資料結構,在樹中的任意一個節點,其左子樹的每個節點的值都小於這個節點的值,右子樹都大於這個節點的值。
接下來我們來看一下二叉樹是怎麼實現快速查詢,刪除,新增
首先我們來看一下查詢是怎麼實現的,快速查詢是依賴二叉樹的這種的特殊的資料結構,我們首先取的是根節點的資料,
如果等於我們要找的資料就返回,小於的話我們就在左子樹遞迴查詢,大於的話我們就在右子樹遞迴查詢
public class BinarySearchTree {
private Node tree;
public Node find(int data) {
Node p = tree;
while (p != null) {
if (data < p.data) p = p.left;
else if (data > p.data) p = p.right;
else return p;
}
return null;
}
public static class Node {
private int data;
private Node left;
private Node right;
public Node(int data) {
this.data = data;
}
}
}
接下來要講的是插入操作,其實插入操作跟查詢也是類似的,將要插入的資料跟根節點進行比較,如果要插入的資料比
節點的資料大,並且節點的右子樹為空我們就插入到右子樹的位置裡,如果不為空,我們就遞迴下去,同理。。。。。。
反之也是同理。。。。。。。
public void insert(int data) {
if (tree == null) {
tree = new Node(data);
return;
}
Node p = tree;
while (p != null) {
if (data > p.data) {
if (p.right == null) {
p.right = new Node(data);
return;
}
p = p.right;
} else { // data < p.data
if (p.left == null) {
p.left = new Node(data);
return;
}
p = p.left;
}
}
}
二叉查詢樹的查詢、插入操作都比較簡單易懂,但是它的刪除操作就比較複雜了 。針對要刪除節點的子節點個數的不同,我們需要分三種情況來處理。
第一種情況是,如果要刪除的節點沒有子節點,我們只需要直接將父節點中,指向要刪除節點的指標置為 null。比如圖中的刪除節點 55。
第二種情況是,如果要刪除的節點只有一個子節點(只有左子節點或者右子節點),我們只需要更新父節點中,指向要刪除節點的指標,讓它指向要刪除節點的子節點就可以了。比如圖中的刪除節點 13。
第三種情況是,如果要刪除的節點有兩個子節點,這就比較複雜了。我們需要找到這個節點的右子樹中的最小節點,把它替換到要刪除的節點上。然後再刪除掉這個最小節點,因為最小節點肯定沒有左子節點(如果有左子結點,那就不是最小節點了),所以,我們可以應用上面兩條規則來刪除這個最小節點。比如圖中的刪除節點 18。
public void delete(int data) {
Node p = tree; // p 指向要刪除的節點,初始化指向根節點
Node pp = null; // pp 記錄的是 p 的父節點
while (p != null && p.data != data) {
pp = p;
if (data > p.data) p = p.right;
else p = p.left;
}
if (p == null) return; // 沒有找到
// 要刪除的節點有兩個子節點
if (p.left != null && p.right != null) { // 查詢右子樹中最小節點
Node minP = p.right;
Node minPP = p; // minPP 表示 minP 的父節點
while (minP.left != null) {
minPP = minP;
minP = minP.left;
}
p.data = minP.data; // 將 minP 的資料替換到 p 中
p = minP; // 下面就變成了刪除 minP 了
pp = minPP;
}
// 刪除節點是葉子節點或者僅有一個子節點
Node child; // p 的子節點
if (p.left != null) child = p.left;
else if (p.right != null) child = p.right;
else child = null;
if (pp == null) tree = child; // 刪除的是根節點
else if (pp.left == p) pp.left = child;
else pp.right = child;
}