Java实现二叉搜索树

前言

在做算法导论第12章的习题时,有一些习题需要用到二叉搜索树的数据结构,为了方便,我将其用Java实现了这个数据结构。

Talk is cheap,show me the code.我就闲话少说了,代码如下。

Java代码实现二叉搜索树数据结构

package hanxl.insist.twelvechapter;

import java.util.Stack;

/** * 搜索二叉树 * @author 韩兴隆 */
public class BinarySearchTree {

    private TreeNode root;

    /** * 将数组构建成一个二叉搜索树 * @param arr */
    public BinarySearchTree(int[] arr) {
        for (int i : arr)
            insert(i);
    }

    /** * 将给定的元素插入树中 * @param e */
    public void insert(Integer e) {
        TreeNode insertPosition = root;
        TreeNode insertPositionParent = null; //记录待插入位置的父节点

        while ( insertPosition != null ) {
            insertPositionParent = insertPosition;
            if ( e < insertPosition.item )
                insertPosition = insertPosition.left;
            else
                insertPosition = insertPosition.right;
        }

        TreeNode insertPoint = new TreeNode(null, e, null, insertPositionParent);
        if ( insertPositionParent == null ) //树是空的情况
            root = insertPoint;
        else if ( e < insertPositionParent.item )
            insertPositionParent.left = insertPoint;
        else
            insertPositionParent.right = insertPoint;
    }

    /** * 将给定的元素从树中删除 */
    public void delete(Integer num) {
        TreeNode delNode = search(root, num);
        if ( delNode.right == null )
            transplant(delNode, delNode.left);
        else if ( delNode.left == null )
            transplant(delNode, delNode.right);
        else {
            //无论minimum是不是delNode的右孩子,minimum都会与delNode交换
            //只不过在不是的这种情况下,minimum首先要与自己的右孩子进行交换,然后在重新定义minimum的右孩子
            TreeNode minimum = minimum(delNode.right);
            if(minimum.p != delNode) {
                transplant(minimum, minimum.right);
                minimum.right = delNode.right;
                minimum.right.p = minimum;
            }
            transplant(delNode, minimum);
            minimum.left = delNode.left;
            minimum.left.p = minimum;
        }
    }

    /** * 用一颗以tmpNode为根的子树来替换一棵以delNode为根的子树 * 结点delNode的父亲就变为tmpNode的父亲,并且最后tmpNode * 成为delNode的父亲的相应孩子。 */
    private void transplant(TreeNode delNode, TreeNode tmpNode) {
        if(delNode.p == null)
            root = tmpNode;
        if(delNode == delNode.p.left)
            delNode.p.left = tmpNode;
        else
            delNode.p.right = tmpNode;
        if(tmpNode != null)
            tmpNode.p = delNode.p;
    }

    /** * 在给定的节点及其后代中查询key * @return 如果查询到关键字则返回它,否则返回Null */
    public TreeNode search(TreeNode node, Integer key) {
        if ( node == null || node.item == key )
            return node;
        else if ( node.item < key )
            return search(node.right, key);
        else
            return search(node.left, key);
    }

    /** * 获取给定节点的前驱 */
    public TreeNode predecessor(TreeNode node) {
        //如果节点有左孩子,它的前驱一定为左子树中的最大值
        if (node.left != null)
            return maximum(node.left);

        TreeNode parent = node.p;
        // 如果节点是其父亲的左孩子,那么其前驱一定是遇到的第一个节点是其父亲的右孩子
        while (parent != null && node == parent.left) {
            node = parent;
            parent = parent.p;
        }

        //如果节点是其父亲的右孩子,它的前驱一定是它的父亲
        return parent;
    }

    /** * 获取给定节点的后继 */
    public TreeNode successor(TreeNode node) {
        if (node.right != null)
            return minimum(node.right);

        TreeNode parent = node.p;
        while (parent != null && node == parent.right) {
            node = parent;
            parent = parent.p;
        }

        return parent;
    }

    /** * 获取给定节点及其子树中的最小值 * @return */
    public TreeNode minimum(TreeNode node) {
        TreeNode minimum = node;
        while ( minimum.left != null )
            minimum = minimum.left;
        return minimum;
    }

    /** * 获取给定节点及其子树中的最大值 * @return */
    public TreeNode maximum(TreeNode node) {
        TreeNode maximum = node;
        while ( maximum.right != null )
            maximum = maximum.right;
        return maximum;
    }

    /** * 非递归版本的中序遍历 */
    public void inorderTreeWalk() {
        Stack<TreeNode> stack = new Stack<TreeNode>(); //这里我用Java.util包中自带的栈
        loadLeftNode(root, stack);
        System.out.print("中序遍历的结果: ");
        while ( !stack.isEmpty() ) {
            TreeNode currentNode = stack.pop();
            System.out.print(currentNode.item + " ");
            currentNode = currentNode.right;
            loadLeftNode(currentNode, stack);
        }
        System.out.println();
    }


    /** * 加载给定节点的所有后代中的左节点到栈中,直到叶子 * 节点为止 * @param stack */
    private void loadLeftNode(TreeNode node, Stack<TreeNode> stack) {
        TreeNode temp = node;
        while ( temp != null ) {
            stack.push(temp);
            temp = temp.left;
        }
    }


    public static class TreeNode {
        Integer item;
        TreeNode left;
        TreeNode right;
        TreeNode p;

        TreeNode(TreeNode left, Integer element, TreeNode right, TreeNode p) {
            this.item = element;
            this.left = left;
            this.right = right;
            this.p = p;
        }
    }

    public TreeNode getRoot() {
        return root;
    }
}

测试数据结构的代码

public static void main(String[] args) {
        int[] a = { 23, 45, 12, 56, 32, 78, 100, 3, 90, 678, 2, 4, 8, 92, 67, 49 };
        BinarySearchTree tree = new BinarySearchTree(a);

        tree.inorderTreeWalk(); //中序遍历树

        System.out.println(tree.search(tree.getRoot(), 12)); //在树中查找给定的关键字

        System.out.println("树中的最小值为:" + tree.minimum(tree.getRoot()).item);

        System.out.println("树中的最大值为:" + tree.maximum(tree.getRoot()).item);

        System.out.println("树根为:" + tree.getRoot().item + " 树根的前驱为:" + tree.predecessor(tree.getRoot()).item);

        System.out.println("树根为:" + tree.getRoot().item + " 树根的后继为:" + tree.successor(tree.getRoot()).item);

        tree.delete(100);
        tree.inorderTreeWalk(); //中序遍历树

    }

你可能感兴趣的:(数据结构)