!!(这里我debug很久才理解过来)** 这里8的前驱为null,所以8的leftType=1,但是6是没有后继的或者说后继为null但是rightType为0(因为后继是在下一个节点来进行连接的,6没有下一个节点,所以不能实现后继的线索化,所以rightType=0)**
public void threadedNodes(HeroNode node){
//如果node == null,就不能线索化
if (node == null){
return;
}
//(1)先线索化左子树
threadedNodes(node.getLeft());
//(2)线索化当前节点
//先处理当前节点的前驱节点
//以8节点来理解
//8节点的left = null,8节点的leftType = 1
if (node.getLeft() == null){
//让当前节点的左指针指向前驱节点
node.setLeft(pre);
//修改当前节点的做指针的类型
node.setLeftType(1);
}
//处理后继节点,处理8的后继节点,让pre的right指向node
if (pre != null && pre.getRight() == null){
//让前驱节点的右指针指向当前节点
pre.setRight(node);
//修改前驱节点的右指针类型
pre.setLeftType(1);
}
//!!!!每处理一个节点,让当前节点是下一个节点的前驱结点
pre = node;
//(3)线索化右子树
threadedNodes(node.getRight());
}
//遍历线索化二叉树的方法
public void threadedList(){
//定义一个遍历存储当前遍历的节点,从root开始
HeroNode node = root;
while (node != null){
//循环找到lefeYype == 1的节点,第一个找到的就是8
//后面随着遍历而变化,因为放leftType==1时说明该节点是按照线索化处理后的有效节点
while (node.getLeftType() == 0){
node = node.getLeft();
}
//打印当前节点
System.out.println(node);
//如果当前节点的右指针指向的是后继节点,就一直输出
while (node.getRightType() == 1){
//获取到当前节点的后继节点
node = node.getRight();
System.out.println(node);
}
//替换这个遍历的节点
node = node.getRight();
}
}
完整代码 (后序遍历线索二叉树没写出来,网上找了一些资料看完感觉还是有一点难度,暂时先不深入了)
package tree.threadedbinarytree;
public class ThreadedBrinaryTreeDemo {
public static void main(String[] args) {
//测试中序线索二叉树的功能
HeroNode root = new HeroNode(1, "tom");
HeroNode node2 = new HeroNode(3, "jack");
HeroNode node3 = new HeroNode(6, "smith");
HeroNode node4 = new HeroNode(8, "mary");
HeroNode node5 = new HeroNode(10, "king");
HeroNode node6 = new HeroNode(14, "dmi");
//二叉树,我们再递归创建,目前简单手动创建
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
//测试线索化
ThreadedBrinaryTree tBrinaryTree = new ThreadedBrinaryTree();
tBrinaryTree.setRoot(root);
tBrinaryTree.threadedNodes();
//测试以10号节点做测试
// HeroNode left = node3.getLeft();
// System.out.println("10号节点的前驱节点是:"+ left);
// HeroNode right = node3.getRight();
// System.out.println("10号节点的后继节点是:"+ right);
// System.out.println("使用线索化的方法中序遍历线索化 二叉树");
// tBrinaryTree.threadedInfixOrder();
// System.out.println("使用线索化的方法前序遍历线索化 二叉树");
// tBrinaryTree.threadedPreOrder();
}
}
//定义ThreadedBinaryTree
class ThreadedBrinaryTree{
private HeroNode root;
//为了实现线索化,需要创建一个指向当前节点的前驱节点的引用
//在递归线索化时,pre总是保留前一个节点
private HeroNode pre = null;
public void setRoot(HeroNode root){
this.root = root;
}
//重载threadedNodes
public void threadedNodes(){
this.threadedNodes(root);
}
//遍历线索化二叉树的前序遍历方法
public void threadedPreOrder(){
HeroNode node = root;
while (node != null){
//打印当前节点
System.out.println(node);
//向左循环有前驱
while(node.getLeftType() == 0){
node = node.getLeft();
System.out.println(node);
}
while (node.getRightType() == 1){
node = node.getRight();
}
node = node.getRight();
}
}
//遍历线索化二叉树的中序遍历方法
public void threadedInfixOrder(){
//定义一个遍历存储当前遍历的节点,从root开始
HeroNode node = root;
while (node != null){
//循环找到lefeYype == 1的节点,第一个找到的就是8
//后面随着遍历而变化,因为放leftType==1时说明该节点是按照线索化处理后的有效节点
while (node.getLeftType() == 0){
node = node.getLeft();
}
//打印当前节点
System.out.println(node);
//如果当前节点的右指针指向的是后继节点,就一直输出
while (node.getRightType() == 1){
//获取到当前节点的后继节点
node = node.getRight();
System.out.println(node);
}
//替换这个遍历的节点
node = node.getRight();
}
}
//编写对二叉树进行中序线索化的方法
public void threadedNodes(HeroNode node){
//如果node == null,就不能线索化
if (node == null){
return;
}
//(1)先线索化左子树
threadedNodes(node.getLeft());
//(2)线索化当前节点
//先处理当前节点的前驱节点
//以8节点来理解
//8节点的left = null,8节点的leftType = 1
if (node.getLeft() == null){
//让当前节点的左指针指向前驱节点
node.setLeft(pre);
//修改当前节点的做指针的类型
node.setLeftType(1);
}
//处理后继节点,处理8的后继节点,让pre的right指向node
if (pre != null && pre.getRight() == null){
//让前驱节点的右指针指向当前节点
pre.setRight(node);
//修改前驱节点的右指针类型
pre.setRightType(1);
}
//!!!!每处理一个节点,让当前节点是下一个节点的前驱结点
pre = node;
//(3)线索化右子树
threadedNodes(node.getRight());
}
//前序遍历
public void preOrder(){
if (this.root != null){
this.root.preOrder();
}else {
System.out.println("二叉树为空无法遍历");
}
}
//中序遍历
public void infixOrder(){
if (this.root != null){
this.root.infixOrder();
}else {
System.out.println("二叉树为空无法遍历");
}
}
//后序遍历
public void postOrder(){
if (this.root != null){
this.root.postOrder();
}else {
System.out.println("二叉树为空无法遍历");
}
}
//前序查找
public HeroNode preOrederSearch(int no){
if (root != null){
return root.preOrderSearch(no);
}else {
return null;
}
}
//中序查找
public HeroNode infixOrderSeach(int no){
if (root != null){
return root.infixOrderSearch(no);
}else {
return null;
}
}
//后序查找
public HeroNode postOrderSeach(int no){
if (root != null){
return root.postOrderSearch(no);
}else {
return null;
}
}
//删除节点
public void delNode(int no){
if (root != null){//判断root是不是要删除的节点
if (root.getNo() == no){
root = null;
}else {
root.delNode(no);
}
}
}
}
//创建节点
class HeroNode{
private int no;
private String name;
private HeroNode left;//默认null
private HeroNode right;//默认null;
//说明
//1.如果leftType == 0 表示指向的是左子树,如果是1表示指向前驱节点
//1.如果rightType == 0 表示指向的是右子树,如果是1表示指向后继节点
private int leftType;
private int rightType;
public int getLeftType() {
return leftType;
}
public void setLeftType(int leftType) {
this.leftType = leftType;
}
public int getRightType() {
return rightType;
}
public void setRightType(int rightType) {
this.rightType = rightType;
}
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
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;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
//编写前序遍历方法
public void preOrder(){
System.out.println(this);//先输出父节点
//递归向左子树前序遍历
if (this.left != null){
this.left.preOrder();
}
//递归向右子树前序遍历
if (this.right != null){
this.right.preOrder();
}
}
//编写中序遍历方法
public void infixOrder(){
//递归向左子树前序遍历
if (this.left != null){
this.left.infixOrder();
}
System.out.println(this);//输出父节点
//递归向右子树前序遍历
if (this.right != null){
this.right.infixOrder();
}
}
//编写后序遍历方法
public void postOrder(){
if (this.left != null){
this.left.postOrder();
}
if (this.right != null){
this.right.postOrder();
}
System.out.println(this);
}
public static int i = 1, j = 1, k =1;
//编写前序查找方法
public HeroNode preOrderSearch(int no){
System.out.println("前序遍历"+(i++)+"次");
if (this.no == no){
return this;
}
HeroNode heroNode = null;
if (this.left != null){
heroNode = this.left.preOrderSearch(no);
}
//不等于空说明在左边找到了
if (heroNode != null){
return heroNode;
}
if (this.right != null){
heroNode = this.right.preOrderSearch(no);
}
return heroNode;
}
//中序遍历查找
public HeroNode infixOrderSearch(int no){
HeroNode heroNode = null;
//先判断当前节点的左子节点是否为空,不为空继续进行中序查找
if (this.left != null){
heroNode = this.left.infixOrderSearch(no);
}
if (heroNode != null){
return heroNode;
}
System.out.println("中序遍历"+(j++)+"次");
if (this.no == no){
return this;
}
if (this.right != null){
heroNode = this.right.infixOrderSearch(no);
}
return heroNode;
}
//后序遍历查找
public HeroNode postOrderSearch(int no){
HeroNode heroNode = null;
//判断当前节点的左子节点是否为空,不为空,则递归后序遍历查找
if (this.left != null){
heroNode = this.left.postOrderSearch(no);
}
if (heroNode != null){
return heroNode;
}
//判断当前节点的右子节点是否为空,不为空,则递归后序遍历查找
if (this.right != null){
heroNode = this.right.postOrderSearch(no);
}
if (heroNode != null){
return heroNode;
}
System.out.println("后序遍历"+(k++)+"次");
//左右子树都没有找到,比较当前节点是不是
if (this.no == no){
return this;
}
return heroNode;
}
//递归删除节点
//规定:如果是叶子节点就删除节点,如果非叶子节点就删除子树
public void delNode(int no){
if (this.left !=null && this.left.no == no){
this.left = null;
return;
}
if (this.right != null && this.right.no == no){
this.right = null;
return;
}
if (this.left != null){
this.left.delNode(no);
}
if (this.right != null){
this.right.delNode(no);
}
}
}