数据结构与算法--线索二叉树及其前序、中序遍历
二叉树如果某个结点没有左孩子或右孩子,则这个域就为空。如node.lChild = null,
而叶子结点两个指针域都是null。我们知道n个结点的二叉树共有2n个指针域,树只有n-1条分支,也就是说还有2n - (n -1) = n + 1个域是空指针。为了充分利用这些空指针,可以存一些有用的信息——比如某结点的前驱和后继结点(按某种次序遍历后的顺序)。这种指向前序后继的指针称为线索,具有前驱后继关系的二叉树叫线索二叉树。线索二叉树的好处是:不仅节约了空间,而且一旦按照某种次序(中序、前序或后序)遍历一次后,线索信息就已经初始化好,下次想要获取某个结点的前驱后继就不用再遍历整棵树了。
具体来说,对于所有空指针域,lChild指向该结点的前驱结点;rChild指向该结点的后继结点。但是lChild和rChild同时也表示某结点的左孩子和右孩子,一个指针有两种意思,对某个结点究竟指代的哪种意思?显然需要一个标志加以区分,我们给每个结点的孩子加上标志,如果是false则表示左/右孩子,如果是true则表示前驱/后继。这棵二叉树中序遍历的结果是HDIBEAFCG,按照遍历所得顺序,H的后继就是D,h.rChild本来是null,现在让其指向D,由于这表示后继,所以相应的标志位应该设置为true。这幅图将所有rChild为空的指针域都指向了其后继。
那么前驱呢?自然是将所有lChild为空的指针域指向该结点的前驱。如下图。
如果将这两幅图结合起来,则每个空指针域都已用上了。这棵二叉树就成了下面这个样子
虚线表示右孩子或者后继,实线表示左孩子或者前驱,具体怎么区分也就是看给结点左右孩子设置的标志位了。仔细观察,把这颗树两头拉直,就成了双向链表!(但又和普通的双向链表不同,这里前驱后继的含义指代比较模糊)
现在来试着实现一下。
package Chap6;
public class ThreadTree {
public static class Node {
private T data;
private Node lchild;
private Node rchild;
private boolean isleftThead;
private boolean isRightThead;
public Node(T data) {
this.data = data;
isleftThead = false;
isRightThead = false;
}
public T getData() {
return data;