一.中序线索二叉树的构造
(1)算法思想
所谓二叉树的线索化就是将二叉链表中的空指针改为指向前驱或者后驱的线索。而前驱和后驱的信息只有在遍历时才能得到,所以二叉树的线索化是在遍历的过程中同时进行的。故有前序,中序,后序线索二叉树,而这都跟二叉树的前序,中序,后序遍历一一对应。并且规定:若某个结点无左子树,则令其lchild指向其前驱结点;若无右子树,则令其rchild指向其后继结点。那么其中中序线索二叉树的构造如下图所示
根据中序遍历,我们可以知道,第一个访问的结点为B。而这时B的左右子树都为空,所以令其lchild指向B的前驱,且设置其lchild标志域的值为1(规定标志域值为0代表指向子结点,标志域值为1代表前驱或后驱结点)。但因为B是第一个结点,所以B的lchild指向NULL。
而第二个遍历的结点是A,因为A的lchild及rchild域均指向其左右子树结点,所以标志域的值均为0。而此时结点A的前驱为结点B,且B中的rchild为空,故令B中的rchild指向A,且rchild标志域的值为1.
那么最后一个遍历的结点为C,结点C的情况与B类似,其lchild与rchild域均为空,故lchild与rchild的标志域均置为1,且其lichild域指向A,rchild域指向NULL。
(2)代码实现
①数据类型声明
#include<stdio.h>
typedef int ElementType;
typedef struct ThreadTreeStruct * PtrToThreadTree;
typedef PtrToThreadTree ThreadTreeNode;
struct ThreadTreeStruct
{
ElementType data; //数据元素
ThreadTreeNode lchild, rchild; //左右孩子指针
int ltag, rtag; //左右线索标志
};
②实现函数
该方法与中序遍历方法相似,即把中序遍历中的访问方法改为中间的线索化
//1.中序线索化算法
void InThread(ThreadTreeNode p, ThreadTreeNode pre) {
if (p!=NULL) {
/*递归线索化左子树*/
InThread(p->lchild,pre);
if (p->lchild == NULL) {
p->ltag = 1;
p->lchild = pre; //指向前驱结点
}
if (pre!=NULL&&pre->rchild==NULL) {
pre->rchild = p; //指向后继结点
pre->rtag = 1;
}
/*递归线索化右子树*/
InThread(p->rchild, pre);
}
}
//2.主过程算法
void CreateInThread(ThreadTreeNode T) {
ThreadTreeNode pre = NULL;
if (T!=NULL) { //非空二叉树,进行线索化
InThread(T,pre); //遍历线索化二叉树
pre->rchild = NULL; //处理遍历的最后一个结点
pre->rtag = 1;
}
}
2.中序线索二叉树的遍历
(1)算法思想
①对于中序遍历来说,先查找二叉线索树的第一个节点(最左方向上的最后一个节点)
②从第一个结点开始,若该结点有右线索则先寻找后继节点,如果线索中断了(即该结点有右子树),则寻找右子树结点(注意线索上的节点是需要访问的)
(2)代码实现
//3.中序线索化遍历
void InOrder(ThreadTreeNode T) {
if (T==NULL) { //若根节点为空则返回
return;
}
ThreadTreeNode p = T; //p为工作指针
while (p!=NULL) {
while (p->ltag==0) { //结点有左树时,寻找最左端的树
p = p->lchild;
}
Visit(p);
while (p!=NULL&&p->rtag==1) { //节点非空并且右树是线索树时查找最前的一个线索树节点
p = p->rchild;
Visit(p);
}
p = p->rchild;//右树不是线索树,查找该节点的右孩子节点
}
}
//4.访问结点
void Visit(ThreadTreeNode T) {
printf("当前结点值:%d",T->data);
}