package com.datastructure.tree; public class BinarySearchTree<T extends Comparable<? super T>> { static class BinaryNode<T> { T data; BinaryNode<T> left; BinaryNode<T> right; public BinaryNode() { this(null, null, null); } public BinaryNode(T data) { this(data, null, null); } public BinaryNode(T data, BinaryNode<T> left, BinaryNode<T> right) { super(); this.data = data; this.left = left; this.right = right; } } private BinaryNode<T> rootTree = null; public BinarySearchTree() { } public boolean isEmpty() { return rootTree == null; } /** * 查找操作 * 在二叉查找树中查找key的过程如下: 1、若二叉树是空树,则查找失败。 2、若key等于根结点的数据,则查找成功,否则, 3、若key小于根结点的数据,则递归查找其左子树,否则, 4、递归查找其右子树。 */ public boolean contains(T key) { return contains(rootTree, key); } public boolean contains(BinaryNode<T> node, T key) { if(null == node) { //二叉树是空树,则查找失败。 return false; } int result = key.compareTo(node.data); if(result < 0) { // 若key小于根结点的数据,则递归查找其左子树 return contains(node.left, key); } else if(result > 0) { // 若key大于根结点的数据,则递归查找其右子树 return contains(node.right, key); } else { //若key等于根结点的数据,则查找成功 return true; } } /** * 查找最小值 * 最左子树的值 */ public T findMin() { if(isEmpty()) return null; return findMin(rootTree).data; } public BinaryNode<T> findMin(BinaryNode<T> node) { if(null == node) return null; if(null == node.left) return node; return findMin(node.left); } /** * 查找最大值 * 最右子树的值 */ public T findMax() { if(isEmpty()) return null; return findMax(rootTree).data; } public BinaryNode<T> findMax(BinaryNode<T> node) { if(null == node) return null; if(null == node.right) return node; return findMin(node.right); } /** * 二叉树查找树b插入操作key的过程如下: 1、若b是空树,则直接将插入的结点作为根结点插入。 2、key等于b的根结点的数据的值,则直接返回,否则。 3、若key小于b的根结点的数据的值,则将key要插入的结点的位置改变为b的左子树,否则。 4、将key要插入的结点的位置改变为b的右子树。 */ public void insert(T key) { rootTree = insert(rootTree, key); } public BinaryNode<T> insert(BinaryNode<T> node, T key) { if(null == node) { return new BinaryNode<T>(key); } int result = key.compareTo(node.data); if(result < 0) { node.left = insert(node.left, key); } else if(result > 0) { node.right = insert(node.right, key); } else ; return node; } /** * 删除操作 对于二叉查找树的删除操作(这里根据值删除,而非结点)分三种情况: 不过在此之前,我们应该确保根据给定的值找到了要删除的结点,如若没找到该结点 不会执行删除操作! 1、 如果结点为叶子结点(没有左、右子树),此时删除该结点不会破坏树的结构, 直接删除,修改其父结点指向它的引用为null 2. 如果其结点只包含左子树/右子树的话,此时直接删除该结点,并将其左子树/右子树设置为其父结点的左子树/右子树。即将该结点赋值为其左子树/右子树 3. 当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为 右子树的最小结点不可能有左孩子,所以第二次删除较为容易。 */ public void remove(T key) { rootTree = remove(rootTree, key); } public BinaryNode<T> remove(BinaryNode<T> node, T key) { if(null == node) // 未找到删除结点, 返回null return null; int result = key.compareTo(node.data); if(result < 0) { // 递归从左子树删除该元素 node.left = remove(node.left, key); } else if(result > 0) { // 递归从右子树删除该元素 node.right = remove(node.right, key); } else { // 找到该元素,判断左右子树情况 if(null != node.left && null != node.right) { // 左右子树都不空的时, 将该结点的值替换为右子树的最小值(不存在左子树),然后从右子树中删除该替换的值 node.data = findMin(node.right).data; node.right = remove(node.right, node.data); } else { // 如果结点为叶子结点(没有左、右子树)或如果其结点只包含左子树/右子树的话,将该结点赋值为其左子树/右子树 node = (node.left != null) ? node.left : node.right; } } return node; } }