泛型的使用实例:构建随机的搜索二叉树(可以使用任意类型的数据)

使用此工具类注意事项:

  1.     用户需要自定义一个类,该类用作树节点TreeNode<T,V>的T泛型,自定义类中需要包含一个用于比较的数据.
  2.     用户自定义类中的数据需要实现Comparable接口.
  3.     用户自定义的类需要实现RandomValue接口(自定义接口,下图代码中以及包含)以及Comparable借口.
  4.     此工具类以及提供两个实例,以及两个实例的测试代码,可供参考.
  5.     该工具类仅供学习,如有不足或泛型使用不当,可以和我交流改进.
package 二叉树工具类;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;

/**
 * 使用BSTUtils工具类时需要自己定义TreeNode节点的类型
 * 类型需要实现Comparable,RandomValue接口
 * 类型需要自定义需要比较的值的类型
 */
public class BSTUtils {
    /**
     * 接口定义
     * @param <V> 传入需要比较的值类型 如需要树节点为Integer类型,则实现RandomValue<Integer>接口
     */
    interface RandomValue<V extends Comparable<V>>{
        /**
         * 用于设置随机值,范围在min到max之间
         * @param min 创建随机值时最小的范围.
         * @param max 创建随机值时最大的范围
         */
        void setRandomValue(V min,V max);

        /**
         * 用于获取自定义类中的值
         * @return 返回生成好的值
         */
        V getValue();

        /**
         * 设置确定的值
         * @param sureValue 需要设置的值
         */
        void setSureValue(V sureValue);
    }

    /**
     * 自定义类(使用案例:Integer类型)
     * 实现Comparable<IntegerTestClass>,RandomValue<Integer>
     *  value为创建二叉树时需要比较的值
     */
    static class IntegerTestClass implements Comparable<IntegerTestClass>,RandomValue<Integer>{

        private Integer value;

        @Override
        public int compareTo(IntegerTestClass obj) {
            return value - obj.getValue();
        }

        @Override
        public void setRandomValue(Integer min,Integer max) {
            this.value = min + (int)(Math.random()*(max - min +1));
        }

        @Override
        public Integer getValue() {
            return value;
        }

        @Override
        public void setSureValue(Integer sureValue) {
            this.value = sureValue;
        }
    }

    /**
     * 自定义类(使用案例:String)
     * 实现Comparable<StringTestClass>,RandomValue<String>
     *  value为创建二叉树时需要比较的值
     */
    static class StringTestClass implements Comparable<StringTestClass>,RandomValue<String> {

        private String value;

        @Override
        public int compareTo(StringTestClass o) {
            return value.compareTo(o.getValue());
        }

        @Override
        public void setRandomValue(String min, String max) {
            //自定义实现.(在这只是做一个简单的演示)
            this.value = min.concat("a");
        }

        @Override
        public String getValue() {
            return this.value;
        }

        @Override
        public void setSureValue(String sureValue) {
            this.value = sureValue;
        }
    }


    /**
     * 树节点的定义
     * @param <T> 自定义的类型
     */
    public static class TreeNode<T extends Comparable<T> & RandomValue<V>,V extends Comparable<V>> {

        private TreeNode<T,V> left;
        private TreeNode<T,V> right;
        private T value;

        public TreeNode<T,V> getRight() {
            return right;
        }

        public TreeNode<T,V> getLeft() {
            return left;
        }

        public T getValue() {
            return value;
        }

        /**
         * 为树节点设置自定义类型的随机值
         * @param value 自定义类型的具体实例
         * @param min 自定义类型中值的最小值
         * @param max 自定义类型中值的最大值
         */
        public void setRandomValue(T value,V min,V max) {
            this.value = value;
            if (value != null) {
                value.setRandomValue(min,max);
            }
        }

        public void setValue(T value) {
            this.value = value;
        }

        public void setRight(TreeNode<T,V> right) {
            this.right = right;
        }

        public void setLeft(TreeNode<T,V> left) {
            this.left = left;
        }

        public int compareTo(TreeNode<T,V> o) {
            return this.value.compareTo(o.value);
        }


    }

    /**
     * 创建随机的搜索二叉树
     * @param tClass 自定义类型的Class对象
     * @param min 自定义类型实例值的最小值
     * @param max 自定义类型实例值的最大值
     * @param level 树的层级
     * @param <T> 自定义类型的类型
     * @return 返回TreeNode<T>节点
     * @throws TreeCreateErrorException 创建树时max比min小时抛出的错误
     */
    public static <T extends Comparable<T> & RandomValue<V>,V extends Comparable<V>> TreeNode<T,V> getTree(Class<T> tClass,V min,V max,int level) throws Exception {
        //判断初始化值是否设置错误.
        if (max.compareTo(min) < 0){
            throw new Exception("初始值设置错误");//错误时抛出异常
        }
        //开始创建树.
        TreeNode<T,V> head = new TreeNode<>();
        try {
            head = createTreeNode(tClass,min,max,1,level);
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        //创建完成
        return head;
    }

    /**
     * 创建树的子节点
     * @param tClass 传入的自定义类的类型信息
     * @param min 自定义类中值的最小值
     * @param max 自定义类中值的最大值
     * @param level 当前树的深度
     * @param n 最大树深度
     * @param <T> 自定义类的类型:要求实现Comparable和RandomValue接口
     * @param <V> 值类型: 要求实现Comparable接口
     * @return 返回子节点
     */
    private static <T extends Comparable<T> & RandomValue<V>,V extends Comparable<V>> TreeNode<T,V> createTreeNode(Class<T> tClass, V min, V max, int level,int n) throws IllegalAccessException, InstantiationException {
        if (max.compareTo(min) < 0 || level > n) {
            return null;
        }

        //创建树节点,不能通过new TreeNode<T>创建,在类型擦除之后,jvm不知道具体类型,无法创建
        TreeNode<T,V> head = new TreeNode<>();
        T t = tClass.newInstance();
        //为节点设置自定义类型的实例
        head.setValue(t);
        //为自定义类型实例赋值
        t.setRandomValue(min,max);
        //通过实现Comparable接口递归设置左右节点
        head.setLeft(createTreeNode(tClass,min,t.getValue(),level+1,n));
        head.setRight(createTreeNode(tClass,t.getValue(),max,level+1,n));

        return head;
    }

    /**
     * 先序遍历
     * @param head 树的头结点
     * @param <T> 树节点的值类型(自定义类)
     */
    public static <T extends Comparable<T> & RandomValue<V>,V extends Comparable<V>> void proOrderPrintTree(TreeNode<T,V> head) {
        ArrayList<TreeNode<T,V>> preOrderList = new ArrayList<>();
        Stack<TreeNode<T,V>> printStack = new Stack<>();
        printStack.push(head);
        TreeNode<T,V> temp = null;
        while(printStack.size() != 0) {
            temp = printStack.pop();
            preOrderList.add(temp);
            if (temp.getRight()!=null) {
                printStack.push(temp.getRight());
            }
            if (temp.getLeft()!=null) {
                printStack.push(temp.getLeft());
            }
        }

        for (TreeNode<T,V> tTreeNode : preOrderList) {
            if (tTreeNode.getValue() != null)
            {
                System.out.print((tTreeNode.getValue()).getValue()+" ");
            }
        }
    }

    /**
     * 中序遍历(中序遍历搜索二叉树会形成一个有序列表)
     * @param head 树的头结点
     * @param <T> 树节点的值类型(自定义类)
     */
    public static <T extends Comparable<T> & RandomValue<V>,V extends Comparable<V>> void inOrderPrintTree(TreeNode<T,V> head) {

        ArrayList<TreeNode<T,V>> inOrderList = new ArrayList<>();
        Stack<TreeNode<T,V>> stack = new Stack<>();
        //②创建变量指针cur表示当前正在访问的结点,cur初始值为root
        TreeNode<T,V> cur = head;
        //③将根结点放入栈中
        stack.push(cur);
        //④循环:当stack不为空就继续循环
        while (!stack.isEmpty()) {
            //⑤循环,如果左结点不为null就将结点放入栈中
            while (cur != null) {
                //先取左结点再放入栈中
                cur = cur.getLeft();
                //注意这里cur!=null并不表示cur.left!=null,因此要重新判断,只有left不为null才放入栈中,否则结束循环
                if (cur != null) {
                    stack.push(cur);
                }
            }
            //当左结点为null,即左结点遍历完成后
            //从栈中弹出结点,这就是当前遍历的结点,放入集合
            cur = stack.pop();
            inOrderList.add(cur);

            //取弹出结点的右结点,判断是否为null,如果不为null则同root一样放入stack中
            cur = cur.getRight();
            if (cur != null) {
                stack.push(cur);
            }
            //如果有结点为null,则通过循环继续弹出结点再取有右结点即可,直到stack为空
        }

        for (TreeNode<T,V> tTreeNode : inOrderList) {
            if (tTreeNode.getValue() != null)
            {
                System.out.print((tTreeNode.getValue()).getValue()+" ");
            }
        }

    }


    public static void main(String[] args) throws Exception {
        //自定义的类,并为其赋值(测试Integer类型的随机二叉树)
        IntegerTestClass min = new IntegerTestClass();
        min.setSureValue(0);
        IntegerTestClass max = new IntegerTestClass();
        max.setSureValue(20);
        //随机二叉树的生成
        TreeNode<IntegerTestClass,Integer> tree = getTree(IntegerTestClass.class,min.getValue(),max.getValue(), 4);


        //测试String类型的随机二叉树
//        StringTestClass min = new StringTestClass();
//        min.setSureValue("aaa");
//        StringTestClass max = new StringTestClass();
//        max.setSureValue("zzz");
//        TreeNode<StringTestClass> tree = getTree(StringTestClass.class,min.getValue(),max.getValue(), 2);


        //proOrderPrintTree(tree);
        inOrderPrintTree(tree);
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值