- 有如下一棵二叉树:
我们发现,有一部分节点(3,4,5,6号节点)的左右指针域为空,比较浪费空间。**且 n 个节点的二叉树含有 n+1 个空指针域。**但是没有这些左右指针域又不行,如果能够充分利用他们,那再好不过了。
我们可以将他们用来指向自己的某种遍历方式的前序或者后序节点,方便遍历。这就是线索化二叉树,附加的指针称为“线索”。 - 以中序遍历为例,线索化二叉树如下图:
- 如何实现呢?
1.首先,我们需要为Node节点类添加属性leftType、rightType来记录指针域是指向的子节点还是前驱或者后继节点。如果leftType = 0,说明指向的是左子树;leftType = 1,指向的是前驱结点,如果rightType = 0,说明指向的是右子树;rightType = 1,指向的是后继结点。节点类代码如下:
public class Node {
private int id;
private String name;
private Node left;
private Node right;
//如果leftType == 0,说明指向的是左子树;leftType == 1,指向的是前驱结点
//如果rightType == 0,说明指向的是右子树;rightType == 1,指向的是后继结点
private int leftType;
private int rightType;
public Node(int id, String name) {
this.id = id;
this.name = name;
}
//getter setter toString方法
}
2.编写线索二叉树类,定义线索化方法。
由于父子节点之间是单向的,为了实现线索化,需要一个指向当前节点的前驱结点的指针pre,在线索化过程中,pre总是指向前一个节点。如果当前节点不为空,由于是中序遍历,所以先线索化左子树,再线索化当前节点,最后线索化右子树。线索化左子树右子树使用递归即可,关键的是对当前节点的线索化。
3.当前节点的线索化
需要判断当前节点的左右子节点是否存在(不存在的时候才会设置线索),以及当前节点的前驱结点的右子树是否存在(右子树为空才能将线索指向当前节点)。最后,还要把pre指向当前节点,往后继节点移动。
4.线索二叉树的遍历
先找到遍历的第一个节点,然后再顺着右指针线索遍历,只要rightType=1,就说明是后继节点。否则就遍历以rightType=0这个节点为根的二叉树,直到全部遍历结束(最后一个节点的右指针为空)。
5.代码如下:
public class ThreadedBinaryTree {
private Node root;
//为了实现线索化,需要一个指向当前节点的前驱结点的指针
//在线索化过程中,pre总是指向前一个节点
private Node pre = null;
public ThreadedBinaryTree(Node root) {
this.root = root;
}
//中序遍历线索二叉树
public void threadedShow(Node node){
while (node != null){
while (node.getLeftType() == 0){
node = node.getLeft();
}
System.out.println(node);
while (node.getRightType() == 1){
node = node.getRight();
System.out.println(node);
}
node = node.getRight();
}
}
//中序线索化二叉树
public void threaded(Node node){
if (node == null){
return;
}
//先线索化左子树
threaded(node.getLeft());
//线索化当前节点
if (node.getLeft() == null){
node.setLeft(pre);
node.setLeftType(1);
}
if (pre != null && pre.getRight() == null){
pre.setRight(node);
pre.setRightType(1);
}
pre = node;
//最后线索化右子树
threaded(node.getRight());
}
}
- 测试:
public class ThreadedDemo {
public static void main(String[] args) {
Node node1 = new Node(1,"A");
Node node2 = new Node(2,"B");
Node node3 = new Node(3,"C");
Node node4 = new Node(4,"D");
Node node5 = new Node(5,"E");
Node node6 = new Node(6,"F");
node1.setLeft(node2);
node1.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(node1);
threadedBinaryTree.threaded(node1);
threadedBinaryTree.threadedShow(node1);
}
}
- 中序线索二叉树的遍历结果: