树采用左孩子-右兄弟链接结构。
由于树与二叉树之间有自然对应的关系,故可以把树转换为对应的二叉树。
每个结点都有三部分:大孩子结点firstChild、数据域data、大兄弟结点nextBrother。
/**
* 树结点类
* @author liangxiamoyi
*
*/
public class TreeNode {
/**
* 数据值
*/
protected char data;
/**
* 大孩子结点
*/
protected TreeNode firstChild;
/**
* 大兄弟结点
*/
protected TreeNode nextBrother;
/**
* 构造方法
* @param data 数据值
* @param first 大孩子结点
* @param next 大兄弟结点
*/
public TreeNode(char data,TreeNode first,TreeNode next){
this.data=data;
this.firstChild=first;
this.nextBrother=next;
}
}
import java.util.Scanner;
/**
* 树
* @author liangxiamoyi
*
*/
public class Tree {
/**
* 根节点
*/
private TreeNode root;
/**
* 输入终止符
*/
private char stop;
/**
* 构造方法
*/
public Tree(){
this.root=null;
}
/**
* 在以t为根节点的树中,搜索p所指结点的父节点
* @param t 根节点
* @param p
* @return p的父节点
*/
public TreeNode findFather(TreeNode t,TreeNode p){
if(t==null||p==null)return null;
TreeNode result=null;
TreeNode q=t.firstChild;
while(q!=null&&q!=p){
result=findFather(q,p);
if(result==null)q=q.nextBrother;
else return result;
}
if(q==p)return t;
else return null;
}
/**
* 在根节点为t的树中,搜索数据域为item的结点
* @param t 根节点
* @param item 数据域
* @return 数据域为item的结点
*/
public TreeNode find(TreeNode t,char item){
if(t==null)return null;
TreeNode result=null;
if(t.data==item)return t;
else{
TreeNode p=t.firstChild;
while(p!=null&&(result=find(p,item))==null){
p=p.nextBrother;
}
return result;
}
}
/**
* 在以t为根节点的树中删除以p为根的子树
* @param t 根节点
* @param p 子树的根
*/
public void delSubTree(TreeNode t,TreeNode p){
if(t!=null&& p!=null){
TreeNode q=null;
TreeNode result=null;
result=findFather(t, p);
if(result!=null){
if(result.firstChild==p){
result.firstChild=p.nextBrother;
return;
}
else{
q=result.firstChild;
while(q.nextBrother!=p)q=q.nextBrother;
q.nextBrother=p.nextBrother;
return ;
}
}
else{
root=null;
}
}
}
/**
* 先根遍历
* @param t 根节点
*/
public void preOrder(TreeNode t){
if(t!=null){
System.out.print(t.data+" ");
TreeNode child=null;
child=t.firstChild;
while(child!=null){
preOrder(child);
child=child.nextBrother;
}
}
}
/**
* 非递归先根遍历
* @param t 根节点
*/
public void norecPreOrder(TreeNode t){
if(t==null)return;
AStack<TreeNode> s=new AStack<>(20);
TreeNode p=t;
do{
while(p!=null){
System.out.print(p.data+" ");
s.push(p);
p=p.firstChild;
}
while(p==null&&!s.isEmpty()){
p=s.pop();
p=p.nextBrother;
}
}while(!s.isEmpty());
}
/**
* 层次遍历
* @param t 根节点
*/
public void levelOrder(TreeNode t){
AQueue<TreeNode> a=new AQueue<TreeNode>(20);
if(t!=null){
TreeNode p;
a.insert(t);
while(!a.isEmpty()){
p=a.delete();
System.out.print(p.data+" ");
p=p.firstChild;
while(p!=null){
a.insert(p);
p=p.nextBrother;
}
}
}
}
public void createTree(char stop){
this.stop=stop;
this.root=create();
}
/**
* <p>创建一棵树</p>
* <p>将firstChild记为左孩子,将nextBrother记做右孩子</p>
* <p>输入时按二叉树先根遍历的顺序输入</p>
* @return 根节点
*/
public TreeNode create(){
TreeNode t,l,r;
char item;
Scanner sc=new Scanner(System.in);
item=sc.next().charAt(0);
if(item==stop){
t=null;
return t;
}
else{
t=new TreeNode(item, null, null);
l=create();
t.firstChild=l;
r=create();
t.nextBrother=r;
return t;
}
}
//测试
public static void main(String[] args){
// 测试数据
// a
// b
// z
// c
// e
// z
// f
// z
// z
// d
// z
// z
// z
Tree tree=new Tree();
tree.createTree('z');
System.out.println("先根遍历:");
tree.preOrder(tree.root);
System.out.println();
System.out.println("非递归先根遍历:");
tree.norecPreOrder(tree.root);
System.out.println();
System.out.println("层次遍历:");
tree.levelOrder(tree.root);
System.out.println();
System.out.println("请输入你想查询的结点的数据:");
Scanner sc=new Scanner(System.in);
char item=sc.next().charAt(0);
System.out.println("父结点:");
System.out.println(tree.findFather(tree.root, tree.find(tree.root, item)).data);
}
}
测试结果: