【題目描述】
寫出在中序線索二叉樹裏查找指定結點在後序的前驅結點的算法。
【分析】
這道題目的前提是我們已經有了中序線索二叉樹。在二叉樹後序序列中,對於結點p,其前驅依次有可能是:①p的右孩子②沒有右孩子,那就可能是左孩子③沒有孩子,那就可能是其父結點的左孩子④否則,可能是其爺爺結點的左孩子,以此類推。
對於①②,特判即可。對於③,中序線索二叉樹中,p無左孩子,則其左指針域指向其父,故可向上訪問,直到有一個祖先有左孩子,則這個左孩子一定是後序遍歷p的前驅。
注意中序序列第一個結點無前驅,其在後序中亦無前驅,需要特判。
【樣例】
測試樣例先序建樹:ABD##E##C#FG##H##
【測試完整代碼】
#include<stdio.h>
#include<stdlib.h>
struct node{
char data;
int ltag,rtag;
struct node *lchild,*rchild;
};
struct node *node_arr[100]; //保存下所有結點的指針
int node_arr_top=0;
struct node* createTree() //先序建樹,樣例ABD##E##C#FG##H##
{
char ch=getchar();
if(ch!='#'){
struct node* p=(struct node*)malloc(sizeof(struct node));
node_arr[++node_arr_top]=p; //保存指針
p->data = ch;
p->lchild = createTree();
p->rchild = createTree();
p->ltag = p->rtag = 0;
return p;
}
return NULL;
}
//二叉樹中序線索化
void convertToXiansuo(struct node *root, struct node **last)
{
if(root)
{
convertToXiansuo(root->lchild,last); //線索化左子樹
if(root->lchild==NULL){ //讓左指針指向前驅
root->lchild=*last;
root->ltag=1;
}
if((*last)!=NULL && (*last)->rchild==NULL){ //root作爲後繼,被last右指針所指
(*last)->rtag=1;
(*last)->rchild=root;
}
*last = root;
convertToXiansuo(root->rchild,last); //線索化右子樹
}
}
void xianSuoHua(struct node *root) //中序線索化
{
struct node *last=NULL; //最先訪問的結點的前驅就是NULL
convertToXiansuo(root,&last);
last->rtag=1; //最後訪問的結點沒有後繼,但也要標記右指針
}
struct node* preOfBackOrder(struct node* p) //求後序序列中p的前驅
{
if(p==NULL)return NULL; //p空,不存在前驅
if(p->rtag==0)return p->rchild; //有右孩子
if(p->ltag==0)return p->lchild; //無右,但有左孩子
//剩下的情況:所求必爲p的最近的<祖先的左孩子>
while(p&&p->ltag==1) //p無左孩子,訪問其父(即中序前驅)
p=p->lchild;
if(p)return p->lchild; //找到了
return NULL; //不存在
}
int main()
{
int i;
printf("請輸入先序序列以建樹: "); //樣例:ABD##E##C#FG##H##
struct node* root=createTree();
xianSuoHua(root);
for(i=1;i<=node_arr_top;i++) //輸出每個結點的信息
{
struct node* p=node_arr[i];
//*printf("%d %9d %c %9d %d\n",p->ltag,p->lchild,p->data,p->rchild,p->rtag);
struct node* r=preOfBackOrder(p);
printf("後序序列中%c的前驅是%c\n",p->data,r?r->data:'-');
}
}