二叉搜索樹 - Java 實現

樹定義

public class BinarySearchTree<T extends Comparable<? super T>> {

	// 二叉樹節點
    private static class BinaryNode<T> {
        T data;
        BinaryNode<T> left, right;

        public BinaryNode(T data, BinaryNode<T> left, BinaryNode<T> right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }
    }
    
	// 樹根
    private BinaryNode<T> root;
    
    ...
}

搜索節點

// 用於表示搜索結果(作爲內部類)
private static class SearchResult<T> {
    BinaryNode<T> target;       // 目標節點
    BinaryNode<T> parent;       // 目標節點之父
    // getter & setter ...
}


// 查找關鍵碼 e:返回目標節點及其父節點(插入、刪除時有用)
public SearchResult<T> search(T e) {
    SearchResult<T> result = new SearchResult<>();
    BinaryNode<T> current = root, parent = null;

    while (current != null) {
        int compareResult = e.compareTo(current.data);

		// 找到了
        if (compareResult == 0) {
            break;
        }

		// 記錄父節點,然後:比當前節點小->往左;否則->往右
        parent = current;
        current = compareResult < 0 ? current.left : current.right;
    }

    result.target = current;
    result.parent = parent;

    return result;
}

插入節點

public void insert(T e) {
	// 先確定目標節點是否存在
    SearchResult<T> result = search(e);

    // 已存在
    if (result.target != null) {
        return;
    }

	// 插入節點
    BinaryNode<T> node = new BinaryNode<>(e, null, null);

	// 建立父節點到新插入節點的連接
    BinaryNode<T> parent = result.parent;
    
    if (parent == null) {		// 爲樹根
        root = node;
    } else {					// 不是樹根
        if (e.compareTo(parent.data) < 0) {
            parent.left = node;
        } else {
            parent.right = node;
        }
    }
}

刪除節點

設待刪除節點爲 v,v 之父爲 p,則根據 v 擁有的非空孩子數,可分爲兩種情況:

(1) v 擁有一個非空孩子

設該非空孩子爲 c,則讓 c 接替 v,成爲 p 的孩子。
在這裏插入圖片描述
(2)v 擁有兩個非空孩子

設 rc 爲 v 的右孩子,在以 rc 爲根的子樹中,找到關鍵碼最小的節點,設爲 t 。

然後將 v 的關鍵碼設爲 t 的關鍵碼(即存放的數據)。因爲 t 的關鍵碼是子樹 rc 中最小的關鍵碼,所以,更新之後,節點 v 的關鍵碼依然小於等於子樹 rc 中的任一節點的關鍵碼,大於左子樹中任一節點的關鍵碼,即符合搜索樹的限定條件。

最後,刪除節點 t 。此時,可以確保節點 t 絕對沒有非空左孩子。(如果有的話,則其左孩子的關鍵碼比 t 的還要小,即 t 就不是關鍵碼最小的節點)

即,情況(2)轉換爲了情況(1)。

在這裏插入圖片描述

// 找到 root 子樹中關鍵碼最小的節點及其父節點
private SearchResult<T> findMinimum(BinaryNode<T> root) {
    SearchResult<T> result = new SearchResult<>();
    BinaryNode<T> parent = null;

	// 一直往左即可找到最小者
    if (root != null) {
        while (root.left != null) {
            parent = root;
            root = root.left;
        }
    }

    result.target = root;
    result.parent = parent;

    return result;
}
// 刪除
public void remove(T e) {
	// 先確認目標節點是否存在
    SearchResult<T> result = search(e);

    // 不存在
    if (result.target == null) {
        return;
    }

    BinaryNode<T> target = result.target;       // 待刪除節點
    BinaryNode<T> parent = result.parent;       // 待刪除節點之父

    // 待刪除節點有左右兩個非空孩子
    // 以待刪除節點爲根,找到其右子樹中關鍵碼最小的節點,讓它代替受死
    if (target.left != null && target.right != null) {
        SearchResult<T> result1 = findMinimum(target.right);
        target.data = result1.target.data;
        target = result1.target;                // 真正被刪除的節點
        parent = result1.parent;
    }

    // 現在,待刪除節點最多隻有一個非空孩子
    // 讓該孩子節點繼承父節點的位置
    BinaryNode<T> child = target.left != null ? target.left : target.right;

    if (parent != null) {				// 待刪除節點不是樹根
        if (parent.left == target) {
            parent.left = child;
        } else {
            parent.right = child;
        }
    } else {							// 待刪除節點是樹根
        root = child;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章