我們知道,對於一個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()) ;//中序遍歷線索化二叉樹
}
}