关于二叉树的链表,数组等表示法,都存在一个明显更的缺点,无法直接访问其每个节点的后继和前驱。对于有一些数据的便利需求显然是无法满足的。因此就提出了二叉树的线索这一方法。其核心就是在遍历二叉树的同时能直接对节点的前驱和后继进行访问操作。
二叉树的线索具体做法是在每一个二叉树的的节点上面添加两个额外的标签LTag,RTag。利用二叉树节点已有的左右孩子指针,在节点有孩子的情况下将Tag标签置为0(哪一侧有就将对应侧的标签置为0),原来左右孩子指针依然指向各自的孩子不变;当节点无孩子时将Tag标签置为1(哪一侧无就将哪一侧对应得标签置为1),并且将原来的孩子指针指向其前驱(LTag为1时)或后继(RTag为1时)。这样不仅能解决传统二叉树无法访问其节点前驱后继的问题还可以极大的利用二叉树节点已有的数据空间。(任何一个二叉树节点的任何一侧其Tag标签要么为0要么为1,二者只能选一个,这是上述方法可行的基本条件)
//二叉树线索的数据结构 typedef enum PointerTag{Precusor,Succeed};//Precusor==0:指针,succeed==1线索 typedef struct Node{ char data; struct Node *lchild, *rchild; PointerTag LTag,RTag; }BiNode,*BiTree;
我们来仔细分析一下二叉树线索(以中序遍历为例)的过程:如上图由头节点开始向下按T->lchild遍历直到到达D节点然后开始输出节点D的data此时D的RTag为1(Succeed即枚举的第二个值).此时T->rchild指向的是该节点的后继即为B节点然后输出B节点的data。此时B的rtag变为0(Precursor即为枚举的第一个值)接着访问E节点此时E的RTag为1,此时T->data为该节点的后继即为A。以此方式遍历整个二叉树。
二叉树线索的实现代码:
1,非递归法
typedef struct BiTree p; InOrder(BiTree T){ p=T->lchild; //p指向二叉树根节点
while(p!=T){
while(p->lchild==Precusor) p=p->lchild;
printf("%c",p->data);
if(p->data){
while(p->RTag==Succeed&&p->rchild!=T){
p=p->rchild;
printf("%c",p->data);
}
p=p->rchild;
}
}
}
2,递归调用法
typedef struct BiTree pre;
InOrder(BiTree T,BiTree &Thrt){ Thrt=(BiTree)malloc(sizeof(BiNode)) //Thrt为头结点 if(Thrt){ Thrt->LTag=Precusor; Thrt->RTag=secceed; Thrt->rchild=Thrt; } if(Thrt->lchild){ Thrt->lchild=T; pre=Thrt;
InThread(T);
pre->rchild=Thrt;
pre->rTag=Succeed;
Thrt->rchild=pre; }
return 0; }
InThread(BiTree p) {
if(p){
InThread(p->lchild);
if(!p->lchild) {p->LTag=Succeed;p->lchild=pre;}
if(!pre-rchild){pre->RTag=Succeed;pre->rchild=p;}
pre=p;
InTread(p->rchild);
}
}
以上就是关于二叉树线索的初步概括,水平有限!仅供学习参考用!