二叉树的线索化:对于N个节点的二叉树,在二叉存储链表中有N+1个空链域,利用这些空链域存放某种遍历次序下的指向该节点的前驱和后继的指针,这些指针成为线索,被线索的二叉树成为线索二叉树。这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
中序线索二叉树:指在中序遍历的同时,对二叉树进行线索化,只需要在原先的中序遍历中添加相应的线索话语句即可,设置两个指针,P和Pre,P指向当前访问的节点,Pre指向上一个访问的节点,修改指针:如果P->LchNULL,则P->Lch=Pre,P->Ltag=1;如果Pre->RchNULL,则Pre->Rch=P,Pre->Rtag=1。随着P和Pre的不断更新,即可完成线索化过程
void InOrder(node *now)
{
if(now!=NULL)
{
InOrder(now->lch);
if(now->lch==NULL)
{
now->lch=pre;
now->Ltag=1;
}
if(pre!=NULL&&pre->rch==NULL)
{
pre->rch=now;
pre->Rtag=1;
}
pre=now;
InOrder(now->rch);
}
return ;
}
如果一个节点的左孩子为空,我们让这个lch指针指向指向该节点的前驱,如果该节点的右孩子为空,则将rch指针指向该节点的后继,此时,我们需要增加两个标记,表明指针是指向孩子的还是指向前驱或者后继。
Ltag:为0,表示Lch指向左孩子;为1,表示Lch指向前驱节点
Rtag:为0,表示Rch指向左孩子;为1,表示Rch指向后继节点
线索化之后,该如何遍历呢?以中序遍历为例,遍历分为两个步骤:
1.访问遍历的第一个节点,位于树中最“左下端的节点”,从根节点沿着左孩子指针,找到没有左孩子的节点即可
node* First_node(node *now)
{
node *first=now;
if(first==NULL)
return first;
while(first->Ltag==0)
first=first->lch;
return first;
}
2.寻找并访问当前节点的后继节点,重复执行步骤2,直到所有的节点都被访问到。如何寻找后继节点呢?如果此时节点的Rtag==1时,Rch指针指向的就是后继节点,否则,根据中序遍历的思想,遍历完该节点后,接下来应该访问其右子树,话句话说,后继节点一定是右子树中第一个被访问的节点,这不正是First_node函数的功能吗?
node* Next_node(node *now)
{
node *next=NULL;
if(now->Rtag==1)
next=now->rch;
else
next=First_node(now->rch);
return next;
}
完整代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1.0)
#define e exp(1.0)
typedef long long ll;
struct node
{
char data;
bool Ltag;
bool Rtag;
node *lch;
node *rch;
};
node *pre=NULL;
void Create(node *&root)
{
char c;
c=getchar();
if(c=='\n')
return ;
if(c=='#')
root=NULL;
else
{
root=new node;
root->data=c;
root->Ltag=0;
root->Rtag=0;
Create(root->lch);
Create(root->rch);
}
return ;
}
void InOrder(node *now)
{
if(now!=NULL)
{
InOrder(now->lch);
if(now->lch==NULL)
{
now->lch=pre;
now->Ltag=1;
}
if(pre!=NULL&&pre->rch==NULL)
{
pre->rch=now;
pre->Rtag=1;
}
pre=now;
InOrder(now->rch);
}
return ;
}
node* First_node(node *now)
{
node *first=now;
if(first==NULL)
return first;
while(first->Ltag==0)
first=first->lch;
return first;
}
node* Next_node(node *now)
{
node *next=NULL;
if(now->Rtag==1)
next=now->rch;
else
next=First_node(now->rch);
return next;
}
void InOrder_chain(node *root)
{
node *now=First_node(root);
while(now!=NULL)
{
printf("%c",now->data);
now=Next_node(now);
}
putchar('\n');
return ;
}
void Delete(node *now)
{
if(now!=NULL)
{
Delete(now->lch);
Delete(now->rch);
delete now;
}
return ;
}
int main()
{
node *root=NULL;
Create(root);
InOrder(root);
InOrder_chain(root);
Delete(root);
return 0;
}
后续再补充线索二叉树的后续遍历算法吧……