线索化二叉树的实现(代码实现)
具体代码如下:(这里我们只给出中序线索化二叉树的代码,对于前序和后序其实是和中序大致相同的,这里不进行编写)
package com.ffyc.tree.threadedbinarytree;
import com.ffyc.tree.BinaryTree;
import org.junit.Test;
class HeroNode {
private int no; //英雄编号
private String name; //英雄名称
private HeroNode left; //默认为null,左指针,指向左子节点
private HeroNode right; //默认为null,右指针,指向右子节点
//表示我们的结点的指针的类型,如果是为0就是表示指向的是子树或者是子节点
private int leftType;
private int rightTyep;
public int getLeftType() {
return leftType;
}
public void setLeftType(int leftType) {
this.leftType = leftType;
}
public int getRightTyep() {
return rightTyep;
}
public void setRightTyep(int rightTyep) {
this.rightTyep = rightTyep;
}
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
//提供get和set方法
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 HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//因为我们要遍历二叉树,所以就要打印节点信息,所以我们再这里重写toString()方法
/*
这里要注意: 我们重写toString()方法的时候不要输出left和right属性 ,否则就会向下递归一直输出后面所有的left和right,因为left属性和right属性都是引用类型的属性
而如果输出我们的引用类型的数据,这个时候就会自动的调用其toString方法,这个时候因为我们的left和righ是引用类型的数据, 这个时候如果我们这里要输出left和right,那么
就会调用其对应的toString()方法,而left和right其实也是HeroNode类的数据,这个时候就会递归一直将后面所有的left和right都输出出来 -->而这个结果显然不是我们想要的
我们只是想要输出当前这一个节点就可以了
*/
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
/**
* 定义ThreadedBinaryTree类,实现中序线索化二叉树的功能
*/
public class ThreadedBinaryTree {
private HeroNode root; //创建一个root指针指向根节点,开始的时候默认为null -->表示树为空
//创建一个pre指针,指向node结点的前驱结点
HeroNode pre = null;
//设置根节点的值,用于构建二叉树
public void setRoot(HeroNode root){
this.root = root;
}
/**
* @param node 表示从node结点开始遍历并线索化
*/
public void threadedNodes(HeroNode node){
//递归的退出条件,只要是node指向了null,就说明一个方向已经是到头了,也就是需要退出这一层递归了
if (node == null){
return;
}
//向左递归
threadedNodes(node.getLeft());
//处理当前节点的线索化
if(node.getLeft() == null){
node.setLeft(pre);//和前驱结点连接
node.setLeftType(1);
}
if(pre != null && pre.getRight() == null){
pre.setRight(node); //和后继结点连接
pre.setRightTyep(1);
}
/*
注意: 每处理完一个节点之后我们都要让pre指向我们此时的node,然后再进行递归
*/
pre = node;
//向右进行递归
threadedNodes(node.getRight());
}
//提供重载方法,如果客户是从根节点开始线索化,直接调用这个方法即可
public void threadedNodes(){
threadedNodes(root);
}
}
给出我们的测试代码:
//测试代码:
@Test
public void test2(){
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
//创建几个结点
HeroNode heroNode1 = new HeroNode(1,"");
HeroNode heroNode2 = new HeroNode(3,"");
HeroNode heroNode3 = new HeroNode(6,"");
HeroNode heroNode4 = new HeroNode(8,"");
HeroNode heroNode5 = new HeroNode(10,"");
HeroNode heroNode6 = new HeroNode(14,"");
//手动的创建一个二叉树
heroNode1.setLeft(heroNode2);
heroNode1.setRight(heroNode3);
heroNode3.setRight(heroNode6);
threadedBinaryTree.setRoot(heroNode1);
heroNode2.setLeft(heroNode4);
heroNode2.setRight(heroNode5);
//进行一个中序线索化
threadedBinaryTree.threadedNodes();
System.out.println(heroNode4.getRight()); //原本的heroNode5结点中存储的no属性值为8的英雄,原本的这个节点的右指针是一个空指针, 但是这个时候线索化之后就是指向了no值为3的结点
}
补充:
如果我们的一个指针目前指向了某个对象,这个时候我们使用这个指针去调用对象的属性或者方法的时候一定要注意: 这个时候我们一定要确保指针指向的位置不是一个null, 所以我们就要提前进行一个判断, 比如我们上面代码中的如下操作:
//因为我们到执行到这一步的时候并不能确定我们的pre指针是否是指向了一个null
if(pre != null && pre.getRight() == null){
pre.setRight(node); //和后继结点连接
pre.setRightTyep(1);
}