线索二叉树
- 当用二叉链表作为二叉树的存储结构时,可以很方便地找到某个结点地左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中地前驱和后继结点。
- 什么是线索化二叉树:n个结点的二叉链表中含有n+1[ 公式 2n-(n-1)= n +1 ]个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针的指针(这种附加的指针称为“线索”)
- 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同,线索二叉树可分为前序线索二叉树,中序线索二叉树和后序线索二叉树。
- 一个结点的前一个结点称为前驱结点
- 一个结点的后一个结点称为后继结点
解决左右指针的指向可能为孩子或结点的方法:在结点类中设置属性来区分。
结点类:
private int no;
private String name;
private HeroNode left;
private HeroNode right;
// 1表示指向结点(前、后驱结点),0表示指向树(左、右子树)
private int leftType;
private int rightType;
- 代码实现
/**
* 对二叉树进行中序线索化的方法
*
* @param node 就是当前需要线索化的节点
*/
public void threadNodes(HeroNode node) {
if (node == null) {
return;
}
// 先线索化左子树
threadNodes(node.getLeft());
// 线索化当前节点
// 处理当前节点的前驱节点
if (node.getLeft() == null) {
// 让当前节点的左指针指向前驱节点
node.setLeft(pre);
node.setLeftType(1);
}
// 处理后继节点
// pre!=null的条件非常重要,它决定了第一次
if (pre != null && pre.getRight() == null) {
// 让前驱节点的右指针指向当前节点
pre.setRight(node);
// 修改前驱节点的右指针类型
pre.setRightType(1);
}
// 每处理一个节点,让当前节点是下一个节点的前驱节点
pre = node;
// 线索化右子树
threadNodes(node.getRight());
}
图解:
- 遍历线索化二叉树
说明:因为线索化后,各个结点的指向有变化,因此原来的遍历方式不能使用,各个结点可以通过线性方式遍历,无需使用递归方式,也提高了遍历的效率。遍历的次序应当和通过前、中、后序线索化一致。
/**
* 遍历中序线索化二叉树的方法
*/
public void threadedList() {
// 定义一个变量,存储当前遍历的结点,从root开始
HeroNode node = root;
while (node != null) {
// 循环的找到leftType为1的结点,说明该结点是按照线索化后处理的有效结点
while (node.getLeftType() != 1) {
node = node.getLeft();
}
System.out.println(node);
// 如果当前结点的右指针指向后继结点,则一直输出
while (node.getRightType() == 1) {
// 获取到当前结点的后继结点
node = node.getRight();
System.out.println(node);
}
// 替换这个遍历的结点
node = node.getRight();
}
}