线索二叉树考的不多
目录
手工部分的话不难,我这里放大佬博客了
图解线索二叉树_八百万的博客-CSDN博客_后序线索二叉树画法图解
很快就能理解并写出线索二叉树的手工题
直接上
基础代码
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
typedef char TElemType;
typedef enum { Link, Thread } PointerTag; //Link==0,表示指向左右孩子指针
//Thread==1,表示指向前驱或后继的线索
//二叉树线索结点存储结构
typedef struct BiThrNode {
TElemType data; //结点数据
struct BiThrNode *lchild, *rchild; //左右孩子指针
PointerTag LTag;
PointerTag RTag; //左右标志
}BiThrNode, *BiThrTree;
//具体线索二叉树的函数实现!
void InThreading(BiThrTree B,BiThrTree *pre) {
if(!B) return;
InThreading(B->lchild,pre);
//--------------------中间为修改空指针代码---------------------
if(!B->lchild){ //没有左孩子
B->LTag = Thread; //修改标志域为前驱线索
B->lchild = *pre; //左孩子指向前驱结点
}
if(!(*pre)->rchild){ //没有右孩子
(*pre)->RTag = Thread; //修改标志域为后继线索
(*pre)->rchild = B; //前驱右孩子指向当前结点
}
*pre = B; //保持pre指向p的前驱
//---------------------------------------------------------
InThreading(B->rchild,pre);
}
增设头结点
线索化后的二叉树,就如同操作一个双向链表。于是我们想到为二叉树增设一个头结点,这样就和双向链表一样,即能够从第一个结点正向开始遍历,也可以从最后一个结点逆向遍历。
在线索二叉链表上添加一个head结点,并令其lchild域的指针指向二叉树的根结点(A),其rchild域的指针指向中序遍历访问的最后一个结点(G)。同样地,二叉树中序序列的第一个结点中,lchild域指针指向头结点,中序序列的最后一个结点rchild域指针也指向头结点。
于是从头结点开始,我们既可以从第一个结点顺后继结点遍历,也可以从最后一个结点起顺前驱遍历。就和双链表一样。
增设头结点并线索化的代码实现
//为线索二叉树添加头结点,使之可以双向操作
Status InOrderThreading(BiThrTree *Thrt,BiThrTree T){
if(!(*Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
exit(OVERFLOW); //开辟结点
(*Thrt)->LTag = Link;
(*Thrt)->RTag = Thread; //设置标志域
(*Thrt)->rchild = (*Thrt); //右结点指向本身
if(!T) {
(*Thrt)->lchild = (*Thrt);
return OK; //若根结点不存在,则该二叉树为空,让该头结点指向自身.
}
BiThrTree pre; //设置前驱结点
//令头结点的左指针指向根结点
pre = (*Thrt);
(*Thrt)->lchild = T;
//开始递归输入线索化
InThreading(T,&pre);
//此时结束了最后一个结点的线索化了,下面的代码把头结点的后继指向了最后一个结点.
//并把最后一个结点的后继也指向头结点,此时树成为了一个类似双向链表的循环.
pre->rchild = *Thrt;
pre->RTag = Thread;
(*Thrt)->rchild = pre;
return OK;
}
中序遍历已经线索化的二叉树
代码实现
Status InOrderTraverse_Thr( BiThrTree Thrt, Status (*Visit)(TElemType e)){
BiThrTree p;
p = Thrt->lchild;
while(p != Thrt){
while(p->LTag == Link)
p = p->lchild; //先走到最左端,开始
if(!(*Visit)(p->data))
return ERROR;
while(p->RTag == Thread && p != Thrt){
p = p->rchild;// 如果右指针是个线索,直接向后遍历后继
(*Visit)(p->data);
}
if (p != Thrt)
/* 如果不加区分就走向右子树,很有可能出现死循环,因为p刚刚停到Thrt
还没进行下一次循环判断,就立刻指向Thrt的后继,循环可能不会终止*/
p = p->rchild;
}
return OK;
}