我们知道,对于一个n个节点的二叉树,除了根节点外每个节点都有一个指向父亲的引用,因此有n-1个引用,而n个节点总共有2*n个引用,因此还有n+1个引用没有使用,如果把这些引用分别指向当前节点的前驱或者后继,则将此二叉树线索化。线索化后的二叉树遍历比较方便,不需要递归,效率快。以下使用java语言描述二叉树的线索化。
二叉树的节点Node类的代码如下:
package edu.qc.tree.thread;
public class Node {
private int data;
private Node left;
private boolean leftIsThread;//左孩子是否为线索
private Node right;
private boolean rightIsThread;//右孩子是否为线索
public Node(int data){
this.data = data ;
this.left = null ;
this.leftIsThread = false ;
this.right = null ;
this.rightIsThread = false ;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public boolean isLeftIsThread() {
return leftIsThread;
}
public void setLeftIsThread(boolean leftIsThread) {
this.leftIsThread = leftIsThread;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public boolean isRightIsThread() {
return rightIsThread;
}
public void setRightIsThread(boolean rightIsThread) {
this.rightIsThread = rightIsThread;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Node){
Node temp = (Node)obj ;
if(temp.getData() == this.data){
return true ;
}
}
return false;
}
@Override
public int hashCode() {
return super.hashCode() + this.data ;
}
}
然后具体的线索化二叉树ThreadTree类的代码如下:
package edu.qc.tree.thread;
public class ThreadTree {
private Node root;// 跟节点
private int size;// 大小
private Node pre = null ;//线索化的时候保存前驱
public ThreadTree(){
this.root = null ;
this.size = 0 ;
this.pre = null ;
}
public ThreadTree(int[] data){
this.pre = null ;
this.size = data.length ;
this.root = createTree(data , 1) ;//创建二叉树
}
/**
* 创建二叉树
* @param data
*/
public Node createTree(int[] data , int index){
if(index > data.length){
return null ;
}
Node node = new Node(data[index-1]) ;
Node left = createTree(data , 2*index) ;
Node right = createTree(data , 2*index+1) ;
node.setLeft(left) ;
node.setRight(right) ;
return node ;
}
/**
* 将以root为根节点的二叉树线索化
* @param root
*/
public void inThread(Node root){
if(root != null){
inThread(root.getLeft()) ;//线索化左孩子
if(null == root.getLeft()){//左孩子为空
root.setLeftIsThread(true) ;//将左孩子设置为线索
root.setLeft(pre) ;
}
if(pre!=null&&null == pre.getRight()){//右孩子为空
pre.setRightIsThread(true) ;
pre.setRight(root) ;
}
pre = root ;
inThread(root.getRight()) ;//线索化右孩子
}
}
/**
* 中序遍历线索二叉树
* @param root
*/
public void inThreadList(Node root){
if(root != null){
while(root!=null && !root.isLeftIsThread()){//如果左孩子不是线索
root = root.getLeft() ;//
}
do{
System.out.print(root.getData() + ",");
if(root.isRightIsThread()){//如果右孩子是线索
root = root.getRight() ;
}else{//有右孩子
root = root.getRight() ;
while(root!=null && !root.isLeftIsThread()){
root = root.getLeft() ;
}
}
}while(root != null) ;
}
}
/**
* 先序遍历递归算法
* @param root
*/
public void preList(Node root){
if(root != null){
System.out.print(root.getData() + ",");
preList(root.getLeft()) ;
preList(root.getRight()) ;
}
}
/**
* 中序遍历
* @param root
*/
public void inList(Node root){
if(root != null){
inList(root.getLeft()) ;
System.out.print(root.getData() + ",");
inList(root.getRight()) ;
}
}
public Node getRoot() {
return root;
}
public void setRoot(Node root) {
this.root = root;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
然后具体的测试类ThreadTreeTest的代码如下:
package edu.qc.tree.thread;
public class ThreadTreeTest {
public static void main(String[] args) {
int[] data = {1,2,3,4,5,6,7,8,9,10} ;
ThreadTree tt = new ThreadTree(data) ;//创建普通二叉树
tt.inList(tt.getRoot()) ;//中序递归遍历二叉树
System.out.println("");
tt.inThread(tt.getRoot()) ;//采用中序遍历将二叉树线索化
tt.inThreadList(tt.getRoot()) ;//中序遍历线索化二叉树
}
}