假设二叉树有n个结点,那么就有2n个指针域(左、右),n-1个连接分支线,意味着只有n-1个指针域得到利用,有2n-(n-1)个指针域为空指针域占用空间
线索二叉树
线索二叉树就是解决普通二叉树的空间利用率不够的问题。普通二叉树没有前驱和后继保存。刚好可以利用空指针域保存前驱和后继,当左指针域为空指针域时将左指针域指向它的前驱,当右指针域为空时指向该结点的后继。
为了区分指针域此时是前驱后继还是指向左子树右子树,那么就需要添加一个标志,标注此时指针域的状态。当指针域指向前驱后继时,可以很方便的查找到它的下一步和上一步该如何走,此时称指针域的指向为线索(thread)
import java.util.Scanner;
// 线索二叉树
// n个结点一共有2n个指针域(左右指针域)
// 一共有n-1个分支线,所以有n-1个指针域可以利用,有2n-(n-1)=n+1个指针域占用空间
// 线索二叉树就是解决普通二叉树的空间利用不够的问题
// 普通二叉数没有前驱和后继,正好利用空间存储加上线索。指向下一步或者上一步该如何走
// 达到一次
public class ThreadBinaryTree {
private BTreeNode root;// 根节点
public ThreadBinaryTree(String data){
this.root = new BTreeNode(data);
}
private enum Tag{Thread,Linked};
private class BTreeNode{
String data;// 数据域
BTreeNode left;// 左指针域
BTreeNode right;// 右指针域
Tag ltag = Tag.Linked;// 左孩子是线索还是指针
Tag rtag = Tag.Linked;// 右孩子是线索还是指针
public BTreeNode(String data){
this.data = data;
}
public void setLeft(BTreeNode left){
this.left = left;
}
public void setRight(BTreeNode right){
this.right = right;
}
}
// 生成一个结点
public BTreeNode createBTreeNode(String data){
return new BTreeNode(data);
}
// 前序遍历线索化
private static BTreeNode prev;// 前一个结点
public void inThreading(BTreeNode node){
if (node==null) return;
if (node.left==null){
node.ltag = Tag.Thread;
node.left = prev;
}
if (prev!=null&&prev.right==null){
prev.rtag = Tag.Thread;
prev.right = node;
}
prev = node;
if (node.ltag==Tag.Linked) inThreading(node.left);
if (node.rtag==Tag.Linked) inThreading(node.right);
}
// 前序遍历二叉树
public void prevOrderRecurse(BTreeNode node){
if (node==null) return;
System.out.println(node.data);
prevOrderRecurse(node.left);
prevOrderRecurse(node.right);
}
// 线索二叉树前序遍历
public void threadPrevOrderRecurse(BTreeNode node){
if (node==null) return;
BTreeNode p = node;
while (p!=null){
// 遍历左边
while (p.left!=null&&p.ltag==Tag.Linked){
System.out.println(p.data);
p = p.left;
}
// 一直查找右边即可
if (p.rtag==Tag.Thread) p = p.right;
while (p!=null){
System.out.println(p.data);
p = p.right;
}
}
}
public static void main(String[] args){
ThreadBinaryTree thrBTree = new ThreadBinaryTree("A");
BTreeNode node1 = thrBTree.createBTreeNode("B");
BTreeNode node2 = thrBTree.createBTreeNode("C");
BTreeNode node3 = thrBTree.createBTreeNode("D");
node1.setRight(node3);
thrBTree.root.setLeft(node1);
thrBTree.root.setRight(node2);
// 普通二叉树遍历
thrBTree.prevOrderRecurse(thrBTree.root);
// 线索二叉树遍历
thrBTree.inThreading(thrBTree.root);
thrBTree.threadPrevOrderRecurse(thrBTree.root);
}
}
private enum Tag{Thread,Linked};
枚举用于标注此时指针域的状态为线索(Thread)还是普通连接(Linked)。
使用线索二叉树遍历的好处在于充分利用了空间、一次线索化终身受用的目的、非递归遍历二叉树