前言:
我们平时写的关于树的算法都是直接写算法,就是比如写一个前序遍历就是
public void preOrder(TreeNode root)
{
//前序遍历
}
但是很少有写一个完整的测试用例的,即写一个函数按照图的样子创建一棵树,然后让这个函数返回根节点,然后就可以在主函数中定义一个树节点获取这个根节点,剩下的就是调用这些树的算法就好了。简而言之就是这篇博客不仅有常见的树的算法,还有真实的测试用例。
一、创建一棵树
首先就是定义树节点这个类
class TreeNode
{
Object data;
public TreeNode left;
public TreeNode right;
public TreeNode(Object data)
{
this.data=data;
this.left=null;
this.right=null;
}
}
1、首先讲最复杂情况,就是这个树的节点值五花八门,比如有数字(1 2 3),字母(h k D)还有可能有一些其他的乱七八糟的(*—/+?)这些都可以作为接节点值(所以前面把树节点的类型定义为Object),所以这样的情况下这些值是不可能放在数组里的(因为数组里的都要求同一类型),所以这种情况下把树节点的值放在字符串里,然后每个值用空格格开。
比如下面的这个树的节点值就可以用这个字符串表示:
String str="A - + 2 / 0 D 0 3 0 0 0 0 *";
解释为什么树的节点值没有0,但是字符串里确有0的,这是因为要按照完全二叉树的顺序写进字符串,按照完全二叉树的顺序如果在没有节点的地方就用0表示,这些0很关键,在后面的打印节点时候要判断。那为什么*后面的0没写进去,因为是按照完全二叉树的形式写,所以D是没有右节点的,所以不写最后一个0也是完全二叉树(这部分是完全二叉树的概念,理解这里对后面构造左右孩子有帮助。)
现在我们只是有了节点的值,还不是树节点的类型,那么接下来的思路是定义一个泛型是TreeNode类型的List,然后通过新建每一个树节点,然后把相应的节点值传给新建节点的方式把树节点都存在list中,然后在list中指明节点的左右孩子。完整代码如下(不看这些文字直接看代码也可以)
public class BianliTree {
public TreeNode create(String str)
{
List<TreeNode> list=new LinkedList<TreeNode>();
for(int i=0;i<str.split(" ").length;i++)
{
list.add(new TreeNode(str.split(" ")[i]));
}
for(int i=0;i<str.split(" ").length/2-1;i++)
{
list.get(i).left=list.get(2*i+1);
list.get(i).right=list.get(2*i+2);
}
//最后一个父节点,因为可能没有右孩子,所以单独拿出来处理。
int temp=str.split(" ").length/2-1;
list.get(temp).left=list.get(2*temp+1);
//如果节点数量是奇数,才有右孩子
if(str.split(" ").length%2==1)
{
list.get(temp).right=list.get(2*temp+2);
}
return list.get(0);
}
public void visit(TreeNode root)
{
if(!root.data.equals("0"))
{
System.out.print(root