java实现二叉搜索树及二叉树测试

java实现二叉搜索树及二叉树测试

二叉树相关知识:

  1. 二叉树是每个节点都不能有多于两个儿子的树
  2. 二叉树的一个性质是一颗平均二叉树的深度要比节点数N小得多
  3. 二叉树的平均深度为O( N \sqrt N N )
  4. 二叉查找树的平均深度为O( log ⁡ N \log N logN)
  5. 关于删除节点
    a. 若删除的节点是叶节点则直接删除
    b. 若删除的是有两个儿子的节点则先用被删除节点的右子树的最小值覆盖被删除节点的值,之后珊瑚这个右子树最小值节点【这个节点一定没有左子树,所以递归到此处直接执行c情况】
    c. 若删除的是有一个儿子的节点则直接改变该节点的父节点的指向即可。
    d. 懒惰删除:当一个节点要被删除的时候依旧将其留在树中,只是被标记为被删除。
实现代码:
/**
 * 关于树的实现
 * 已实现的方法:
 * 1) 遍历【preorder,inorder,postorder】
 * 2) contains()
 * 3) findMin(),findMax()
 * 4) insertNode()
 * 5) removeNode()
 */

package tree;

public class MyBinaryTree<nodeType extends Comparable<? super nodeType>> {
    private BinaryNode<nodeType> mroot;

    public void setMroot(nodeType x) {
        mroot = new BinaryNode<>(x);
    }

    /**
     * 置空(初始化根节点)
     */
    public void makeEmpty() {
        mroot = null;
    }

    public void BinarySearchTree() {
        this.mroot = null;
    }

    /**
     * 判断是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return mroot == null;
    }

    /**
     * 树节点数据结构
     * 与链表的节点类一样,是一个嵌套类
     * 实现Comparable接口以实现比较功能
     *
     * @param <nodeType>
     */
    public static class BinaryNode<nodeType> {
        //数据定义:
        nodeType element;  //节点数据
        BinaryNode left;  //左节点
        BinaryNode right;  //右节点

        //Constructor
        public BinaryNode(nodeType element, BinaryNode left, BinaryNode right) {
            this.element = element;
            this.left = left;
            this.right = right;
        }

        public BinaryNode(nodeType element) {
            this(element, null, null);
        }
    }

    /**
     * 先序遍历 NLR
     *
     * @param root 被遍历的根节点
     */
    public void preoder(BinaryNode<nodeType> root) {
        if (root != null) {
            System.out.print(root.element + "\t");
            preoder(root.left);
            preoder(root.right);
        }
    }

    public void preorder() {
        preoder(mroot);
    }

    /**
     * 中序遍历 LNR
     *
     * @param root
     */
    public void inorder(BinaryNode<nodeType> root) {
        if (root != null) {
            inorder(root.left);
            System.out.print(root.element + "\t");
            inorder(root.right);
        }
    }

    public void inorder() {
        inorder(mroot);
    }

    /**
     * 后序遍历 LRN
     *
     * @param root 被遍历的节点
     */
    public void postorder(BinaryNode<nodeType> root) {
        if (root != null) {
            postorder(root.left);
            postorder(root.right);
            System.out.print(root.element + "\t");
        }
    }

    public void postorder() {
        postorder(mroot);
    }

    /**
     * 检查树中是否包含元素x
     * 使用尾递归,可以用while代替:
     * 尾递归可以通过将代码放到一个while循环中并且每个方法参数的一次赋值代替递归调用而被手工消除
     *
     * @param x    要搜索的元素
     * @param node 每个子树的根节点
     * @return
     */
    public boolean contains(nodeType x, BinaryNode<nodeType> node) {
        //尾递归
        /*
        if (node == null)
            return false;
        if (x.compareTo(node.element) < 0)
            return contains(x,node.left);
        else if (x.compareTo(node.element) > 0)
            return contains(x,node.right);
        else return true;
        */
        //将尾递归改为while
        while (true) {
            if (node == null) return false;
            if (x.compareTo(node.element) < 0)
                node = node.left;
            else if (x.compareTo(node.element) > 0)
                node = node.right;
            else
                return true;
        }
    }

    public boolean contains(nodeType x) {
        return contains(x, mroot);
    }

    /**
     * 寻找最小节点
     *
     * @param node 每个子树的根节点
     * @return 返回最小节点
     */
    public BinaryNode findMin(BinaryNode<nodeType> node) {
        //if (isEmpty())  throw new BufferUnderflowException();
       /* while (true){
            if (root.left != null){
                root = root.left;
            }else {
                return root.element;
            }
        }*/
        if (node == null) return null;
        if (node.left == null) return node;
        return findMin(node.left);
    }

    public nodeType findMin() {
        return (nodeType) findMin(mroot).element;
    }

    /**
     * 寻找最大节点
     *
     * @param node 每个子树的根节点
     * @return 返回最小节点
     */
    public BinaryNode findMax(BinaryNode<nodeType> node) {
        while (true) {
            if (node == null)
                return null;
            if (node.right == null)
                return node;
            else node = node.right;
        }
    }

    public nodeType findMax() {
        return (nodeType) findMax(mroot).element;
    }

    /**
     * 插入节点
     *
     * @param x    要插入的元素
     * @param root 根节点
     */
    public BinaryNode<nodeType> insertNode(nodeType x, BinaryNode<nodeType> root) {
        //若节点为空【包含根节点为空,root.left为空,root.right为空的情况】
        if (root == null)
            return new BinaryNode<nodeType>(x);
        if (x.compareTo(root.element) < 0)
            root.left = insertNode(x, root.left);
        else if (x.compareTo(root.element) > 0)
            root.right = insertNode(x, root.right);
        else
            ;  //重复值,不做任何操作
        return root;
    }

    /**
     * 在外部访问insert()
     *
     * @param x
     */
    public void insertNode(nodeType x) {
        insertNode(x, mroot);
    }

    /**
     * 删除节点,
     * 1) 叶节点直接删除
     * 2) 子节点先用右子树最小的值替换,再删除几点
     * 3) 懒惰删除:被删除节点还在树中,只是标记为被删除
     *
     * @param x    被删除的节点的element
     * @param root
     */
    public BinaryNode removeNode(nodeType x, BinaryNode<nodeType> root) {
        if (root == null)
            return root;  //未找到元素
        if (root.element.compareTo(x) < 0)
            root.right = removeNode(x, root.right);      //是否可以改写为 return removeNode(x, root.right)?
        else if (root.element.compareTo(x) > 0)
            root.left = removeNode(x, root.left);
        else if (root.right != null && root.left != null) { //被删除节点有两个子节点的情况
            root.element = (nodeType) findMin(root.right).element;
            root.right = removeNode(root.element, root.right);
        } else {
            //这里包含了没有子节点的情况,即root.rigth == root.left == null的情况
            //这里也包含了只有右节点或者左节点的情况
            //只有此处修改了root,其他地方在不修改其作用域内的root值【不止修改element】
            root = (root.left == null) ? root.right : root.left;
        }
        return root;
    }

    public nodeType removeNode(nodeType x) {
        return (nodeType) removeNode(x, mroot).element;
    }
}
测试代码:
/**
 * 二叉搜素树测试
 */

package tree.test;

import tree.MyBinaryTree;

public class MyBinaryTreeTest {
    private static final int[] arr = {1, 4, 5, 2, 6};

    public static void main(String[] args) {
        MyBinaryTree<Integer> tree = new MyBinaryTree<Integer>();
        System.out.println("== 依次添加:");
        tree.setMroot(3);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
            tree.insertNode(arr[i]);
        }
        System.out.print("\n先序遍历:");
        tree.preorder();
        System.out.print("\n中序遍历:");
        tree.inorder();
        System.out.print("\n后序遍历:");
        tree.postorder();
        System.out.println();
        boolean contains = tree.contains(5);
        System.out.println(contains);
        System.out.println("MinValue:" + tree.findMin());
        System.out.println("MaxValue:" + tree.findMax());
        System.out.println("删除节点:" + tree.removeNode(5));
        System.out.print("删除节点后先序遍历:");
        tree.preorder();
        System.out.print("\n删除节点后中序遍历:");
        tree.inorder();
        System.out.print("\n删除节点后后序遍历:");
        tree.postorder();
    }
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值