1.什么是线索二叉树
- 在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。
- 对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树。
- 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
- 注意:线索链表解决了无法直接找到该结点在某种遍历序列中的前驱和后继结点的问题,解决了二叉链表找左、右孩子困难的问题。
优势
(1)利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度较一般二叉树的遍历速度快,且节约存储空间。
(2)任意一个结点都能直接找到它的前驱和后继结点。
不足
(1)结点的插入和删除麻烦,且速度也较慢。
(2)线索子树不能共用。
- 这里的中序应该为 8,3 ,10 ,1 ,14 ,6
- 应用
- no 8 没有前驱节点
- no 8 有后继节点 3 ,所以8的右指针指向no 3
- no 3 的左右指针都被占用,所以不能指向前驱或者后继节点
- no 10 的前驱节点为3,而且他左右指针都为空,所以10的左指针指向3 ,因为10的后继节点为1,所以右指针指向1
- no 1 的左右指针都被占用,所以不能指向前驱或者后继节点
- no 14的前驱节点为1,后继节点为6 ,而且他的左右指针都为空,所以14的左指针指向1,右指针指向6
- no 6的前驱节点为14,且左右指针都为空,那么6的左指针直线1,没有后继节点
代码实现
package com.qin.tree;
//线索化二叉树
public class ThreadedBinaryTreeDemo {
public static void main(String[] args) {
//测试中序线索二叉树
HeroNode1 root = new HeroNode1(1, "tom");
HeroNode1 node2 = new HeroNode1(3, "qxd");
HeroNode1 node3 = new HeroNode1(6, "lmy");
HeroNode1 node4 = new HeroNode1(8, "cxr");
HeroNode1 node5 = new HeroNode1(10, "cyc");
HeroNode1 node6 = new HeroNode1(14, "mzj");
//手动创建
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
//测试线索化、
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(); //创建线索化二叉树
threadedBinaryTree.setRoot(root);
threadedBinaryTree.threadedNode();
//测试 10 号节点测试
HeroNode1 left = node5.getLeft();
HeroNode1 right = node5.getRight();
System.out.println("10号节点的前驱节点"+left.toString());
System.out.println("10号节点的后继节点"+right.toString());
System.out.println("===========");
System.out.println("使用线索化的方式遍历线索化二叉树");
threadedBinaryTree.infixThreadedList();
}
}
//先创建HeroNode节点
class HeroNode1{
public int no;
public String name;
public HeroNode1 left; //默认null
public HeroNode1 right; //默认null
//说明
//1. 如果leftType == 0 表示指向的是左子树 ,leftType == 1 表明指向前驱节点
//1. 如果rightType == 0 表示指向的是右子树 ,rightType == 1 表明指向后继节点
public int leftType;
public int rightType;
public HeroNode1(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "HeroNode1{" +
"no=" + no +
", 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 HeroNode1 getLeft() {
return left;
}
public void setLeft(HeroNode1 left) {
this.left = left;
}
public HeroNode1 getRight() {
return right;
}
public void setRight(HeroNode1 right) {
this.right = right;
}
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;
}
}
//编写线索化二叉树
//第一一个BinaryTree 二叉树,实现了线索化功能的二叉树
class ThreadedBinaryTree{
private HeroNode1 root;
//为了实现线索化,需要创建要给指向当前节点的前驱节点的指针
//在递归线索化时,pre总是保留前一个节点
private HeroNode1 pre = null;
public void setRoot(HeroNode1 root) {
this.root = root;
}
//重载threadedNode方法
public void threadedNode(){
this.threadedNode(root);
}
//编写对二叉树中序线索化的方法
//node 就是当前需要线索化的节点
public void threadedNode(HeroNode1 node){
//如果说当前节点为空,node == null ,不能线索化
if(node==null){
return;
}
//1.先线索化左子树
threadedNode(node.left);
//2.线索化当前节点(重点)
//先处理当前节点的前驱节点
if (node.left==null){
//让当前节点的左指针指向前驱节点
node.left = pre;
//修改当前节点左指针的类型,指向的是前驱节点
node.setLeftType(1);
}
//处理后继节点
if (pre!=null && pre.getRight()==null){
//让前驱节点的右指针指向当前节点
pre.setRight(node);
//修改前驱节点的右指针类型
pre.setRightType(1);
}
//!!! 每处理一个节点后,让当前节点是下一个节点的前驱节点
pre = node;
//3.线索化右子树
threadedNode(node.right);
}
//遍历中序线索化二叉树
public void infixThreadedList(){
//定义一个变量,存储当前遍历的节点,从root开始
HeroNode1 node = root;
while (node != null){
//循环的找到leftType == 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();
}
}
}