线索二叉树是利用叶子结点的左右子树结点指向自己的前驱后继
利用浪费的空间让树更加效率
先创建二叉树结点:
public class node {
private int no;
private String name;
private node Left;
private node Right;
/**
* NoLeft和NoRight表示一个结点的左右节点是否有结点
* 如果有则表示1 没有则为0
*/
private int NoLeft;
private int NoRight;
public node(int no, String name) {
this.no = no;
this.name = name;
}
/**
* 删除结点
* @param no
*/
public void DelNode(int no){
/*
判断左子树是否为空,并且左子树的No是否等于要删除的no如果相等则把左子树置为空 删掉左子树。
如果不相等那就在下面递归
*/
if(this.Left!=null&&this.Left.getNo()==no){
this.Left=null;
return;
}
/*
判断右子树和左子树同理
*/
if(this.Right!=null&&this.Right.getNo()==no){
this.Right=null;
return;
}
/*
判断子树是否为空 继续递归下 直到直到叶子结点
*/
if(this.Left!=null){
this.Left.DelNode(no);
}
if(this.Right!=null){
this.Right.DelNode(no);
}
}
/**
* 中序遍历
*/
public void MidSelect(){
/*
判断结点子树是否为空 同时也是递归的终止条件
*/
if(this.Left!=null) this.Left.MidSelect();//向左递归
System.out.println(this);//输出此结点的数据
if(this.Right!=null) this.Right.MidSelect();//向右递归
}
/**
* 根据编号中序查找
*/
public node MidFound(int no){
/*
设计辅助结点,用来接收返回值
也是用来返回的值
*/
node temp=null;
/*
如果左子树有结点则递归左子树接收返回值
*/
if(this.Left!=null){
temp=this.Left.MidFound(no);
}
/*
用来递归左子树的结点 如果没找到则temp为null
*/
if(temp!=null) return temp;
/*
判断该结点是否为要查找的值结点
*/
if(this.getNo()==no){
return this;
}
if(this.Right!=null){
temp=this.Right.MidFound(no);
}
/*
用来递归右子树的结点 如果没找到则temp为null
*/
return temp;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public node getLeft() {
return Left;
}
public void setLeft(node left) {
Left = left;
}
public node getRight() {
return Right;
}
public void setRight(node right) {
Right = right;
}
public int getNoLeft() {
return NoLeft;
}
public void setNoLeft(int noLeft) {
NoLeft = noLeft;
}
public int getNoRight() {
return NoRight;
}
public void setNoRight(int noRight) {
NoRight = noRight;
}
@Override
public String toString() {
return "node{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
创建一个线索二叉树的建立:
public class BinaryTree {
/**
* root为根结点
*/
private node root;
/**
* pre是用来指向前驱的结点的继辅助指针
*/
private node pre;
public void setRoot(node root) {
this.root = root;
}
/**
* 普通二叉树转线索二叉树
*/
/**
* 重载方法 方便试用
*/
public void ClueNode(){
this.ClueNode(this.root);
}
public void ClueNode(node n){
if(n==null) return;
/*
中序转化 先线索化左子树一直递归到左子树
*/
ClueNode(n.getLeft());
//找到叶子结点没有前驱后继都是Null
/*
找到叶子结点后他的前驱肯定是空的 那么pre也是null直接赋值
并且设置为有结点状态
中序遍历的最左边的叶子前驱是没有东西的
其他结点同理
*/
if(n.getLeft()==null){
n.setLeft(pre);
n.setNoLeft(1);
}
//如果该结点pre不为空那说明该结点的前驱有了
//那就可以赋值后继
/**
* 那就可以吧此结点设置为pre来当下个结点的前驱也就是此结点的后继
* 如果pre不为空那表示已经有结点了
* 那就把pre设置为此结点来表示下个结点的前驱
* 有点类似于链表的辅助temp遍历链表
*/
if(pre!=null&&pre.getRight()==null){
pre.setRight(n);
pre.setNoRight(1);
}
//迭代处理下一个结点
pre=n;
/*
左子树处理完然后继续递归右子树
*/
ClueNode(n.getRight());
}
/**
* 遍历线索化二叉树
*/
public void ClueList(){
//创建临时结点用来迭代每个结点
node temp = this.root;
while(temp!=null){
//中序查询先从左子树查
//循环从根结点出发根结点的NoLeft是等于0的
//而最左子树的结点的NoLeft是等于1的
//也就是说到最左子树的时候停下并且打印
while(temp.getNoLeft()==0){
temp=temp.getLeft();
}
System.out.println(temp);
//现在temp是等于最左边的子树然后寻找后继就可以了
//叶子结点的NoRight如果等于1那就表示有后继
//如果一个结点拥有左右子树的话那这个结点的前驱后继是等于0的
//也就是从这个等于0的结点进行
/*
//继续循环找
temp=temp.getRight();
*/
while(temp.getNoRight()==1){
temp=temp.getRight();
System.out.println(temp);
}
//继续循环找
temp=temp.getRight();
}
}
}