线索二叉树
具有n个节点的二叉链表中含有n+1个空指针。利用这些空指针域可以存放指向节点在某种遍历次序下的前驱节点和后继节点的指针(这种附加指针称为“线索”)。若一个节点的左指针为空,则可使其指向前驱节点,若其右节点为空,则可使其指向后继节点。又为了分辨指针到底是指向儿子还是前驱或后继节点,需要增加两个标志域。当标志位为0时表示其指向为儿子,当标志位为1时,表示其指向为前驱或者后继节点。
| leftSon | leftFlag | value | rightFlag | rightSon |
根据线索性质的不同可分为前序线索二叉树、中序线索二叉树、后序线索二叉树。
线索二叉树在遍历二叉树时不需要设栈,无需由叶子向树根溯源,故遍历线索二叉树的效率比普通二叉树更高。所以如果在程序中使用的二叉树经常需要遍历,该程序的存储结构就应该使用线索链表。
中序线索二叉树
如图所示,中序遍历的结果应为D,B,E,A,F,C,G。
不难发现,在中序遍历的情况下,开始位置为左子树最左边的节点,结束位置为右子树最右边的节点。
//中序线索化二叉树
public void threadTreeNodes(){
threadTreeNodes(root);
}
public void threadTreeNodes(ThreadedTreeNode node){
//当前节点为空,则返回
if(node==null){
return;
}
//处理左子树
threadTreeNodes(node.leftSon);
//处理前驱节点
if(node.leftSon==null){
//让当前节点的左指针指向前驱节点
node.leftSon = pre;
//改变当前节点左指针类型
node.leftFlag=1;
}
//处理前驱节点的右指针,如果前驱节点的右指针是null,则将当前节点设置为pre的后继节点。
if(pre!=null&&pre.rightSon == null){
pre.rightSon = node;
pre.rightFlag = 1;
}
//当前节点是下一个节点的前驱节点
pre = node;
//处理右子树
threadTreeNodes(node.rightSon);
}
//遍历线索二叉树
public void threadIterate(){
//用于临时存储当前遍历节点
ThreadedTreeNode node = root;
while(node!=null){
//找到开始节点
while(node.leftFlag==0){
node = node.leftSon;
}
//打印当前节点的值
System.out.println(node.value);
//如果当前节点的右指针指向的是后继节点,可能后继节点还有后继节点
while(node.rightFlag==1){
node = node.rightSon;
System.out.println(node.value);
}
//第一次执行到这里,node已经指向了root,开始遍历右子树。
node = node.rightSon;
}
}