1.概念

n个结点的二叉链表中含有n+1个空指针域。

利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")

线索化二叉树及其遍历_edn


例如为10的这个节点,它的前驱节点为3,后继节点为1.

2.中序线索化代码

public class Main {
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, "dim");
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;

System.out.println("线索化之前 id为10的left为:"+ node5.left + " right为:"+ node5.right);
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(root);
threadedBinaryTree.threadedNodes(root);

System.out.println("线索化之后 id为10的left为:"+ node5.left + " right为:"+ node5.right);
}



}
class ThreadedBinaryTree{
HeroNode root;
HeroNode preCurNode = null;//指向当前节点的前一个节点

public ThreadedBinaryTree(HeroNode root) {
this.root = root;
}

//中序线索化二叉树
public void threadedNodes(HeroNode curNode){
if (curNode == null){
//System.out.println("当前节点为null 无法线索化");
return;
}

//先向左递归
threadedNodes(curNode.left);

//然后对当前节点进行线索化
//对当前节点的左指针进行线索化
if (curNode.left == null){
curNode.left = preCurNode;
curNode.HERO_NODE_TYPE_LEFT = 1;//说明左指针指向了前驱节点
}

//对右指针的线索化是下一轮进行的
if (preCurNode != null && preCurNode.right == null){
preCurNode.right = curNode;
preCurNode.HERO_NODE_TYPE_RIGHT = 1;
}

preCurNode = curNode;

//最后向右递归
threadedNodes(curNode.right);
}

}
//树的每个节点
class HeroNode{
int id;
String name;
HeroNode left;
HeroNode right;
//节点指针类型
//如果值为1说明节点左 或者 右指针指向的是前驱 或者 后继节点
//如果值为0说明节点左 或者 右指针指向的是左 或者 右子树
int HERO_NODE_TYPE_LEFT = 0;
int HERO_NODE_TYPE_RIGHT = 0;


public HeroNode(int id, String name) {
this.id = id;
this.name = name;
}

@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
值得注意的地方

①在​​HeroNode​​​中新增了两个变量,表示左右指针的指向类型。
②​​​threadedNodes​​​方法是线索化方法,需要注意​​preCurNode​​的取值,以及发挥作用是在下一轮。

结果
线索化之前 id为10的left为:null right为:null
线索化之后 id为10的left为:HeroNode{id=3, name='jack'} right为:HeroNode{id=1, name='tom'}

3.中序线索化二叉树的遍历

public class Main {
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, "dim");
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;

//System.out.println("线索化之前 id为10的left为:"+ node5.left + " right为:"+ node5.right);
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(root);
threadedBinaryTree.threadedNodes(root);

//System.out.println("线索化之后 id为10的left为:"+ node5.left + " right为:"+ node5.right);
threadedBinaryTree.sufixListThreadedBinaryTree();
}



}
class ThreadedBinaryTree{
HeroNode root;
HeroNode preCurNode = null;//指向当前节点的前一个节点

public ThreadedBinaryTree(HeroNode root) {
this.root = root;
}

/**
* 中序遍历线索二叉树,按照后继方式遍历(思路:找到最左子节点开始)
* @param node
*/
void inThreadList(HeroNode node) {
//1、找中序遍历方式开始的节点
while(node != null && node.HERO_NODE_TYPE_LEFT == 0) {
node = node.left;
}

while(node != null) {
System.out.print(node.id + ", ");

//如果右指针是线索
if(node.HERO_NODE_TYPE_RIGHT == 1) {
node = node.right;

} else { //如果右指针不是线索,找到右子树开始的节点
node = node.right;
while(node != null && node.HERO_NODE_TYPE_LEFT == 0) {
node = node.left;
}
}
}
}

//中序线索化二叉树
public void threadedNodes(HeroNode curNode){
if (curNode == null){
//System.out.println("当前节点为null 无法线索化");
return;
}

//先向左递归
threadedNodes(curNode.left);

//然后对当前节点进行线索化
//对当前节点的左指针进行线索化
if (curNode.left == null){
curNode.left = preCurNode;
curNode.HERO_NODE_TYPE_LEFT = 1;//说明左指针指向了前驱节点
}

//对右指针的线索化是下一轮进行的
if (preCurNode != null && preCurNode.right == null){
preCurNode.right = curNode;
preCurNode.HERO_NODE_TYPE_RIGHT = 1;
}

preCurNode = curNode;

//最后向右递归
threadedNodes(curNode.right);
}

}
//树的每个节点
class HeroNode{
int id;
String name;
HeroNode left;
HeroNode right;
//节点指针类型
//如果值为1说明节点左 或者 右指针指向的是前驱 或者 后继节点
//如果值为0说明节点左 或者 右指针指向的是左 或者 右子树
int HERO_NODE_TYPE_LEFT = 0;
int HERO_NODE_TYPE_RIGHT = 0;


public HeroNode(int id, String name) {
this.id = id;
this.name = name;
}

@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
结果
HeroNode{id=8, name='mary'}
HeroNode{id=3, name='jack'}
HeroNode{id=10, name='king'}
HeroNode{id=1, name='tom'}
HeroNode{id=14, name='dim'}
HeroNode{id=6, name='smith'}

4.完整版

包括前序线索化,前序线索化遍历;中序线索化,中序线索化遍历;后序线索化。无后序线索化遍历

import java.util.*;

public class Main {
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, "dim");
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;

System.out.println("x序线索化之前 id为14的left为:"+ node6.left + " right为:"+ node6.right);
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(root);
threadedBinaryTree.postThreadedNodes(root);

System.out.println("x序线索化之后 id为14的left为:"+ node6.left + " right为:"+ node6.right);

}
}
class ThreadedBinaryTree{
HeroNode root;
HeroNode preCurNode = null;//指向当前节点的前一个节点

public ThreadedBinaryTree(HeroNode root) {
this.root = root;
}
//前序遍历线索化二叉树
public void preListThreadedBinaryTree(){
HeroNode curNode = root;
while (curNode != null){
System.out.println(curNode);

//然后向左循环
while (curNode.HERO_NODE_TYPE_LEFT != 1){
curNode = curNode.left;
System.out.println(curNode);
}

while (curNode.HERO_NODE_TYPE_RIGHT != 0){
curNode = curNode.right;
System.out.println(curNode);
}

if (curNode.HERO_NODE_TYPE_RIGHT == 0){
curNode = curNode.right;
}

}
}
//中序遍历线索化二叉树
public void sufixListThreadedBinaryTree(){
HeroNode curNode = root;

while (curNode != null){
while (curNode.HERO_NODE_TYPE_LEFT == 0){
curNode = curNode.left;
}
//此时说明到达最左下角的哪个节点了
System.out.println(curNode);

while (curNode.HERO_NODE_TYPE_RIGHT != 0){
curNode = curNode.right;
System.out.println(curNode);
}

//这个if也可以没有
if (curNode.HERO_NODE_TYPE_RIGHT == 0){
curNode = curNode.right;
//当curNode为null的时候,就是到了最后一个节点了
//这个节点特点就是没有后继节点 即right==null,也就是树的最右下角的节点
}
}
}

//前序线索化二叉树
public void preThreadedNodes(HeroNode curNode){
if (curNode == null){
return;
}

//先线索化自己
if (curNode.left == null){
curNode.left = preCurNode;
curNode.HERO_NODE_TYPE_LEFT = 1;
}

if (preCurNode != null && preCurNode.right == null){
preCurNode.right = curNode;
preCurNode.HERO_NODE_TYPE_RIGHT = 1;
}

preCurNode = curNode;

//然后向左递归
//!!!!!! 注意这个条件 当左指针是左子树的时候才递归
if (curNode.HERO_NODE_TYPE_LEFT == 0){
preThreadedNodes(curNode.left);
}

//然后向右递归
//!!!!!! 注意这个条件 当右指针是右子树的时候才递归
if (curNode.HERO_NODE_TYPE_RIGHT == 0){
//然后向右递归
preThreadedNodes(curNode.right);
}

}
//中序线索化二叉树
public void threadedNodes(HeroNode curNode){
if (curNode == null){
//System.out.println("当前节点为null 无法线索化");
return;
}

//先向左递归
threadedNodes(curNode.left);

//然后对当前节点进行线索化
//对当前节点的左指针进行线索化
if (curNode.left == null){
curNode.left = preCurNode;
curNode.HERO_NODE_TYPE_LEFT = 1;//说明左指针指向了前驱节点
}

//对右指针的线索化是下一轮进行的
if (preCurNode != null && preCurNode.right == null){
preCurNode.right = curNode;
preCurNode.HERO_NODE_TYPE_RIGHT = 1;
}

preCurNode = curNode;

//最后向右递归
threadedNodes(curNode.right);
}

//然后后序线索化
public void postThreadedNodes(HeroNode curNode){
if (curNode == null){
return;
}

//先向左递归
postThreadedNodes(curNode.left);

//再向右递归
postThreadedNodes(curNode.right);

//最后输出自身
if (curNode.left == null){
curNode.left = preCurNode;
curNode.HERO_NODE_TYPE_LEFT = 1;
}

if (preCurNode != null && preCurNode.right == null){
preCurNode.right = curNode;
preCurNode.HERO_NODE_TYPE_RIGHT = 1;
}
preCurNode = curNode;
}

}
//树的每个节点
class HeroNode{
int id;
String name;
HeroNode left;
HeroNode right;
//节点指针类型
//如果值为1说明节点左 或者 右指针指向的是前驱 或者 后继节点
//如果值为0说明节点左 或者 右指针指向的是左 或者 右子树
int HERO_NODE_TYPE_LEFT = 0;
int HERO_NODE_TYPE_RIGHT = 0;


public HeroNode(int id, String name) {
this.id = id;
this.name = name;
}

@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}