线索二叉树(Java)
在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化
定义
- 对二叉树进行遍历,可以把二叉树中所有结点排列为一个线性序列;
- 为了保留结点在某种遍历序列中 直接前驱和直接后继 的位置信息,可以利用二叉树的二叉链表存储结构中的空指针域 来指示
意义
- 一个具有n 个结点的二叉树若采用二叉链表存储结构,在2n 个指针域中只有n -1 个指针域是用来存储结点孩子的引用,而另外n +1 个指针域 存放的都是NULL
- 对二叉树进行遍历,时间复杂度大,且一次遍历之后无法记忆某结点的前驱或者后继
举个栗子
原二叉树如下:
经过先序线索化后的二叉树如下:
public void prethreadbinary(Node no) {//先序线索化
if(no==null) {
return ;
}
if(no.getLeft()==null) {
no.setLeft(pre);
no.setLeftype(1);
}
if(pre!=null&&pre.getRight()==null) {
pre.setRight(no);
pre.setRighttype(1);
}
pre=no;
if(no.getLeftype()==0) {
prethreadbinary(no.getLeft());//线索化右8子树
}
if(no.getRighttype()==0) {
prethreadbinary(no.getRight());
}
}
经过中序线索化后的二叉树如下:
public void infixthreadbinary(Node no) {//中序线索化
if(no==null) {
return;
}
infixthreadbinary(no.getLeft());//线索化左子树
if(no.getLeft()==null) {//处理前驱结点
no.setLeft(pre);
no.setLeftype(1);
}
if(pre!=null&&pre.getRight()==null) {//处理后继结点
pre.setRight(no);
pre.setRighttype(1);
}
pre=no;//处理一个结点后,让当前结点为下一个结点的前驱
infixthreadbinary(no.getRight());//线索化右子树
}
遍历线索二叉树
因线索化后有前驱和后继,所以之前的遍历方式会出现死循环
先序遍历先序线索化二叉树:
//先序遍历
public void prethread() {
Node no=root;
while(no!=null) {
while(no.getLeftype()==0) {
System.out.println(no);
no=no.getLeft();
}
System.out.println(no);
no=no.getRight();
}
}
中序遍历中序线索化二叉树:
//中序遍历
public void infixthread() {
Node no=root;
while(no!=null) {
while(no.getLeftype()==0) {//找到leftype==1的结点,即被线索化结点
no=no.getLeft();
}
System.out.println(no);
while(no.getRighttype()==1) {//获取当前结点的后继结点
no=no.getRight();
System.out.println(no);
}
no=no.getRight();//用后继结点替换当前结点
}
}
完整代码
public class Threadbinarytree2 {
public static void main(String[] args) {
Threadbinarytree binarytree=new Threadbinarytree();//创建二叉树
Node root = new Node( "A");//创建结点
Node node2 = new Node( "B");
Node node3 = new Node( "C");
Node node4 = new Node( "D");
Node node5 = new Node( "E");
Node node6 = new Node("F");
root.setLeft( node2);//建立结点间的关系
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
binarytree.setRoot(root);
// System.out.println("-----先序线索化二叉树后------");
// binarytree.prethreadbinary();//线索化二叉树
// Node lnode=node5.getLeft();
// Node rnode=node5.getRight();
//
// System.out.println("E结点的前驱结点为:"+lnode);
// System.out.println("E结点的后继结点为:"+rnode);
// System.out.println("前序遍历二叉树结果为:");
// binarytree.prethread();
System.out.println("-----中序线索化二叉树后------");
binarytree.infixthreadbinary();//线索化二叉树
Node lnode=node5.getLeft();
Node rnode=node5.getRight();
System.out.println("E结点的前驱结点为:"+lnode);
System.out.println("E结点的后继结点为:"+rnode);
System.out.println("中序遍历二叉树结果为:");
binarytree.infixthread();
}
}
class Threadbinarytree {//定义二叉树
private Node root;
private Node pre=null;//前驱指针
public void setRoot(Node root) {
this.root = root;
}
public void prethreadbinary() {
this.prethreadbinary(root);
}
public void infixthreadbinary() {//重载
this.infixthreadbinary(root);
}
public void prethreadbinary(Node no) {//先序线索化
if(no==null) {
return ;
}
if(no.getLeft()==null) {
no.setLeft(pre);
no.setLeftype(1);
}
if(pre!=null&&pre.getRight()==null) {
pre.setRight(no);
pre.setRighttype(1);
}
pre=no;
if(no.getLeftype()==0) {
prethreadbinary(no.getLeft());//线索化右8子树
}
if(no.getRighttype()==0) {
prethreadbinary(no.getRight());
}
}
public void infixthreadbinary(Node no) {//中序线索化
if(no==null) {
return;
}
infixthreadbinary(no.getLeft());//线索化左子树
if(no.getLeft()==null) {//处理前驱结点
no.setLeft(pre);
no.setLeftype(1);
}
if(pre!=null&&pre.getRight()==null) {//处理后继结点
pre.setRight(no);
pre.setRighttype(1);
}
pre=no;//处理一个结点后,让当前结点为下一个结点的前驱
infixthreadbinary(no.getRight());//线索化右子树
}
//前序遍历
public void prethread() {
Node no=root;
while(no!=null) {
while(no.getLeftype()==0) {
System.out.println(no);
no=no.getLeft();
}
System.out.println(no);
no=no.getRight();
}
}
//中序遍历
public void infixthread() {
Node no=root;
while(no!=null) {
while(no.getLeftype()==0) {//找到leftype==1的结点,即被线索化结点
no=no.getLeft();
}
System.out.println(no);
while(no.getRighttype()==1) {//获取当前结点的后继结点
no=no.getRight();
System.out.println(no);
}
no=no.getRight();//用后继结点替换当前结点
}
}
}
class Node{
private String no;
private Node left;
private Node right;
private int leftype;
private int righttype;
public Node(String no) {
this.no=no;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public int getLeftype() {
return leftype;
}
public void setLeftype(int leftype) {
this.leftype = leftype;
}
public int getRighttype() {
return righttype;
}
public void setRighttype(int righttype) {
this.righttype = righttype;
}
@Override
public String toString() {
return "Node [no=" + no + "]";
}
}