使用此工具类注意事项:
- 用户需要自定义一个类,该类用作树节点TreeNode<T,V>的T泛型,自定义类中需要包含一个用于比较的数据.
- 用户自定义类中的数据需要实现Comparable接口.
- 用户自定义的类需要实现RandomValue接口(自定义接口,下图代码中以及包含)以及Comparable借口.
- 此工具类以及提供两个实例,以及两个实例的测试代码,可供参考.
- 该工具类仅供学习,如有不足或泛型使用不当,可以和我交流改进.
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);
}
}