
为什么要有一个线索二叉树?
为了解决无法在某个遍历序列中直接找到该节点的前任节点和后继节点的问题
但是同时,在二元列表中查找左,右子代的问题很困难,也就是说,在构建线索二叉树之后,列表的原始遍历方法会出现问题.
-ltag为0表示lchild指向节点的左子节点,而1表示lchild指向节点的前身

-rtag为0,表示rchild指向节点的右子节点. 当它为1时,rchild指向该节点的后继
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
/*
线索存储标志位
Link(0):表示指向左右孩子的指针
Thread(1):表示指向前驱后继的线索
*/
typedef enum {Link, Thread} PointerTag;
typedef struct BiThrNode{
ElemType data;
struct BiThrNode *lchild, *rchild;
PointerTag ltag;
PointerTag rtag;
}BiThrNode, *BiThrTree;
//全局变量,始终指向刚刚访问过的节点
BiThrTree pre;
//创建一棵二叉树,约定用户遵照前序遍历方式输入数据
void createBiThrTree(BiThrTree *T){
char c;
scanf("%c", &c);
if('#' == c){
*T = NULL;
}else{
*T = (BiThrNode*)malloc(sizeof(BiThrNode));
(*T)->data = c;
(*T)->ltag = Link;
(*T)->rtag = Link;
createBiThrTree(&(*T)->lchild);
createBiThrTree(&(*T)->rchild);
}
}
//中序遍历线索化
void inThreading(BiThrTree T){
if(T){
inThreading(T->lchild);//递归左孩子线索华
//节点处理
if(!T->lchild){//处理前驱,什么时候能知道前驱,就是当前节点的时候,
//已经知道前一个是pre了,所以直接tag=thread,lchild=pre
T->ltag = Thread;
T->lchild = pre;
}
if(pre!=NULL && !pre->rchild){//处理后继,什么时候处理后继,只有访问到下一个的时候,
//才能知道下一个是谁,因为当访问下一个的时候,下一个是T,让pre的rchild指向T就好
pre->rtag = Thread;
pre->rchild = T;
}
pre = T;
inThreading(T->rchild);//递归右孩子线索华
}
}
//中序遍历线索二叉树---非递归
void InOrderThreading(BiThrTree T){
BiThrTree p = T;
while(p != NULL){
//当ltag == Thread时,循环到中序序列第一个节点
while(p->ltag == Link){
p = p->lchild;
}
printf("%c ", p->data);
while(p->rtag == Thread && p->rchild != NULL){
p = p ->rchild;
printf("%c ", p->data);
}
p = p->rchild;
}
}
int main(){
BiThrTree T = NULL;
createBiThrTree(&T);
inThreading(T);
pre->rtag = Thread;
InOrderThreading(T);
return 0;
}
①预先输入以构建二叉树
-输入c

-递归退出: 如果c为#,则该节点为空,* T = NULL;
---如果不等于#,则表示该节点不为空
--------由于顺序遍历,首先是根,然后是左,然后是右,因此递归的想法是为当前节点分配空间,而左和右标记是链接
--------然后递归左孩子
--------递归的右子对象

②以中间顺序构造线索二叉树(参考中间顺序遍历,如果T为空,则递归退出,如果不为空,则递归遍历当前节点的左子树,然后打印出当前节点,递归遍历在当前节点的右侧子树中线索化二叉树,“线程”只是将打印更改为“线程”操作
---如果T为空,则递归导出
---如果不为空,则开始操作
------领先于当前T节点的左子树
------线索是找到子节点为空的节点的前任和后任,因此请考虑何时获得前任以及何时获得后任

-----------处理前任节点: 对于当前节点,何时可以获取前任节点,就可以访问当前节点,因此需要记录前一个节点,但前提是T的左子树是空的;
-----------处理后继者: 对于前节点,何时处理后继者,在访问下一个节点时,我们能否知道当前节点的后继者是什么,因此对于下一个节点节点T,pre的后继者是T,因此pre必须为空,前提是pre!= NULL且pre的右子树为空
③序列遍历线索二叉树---非递归(左中右)
-获取根节点并将其赋予移动指针p
---如果p不为空,请循环,因为在提示之后,它等同于已连接树,知道找到了最后一个元素,则其地址为空
------转到最左边的节点线索化二叉树,如果ltag == link表示确实有一个孩子,则p = p-> lchild
------输出p节点的元素
------下一个后继,如果rtag是一个线索并且右子树不为空(考虑到右子树为空,并继续导致内存溢出),则p = p-> rchild;输出当前的p节点(如果还可以,因为有一个继任者,也就是说,继任者必须是某个父亲,而父亲只有两种情况,是否有合适的孩子,但无论是否有)循环条件,它只会执行一次)
------ p = p-> rchild'用于处理具有正确子节点的节点
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-258346-1.html
夸张了点吧
为何这位这样说
小米壮哉@小米公司@红米手机