二叉搜索树 - 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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章