线索二叉树的基本概念
我们按某种方式对二叉树进行遍历,将二叉树中所有节点排序为一个线性序列,在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点;除最后一个结点外每一个结点有且仅有一个直接后继结点。
在有N个节点的二叉树中需要利用N+1个空指针添加线索,这是因为在N个节点的二叉树中,每个节点有2个指针,所以一共有2N个指针,除了根节点以外,每一个节点都有一个指针从它的父节点指向它,所以一共使用了N-1个指针,所以剩下2N-(N-1)也就是N+1个空指针;
我们利用这些空指针域来存放指向该节点的直接前驱或是直接后继的指针,则可由此信息直接找到在该遍历次序下的前驱结点或后继结点,从而比递归遍历提高了遍历速度,节省了建立系统栈所使用的存储空间;
这些被重新利用起来的空指针就被称为线索(Thread),加上了这些线索的二叉树就是线索二叉树
根据线索性质的不同,线索二叉树可以分为前序线索二叉树,中序线索二叉树,后序线索二叉树。
记node指向二叉链表中的一个结点,以下是建立线索的规则:
(1)如果node的左指针域为空,则存放指向某种遍历序列中该结点的前驱结点,这个结点称为node的前驱;
(2)如果node的右指针域为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为node的后继;
代码实现
修改二叉树节点数据结构,节点类:
package 线索二叉树;
public class ClueNode {
private Object data;
private ClueNode left;
private ClueNode right;
private boolean leftIsThread;
private boolean rightIsThread;
public ClueNode(Object data) {
this.data = data;
this.left = null;
this.right = null;
this.leftIsThread = false;
this.rightIsThread = false;
}
public ClueNode(Object data, ClueNode left, ClueNode right, boolean leftIsThread, boolean rightIsThread) {
this.data = data;
this.left = left;
this.right = right;
this.leftIsThread = leftIsThread;
this.rightIsThread = rightIsThread;
}
public Object getData() {
return this.data;
}
public void setData(Object data ) {
this.data = data;
}
public ClueNode getLeft() {
return left;
}
public void setLeft(ClueNode left)
{
this.left = left;
}
public boolean isLeftIsThread()
{
return leftIsThread;
}
public void setLeftIsThread(boolean leftIsThread)
{
this.leftIsThread = leftIsThread;
}
public ClueNode getRight()
{
return right;
}
public void setRight(ClueNode right)
{
this.right = right;
}
public boolean isRightIsThread()
{
return rightIsThread;
}
public void setRightIsThread(boolean rightIsThread)
{
this.rightIsThread = rightIsThread;
}
public boolean equals(Object o) {
if(o instanceof ClueNode) {
ClueNode clue = (ClueNode)o;
return (clue.getData() == this.data) ? true : false;
}
else return false;
}
}
线索二叉树类:
package 线索二叉树;
public class ClueForkTree {
private ClueNode preNode;
//根据数组构建完全二叉树
public static ClueNode createClueForkTree(Object[] array, int index) {
ClueNode node = null;
if(index < array.length) {
node = new ClueNode(array[index]);
ClueNode left = createClueForkTree(array, index * 2 + 1);
ClueNode right = createClueForkTree(array, index * 2 + 2);
node.setLeft(left);
node.setRight(right);
return node;
}
else return null;
}
//中序线索化二叉树
public void inThReading(ClueNode node) {
if(node == null) return;
inThReading(node.getLeft());
if(node.getLeft() == null) {
node.setLeft(preNode);
node.setLeftIsThread(true);
}
if(preNode != null && preNode.getRight() == null) {
preNode.setRight(node);
preNode.setRightIsThread(true);
}
preNode = node;
inThReading(node.getRight());
}
//中序按后继方式遍历线索二叉树
public void inThreadList(ClueNode node) {
while(node != null && !node.isLeftIsThread()) {
node = node.getLeft();
}
while(node != null) {
System.out.print(node.getData() + ",");
if(node.isRightIsThread()) {
node = node.getRight();
}
else {
node = node.getRight();
while(node != null && !node.isLeftIsThread()) {
node = node.getLeft();
}
}
}
}
//中序按前驱方式遍历线索二叉树
public void inPreThreadList(ClueNode node) {
while(node.getRight() != null && !node.isRightIsThread()) {
node = node.getRight();
}
while(node != null) {
System.out.print(node.getData() + ",");
if(node.isLeftIsThread()) {
node = node.getLeft();
}
else {
node = node.getLeft();
while(node.getRight() != null && !node.isRightIsThread()) {
node = node.getRight();
}
}
}
}
//前序线索化二叉树
public void inThFrontReading(ClueNode node) {
if(node == null) return;
if(node.getLeft() == null) {
node.setLeft(preNode);
node.setLeftIsThread(true);
}
if(preNode != null && preNode.getRight() == null) {
preNode.setRight(node);
preNode.setRightIsThread(true);
}
preNode = node;
if(!node.isLeftIsThread()) {
inThFrontReading(node.getLeft());
}
if(!node.isRightIsThread()) {
inThFrontReading(node.getRight());
}
}
//前序按后继方式进行遍历二叉树
public void preThreadList(ClueNode node) {
while(node != null) {
while(!node.isLeftIsThread()) {
System.out.print(node.getData() + ",");
node = node.getLeft();
}
System.out.print(node.getData() + ",");
node = node.getRight();
}
}
public static void main(String[] args) {
String[] array = {"A", "B", "C", "D", "E", "F", "G", "H"};
ClueNode root = createClueForkTree(array, 0);
ClueForkTree tree = new ClueForkTree();
tree.inThReading(root);
System.out.println("中序按后继节点遍历线索二叉树结果:");
tree.inThreadList(root);
System.out.println("
中序按前驱节点遍历线索二叉树结果:");
tree.inPreThreadList(root);
ClueNode root1 = createClueForkTree(array, 0);
tree.inThFrontReading(root1);
tree.preNode = null;
System.out.println("
前序按后继节点遍历线索二叉树结果:");
tree.preThreadList(root1);
}
}