1. 线索二叉树
普通二叉树在存储过程中如果树结点没有孩子域,那么它将指向空指针,这样就浪费了大量存储空间,在一棵有n个结点的普通二叉树中,每个结点有两个指针域,整棵树有2n个指针域,树中有n-1条边,所有有2n-(n-1) = n+1个空指针,从存储空间的角度来看,这n+1个空指针域浪费了内存资源。而在遍历二叉树的几种递归方法中,都利用了栈,在一定程度上也浪费了内存资源,层次遍历则是利用队列来实现,一样也浪费了内存资源。之所以要利用栈和队列来遍历二叉树,是因为我们不知道每个结点的前驱结点和后继结点分别是谁,如果我们在第一次遍历的时候,标记出每个结点的前驱结点和后继结点,那么在以后的每次遍历中将会获得更快的速度,而普通二叉树中的空指针也可以给我们利用起来。因此我们规定,如果一个树结点左孩子指针为空,就将它指向前驱结点,右孩子指针域为空就指向它的后继结点。我们把这种指向前驱和后继的指针成为线索,加上线索的二叉链表成为线索链表,对应的二叉树就成为“线索二叉树(Threaded Binary Tree)” 。
2.线索二叉树的类型
根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种;
记node指向二叉链表中的一个结点,以下是建立线索的规则:
(1)如果node的左指针域为空,则存放指向某种遍历序列中该结点的前驱结点,这个结点称为node的前驱;
(2)如果node的右指针域为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为node的后继;
1. 线索化的实质就是将二叉链表中的空指针改为指向前驱节点或后继节点的线索;
2. 线索化的过程就是修改二叉链表中空指针的过程,可以按照前序、中序、后序的方式进行遍历,分别生成不同的线索二叉树;
3. 有了线索二叉树之后,我们再次遍历时,就相当于操作一个双向链表。
4. 使用场景:如果我们在使用二叉树过程中经常需要遍历二叉树或者查找节点的前驱节点和后继节点,可以考虑采用线索二叉树存储结构。可以考虑采用线索二叉树存储结构。
3.中序线索二叉树的实现
在普通二叉树实现的基础上添加两个布尔值,用于标记树结点是否指向前驱结点和后继结点。
比如:
boolean rtag = false;//树结点的存在左孩子,左孩子指针不是线索
boolean ltag = true;//树结点的右孩子是线索,指向其后继结点
Java版本实现
package tree.thread;
public class ThreadTree {
class Node{
private int data;
private Node left = null;
private boolean ltag = false;
private Node right = null;
private boolean rtag = false;
public Node(int data) {
super();
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getLeft() {
return left;
}
public void setLef