虽然把树转换为二叉树可减少空间的浪费,但是如果我们仔细观察使用链表建立的n节点二叉树,会发现用来指向左右节点的指针只有n-1个链接,另外的n+1个指针都是空链接。线索二叉树就是把这些空的链接加以利用,再指到树的其他节点,而这些链接就称为”线索“(thread),而这棵树就称为线索二叉树(Threaded Binary Tree)。将二叉树转换为线索二叉树的步骤如下:
①先将二叉树通过中序遍历的方式按序排出,并将所有空链接改成线索;
②如果线索链接指向该节点的左链接,则将该线索指到中序遍历顺序下前一个节点;
③如果线索链接指向该节点的右链接,则将该线索指到中序遍历顺序下的后一个节点;
④指向一个空节点,并将此空节点的右链接指向自己,而空节点的左子树是此线索二叉树。
线索二叉树的基本结构如下:
leftTag leftNode DATA rightNode rightTag
leftTag:左控制位,如果leftTag=1,则为正常指针,若果leftTag=0,则为线索;
rightTag:右控制位,如果rightTag=1,则为正常指针,若果rightTag=0,则为线索;
leftNode:左子树链接;rightNode:右子树链接。
下面的示例程序是利用线索二叉树来追踪某一节点的中序前驱与中序后继:
//=============== Program Description ===============
//程序名称: ThreadTreeTest.java
//程序目的:线索二叉树的建立与中序遍历
//===================================================
import java.io.IOException;
class ThreadNode{
int value;
int leftTag;
int rightTag;
ThreadNode leftNode;
ThreadNode rightNode;
public ThreadNode(int value) {
this.value=value;
this.leftTag=0;
this.rightTag=0;
this.leftNode=null;
this.rightNode=null;
}
}
class ThreadTree{
public ThreadNode rootNode;
public ThreadTree(int[] data) {
for(int i=0;i<data.length;i++) {
AddNode(data[i]);
}
}
public void AddNode(int value) {
ThreadNode newnode=new ThreadNode(value);
ThreadNode current;
ThreadNode parent;
ThreadNode previous = null;
int pos;
if(rootNode==null) {
rootNode=newnode;
rootNode.rightTag=1;
rootNode.rightNode=null;
return;
}
if(rootNode.rightNode==null) {
rootNode.rightNode=newnode;
newnode.leftNode=rootNode;
return;
}
current=rootNode.rightNode;
parent=rootNode;
pos=0;
while(current!=null) {
if(current.value>value) {
if(pos!=-1) {
pos=-1;
previous=parent;
}
parent=current;
if(current.leftTag==1) {
current=current.leftNode;
}else {
current=null;
}
}else {
if(pos!=1) {
pos=1;
previous=parent;
}
parent=current;
if(current.rightTag==1) {
current=current.rightNode;
}else {
current=null;
}
}
}
if(parent.value>value) {
parent.leftTag=1;
parent.leftNode=newnode;
newnode.leftNode=previous;
newnode.rightNode=parent;
}else {
parent.rightTag=1;
parent.rightNode=newnode;
newnode.leftNode=parent;
newnode.rightNode=previous;
}
}
public void print() { //线索二叉树中序遍历
ThreadNode tempNode;
tempNode=rootNode;
do {
if(tempNode.rightTag==0)
tempNode=tempNode.rightNode;
else{
tempNode=tempNode.rightNode;
while(tempNode.leftTag!=0)
tempNode=tempNode.leftNode;
}
if(tempNode!=rootNode)
System.out.println("["+tempNode.value+"]");
}while(tempNode!=rootNode);
}
}
public class ThreadTreeTest {
public static void main(String[] args) throws IOException {
System.out.println("线索二叉树经建立后,以中序追踪能有排序的效果");
System.out.println("除了第一个数字作为线索二叉树的开头节点外");
int[] data1={0,10,20,30,100,399,453,43,237,373,655};
ThreadTree tree1=new ThreadTree(data1);
System.out.println("====================================");
System.out.println("范例 1 ");
System.out.println("数字由小到大的排列顺序结果为: ");
tree1.print();
int[] data2={0,101,118,87,12,765,65};
ThreadTree tree2=new ThreadTree(data2);
System.out.println("====================================");
System.out.println("范例 2 ");
System.out.println("数字由小到大的排列顺序结果为: ");
tree2.print();
}
}