线索二叉树
采用二叉链表和三叉链表作为二叉树的存储结构,只能找到节点的左右孩子和父节点(三叉链表),而不能直接找到该节点的直接前驱和直接后驱的相关信息,只能在对二叉树的遍历中才能得到,这显然不是最直接和最便利的方法。为了直接得到任何一个节点的直接前驱和直接后驱的信息,需要对二叉树进行线索化,本文主要介绍线索二叉树的概念机线索二叉树的遍历。
线索二叉树的概念
在二叉链表的存储结构中,n个节点的二叉链表具有n+1个空指针域(二叉树的分支数目为n-1,即非空域有n-1个,则空指针域有n+1个),因此可以利用这些孔指针域存放节点的直接前驱和直接后驱相关的信息。我们可以用下面的节点存储:
这种结构构成的二叉链表称为二叉树的线索二叉树。采用这种存储结构的二叉链表称为线索链表。其中指向节点直接前驱和直接后继的指针称为线索。在二叉树的遍历过程中,加上线索之后,得到先序线索二叉树,同理,在二叉树的中序(后序)遍历中,加上线索之后得到中序(后序)线索二叉树。二叉树按照某种遍历方式使二叉树变为线索二叉树的过程称为二叉树的线索化。
线索二叉树的实现
package binaryTree;
/**
* 线索二叉树
* @author Administrator
*
*/
public class ThreadedBinaryTree {
/**
* 线索二叉树的节点
* @author Administrator
*
* @param <T>
*/
private class Node<T>{
T data;
Node lChild;
Node rChild;
boolean ltag = false; //是否为左子节点
boolean rtag = false;//是否为右子节点
public Node(){
}
public Node(T data, Node lChild, Node rChild) {
this.data = data;
this.lChild = lChild;
this.rChild = rChild;
}
public Node(T data, Node lChild, Node rChild, boolean ltag, boolean rtag) {
this.data = data;
this.lChild = lChild;
this.rChild = rChild;
this.ltag = ltag;
this.rtag = rtag;
}
}
private Node pre;//刚刚访问过的节点
private Node root;//根节点
/**
* 中序线索二叉树
* @param root
* @return
*/
public void inOrderThreading(Node node){
//如果二叉树不为空
if(node != null){
//递归线索化左子树
inOrderThreading(node.lChild);
//如果没有左孩子
if(node.lChild == null){
node.ltag = false;//前驱线索
node.lChild = pre;//指向刚刚访问过的节点
}
//如果没有右孩子
if(node.rChild == null){
node.rtag = false;//后继线索
pre.rChild = node;//前驱的右孩子指向当前节点
}
pre = node;
//递归线索化右子树
inOrderThreading(node.rChild);
}
}
/**
* 中序线索二叉树的遍历
*/
public void inOrderThreadingTraverse(Node node){
while(node != root){
while(node.ltag == true){
//当存在左子树是,循环遍历到中序序列的第一个节点
node = node.lChild;
}
System.out.println(node.data);
while(node.rtag == false && node.rChild != root){
node = node.rChild;
System.out.println(node.data);
}
node = node.rChild;
}
}
}