线索二叉树:
n个结点的二叉树有n+1个空指针,利用这些空指针来存放指向前驱或后继的指针
遍历线索化
例如:中序线索化,在中序遍历访问结点的时候进行线索化
设置一个全局变量pre指向当前访问结点的前一个
具体代码如下:
void visit(ThreadNode *q){
if(q->lchild==NULL){
q->lchild=pre;
q->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL){
pre->rchild=q;
pre->rtag=1;
}
pre=q;
}
遍历到最后一个结点的时候pre=q,需要再处理一下pre的后继
if(pre->rchild==NULL)
pre->rtag=1;
完整代码:
ThreadNode *pre=NULL;
//中序线索化二叉树
void CreatInThread(ThreadTree T){
pre=NULL;
if(T!=NULL){
InThread(T);
if(pre->rchild==NULL)
pre->rtag=1;//处理遍历的最后一个结点
}
}
//线索二叉树结点
typedef struct ThreadTree{
ElemType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag;//左右标志线索
}ThreadNode,*ThreadTree;
//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree T){
if(T!=NULL){
InThread(T->lchild);
visit(T);//在访问时线索化
InThread(T->rchild);
}
}
void visit(ThreadNode *q){
if(q->lchild==NULL){
q->lchild=pre;
q->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL){
pre->rchild=q;
pre->rtag=1;
}
pre=q;
}
先序线索化思路一样,但可能会出现“原地打转”的现象
需要通过ltag辨别是左孩子还是前驱
void PreThread(ThreadTree T){
if(T!=NULL){
visit(T);//在访问时线索化
if(T->ltag==0)
PreThread(T->lchild);
preThread(T->rchild);
}
}
后序线索化思路相同
查找线索二叉树的前驱和后继结点
中序线索二叉树:
后继:
1.该结点已经被线索化,则后继结点就是next
2.未被线索化,则需要找到该结点的右分支的最左下角的结点(左根右)
void *FirstNode(ThreadTree *p){
while(p->ltag==0)//存在左孩子则继续往下寻找
p=p->lchild;
return p;
}
ThreadNode *NextNode(ThreadNode *p){
if(p->rtag==0) return FirstNode(p->rchild);//右分支最左下的结点
else return p->rchild;
}
利用线索二叉树实现中序遍历(利用线索实现中序遍历的非递归算法)
void InOrder(ThreadNode *T){
while(ThreadNode *p=FirstNode(T);p!=NULL;p=NextNode(p))
visit(p);
}
中序线索二叉树的前驱结点:
1.已线索化的前驱
2.未被线索化,左分支的最右下的结点
ThreadNode *LastNode(ThreadNode *p){
while(rtag==0) p=p->rchild;
return p;
}
ThreadNode *PreNode(ThreadNode *p){
if(p->ltag==0) return LastNode(p->lchild);
else return p->lchild;
}
利用中序前驱逆向中序遍历
void RevInoder(ThreadNode *T){
for(ThreadNode *p=LastNode(T);p!=NULL;p=PreNode(p))
visit(p);
}
先序线索二叉树
先序:根 左 右
后继:1.rtag==1
2.rtag=0,存在右分支,需要考虑是否存在左孩子
2.1左孩子存在,即后继是左孩子
2.2左孩子不存在,则后继是右孩子
ThreadNode *NextNode(ThreadNode *p){
if(p->rtag==0){
if(p->lchild!=NULL) return p->lchild;
else return p->rchild;
}
else return p->rchild;
}
前驱
1.ltag=1
2.ltag=0 无法找到
解决:增加指向父结点的指针,改造成三叉链表
能找到p的父结点,则存在以下情况:
1.p是左孩子 p->pre=父结点
2.p是右孩子
2.1左兄弟为空 p->pre=父结点
2.2左兄弟非空,p->pre=左兄弟先序遍历最后一个被访问的结点(不一定是最右的)
3.p是根节点,无前驱
后序线索二叉树思路相同