先中后序线索化二叉树具体实现

#define END '#'
typedef char ElemType;
typedef enum{LINK,THREAD}pointerTag; //注意两者的顺序,如果换过来就很麻烦,最好enum{THREAD=1,LINK=0};
typedef struct BiThrNode
{
ElemType data;
pointerTag Ltag,Rtag;
BiThrNode *leftchild,*rightchild;
};

BiThrNode *_BuyNode()
{
BiThrNode *s=(BiThrNode *)malloc(sizeof(BiThrNode));
assert(s != NULL);
memset(s,0,sizeof(BiThrNode)); //变相的将Ltag和Rtag初始化为LINK
return s;
}
BiThrNode *CreateTree(char *&str)
{
BiThrNode *s=NULL;
if(str != NULL)
{
if(*str != END)
{
s=_BuyNode();
s->data=*str;
s->Ltag=LINK;
s->Rtag=LINK;
s->leftchild=CreateTree(++str);
s->rightchild=CreateTree(++str);
}
}
return s;
}
////////////////////////////////////////////////////////////////中序
void ThreadInTree(BiThrNode *p,BiThrNode*&ptr)
{
if(p != NULL)
{
ThreadInTree(p->leftchild,ptr);
if(p->leftchild == NULL)
{
p->leftchild=ptr;
p->Ltag=THREAD;
}
if(ptr != NULL && ptr->rightchild == NULL)
{
ptr->rightchild=p;
ptr->Rtag=THREAD;
}
ptr=p;
ThreadInTree(p->rightchild,ptr);
}
}
void CreateInThrTree(BiThrNode *p)
{
BiThrNode *ptr=NULL;
ThreadInTree(p,ptr);
ptr->Rtag=THREAD;
ptr->rightchild=NULL;
ptr=NULL;
}
//////////////////////////////////////////////////////////////////////
/*
BiThrNode *ptr=NULL; //设全局变量或引用
void CreateInThrTree(BiThrNode *p)
{
if(p != NULL)
{
CreateInThrTree(p->leftchild);
if(p->leftchild == NULL)
{
p->leftchild=ptr;
p->Ltag=THREAD;
}
if(ptr != NULL && ptr->rightchild == NULL)
{
ptr->rightchild=p;
ptr->Rtag=THREAD;
}
ptr=p;
CreateInThrTree(p->rightchild);
}
}
*/
//////////////////////////////////////////////////////////////////////

BiThrNode *First(BiThrNode *p)
{
while(p != NULL && p->Ltag != THREAD)
{
p=p->leftchild;
}
return p;
}
BiThrNode *NextIn(BiThrNode *p)
{
if(p != NULL)
{
if(p->Rtag == THREAD)
{
return p->rightchild;
}
else if(p->Rtag == LINK)
{
return First(p->rightchild);
}
}
return NULL;
}
void ThreadInOrder(BiThrNode *p) //线索二叉树非递归中序遍历
{
for(BiThrNode *p1=First(p);p1!=NULL;p1=NextIn(p1))
{
cout<<p1->data<<" ";
}
cout<<endl;
}
////////////////////////////////////////////////////////////////先序
void ThreadPreTree(BiThrNode *p,BiThrNode *&ptr)
{
if(p != NULL)
{
if(p->leftchild == NULL)
{
p->leftchild=ptr;
p->Ltag=THREAD;
}
if(ptr != NULL && ptr->rightchild == NULL)
{
ptr->rightchild=p;
ptr->Rtag=THREAD;
}
ptr=p;
if(p->Ltag != THREAD)
{
ThreadPreTree(p->leftchild,ptr);
}
ThreadPreTree(p->rightchild,ptr);
}
}
void CreatePreThrTree(BiThrNode *p)
{
BiThrNode *ptr=NULL;
ThreadPreTree(p,ptr);
ptr->rightchild=NULL;
ptr->Rtag=THREAD;
ptr=NULL;
}

BiThrNode *NextPre(BiThrNode *p)
{
if(p == NULL) return NULL;
if(p->Ltag == THREAD)
{
return p->rightchild;
}
else if(p->Ltag == LINK)
{
return p->leftchild;
}
}
void ThreadPreOrder(BiThrNode *p)
{
for(BiThrNode *p1=p;p1 != NULL;p1=NextPre(p1))
{
cout<<p1->data<<" ";
}
cout<<endl;
}
/////////////////////////////////////////////////////////////////后序
void ThreadPastTree(BiThrNode *p,BiThrNode *&ptr)
{
if(p != NULL)
{
ThreadPastTree(p->leftchild,ptr);
ThreadPastTree(p->rightchild,ptr);

if(p->leftchild == NULL)
{
p->leftchild = ptr;
p->Ltag = THREAD;
}
if(ptr != NULL && ptr->rightchild == NULL)
{
ptr->rightchild = p;
ptr->Rtag = THREAD;
}
ptr=p;
}
}
void CreatePastThrTree(BiThrNode *p)
{
BiThrNode *ptr=NULL;
ThreadPastTree(p,ptr);
}
BiThrNode *FindParent(BiThrNode *ptr,BiThrNode *child)
{
if(child == NULL || child == ptr) return NULL; //注意退出条件,缺少child==ptr这一句会出现死循环,最后导致栈溢出
if(ptr == NULL || ptr->leftchild == child || ptr->rightchild == child)
{
return ptr;
}
BiThrNode *s=FindParent(ptr->leftchild,child);
if(s == NULL)
{
s=FindParent(ptr->rightchild,child);
}
return s;
}
BiThrNode *NextPast(BiThrNode *p,BiThrNode *ptr)
{
if(ptr == NULL) return NULL;
if(ptr->Rtag == THREAD)
{
return ptr->rightchild;
}
else
{
BiThrNode *s=FindParent(p,ptr);
if(s == NULL) return NULL;
if(s->leftchild == ptr)
{
s=s->rightchild;
while(s != NULL && s->Ltag == LINK)
{
s=s->leftchild;
}
while(s != NULL && s->Rtag == LINK)
{
s=s->rightchild;
}
}
return s;
}
}
void ThreadPastOrder(BiThrNode *p)//最后栈溢出才打印出来
{
for(BiThrNode *ptr=First(p);ptr != NULL;ptr=NextPast(p,ptr))
{
cout<<ptr->data<<" ";
}
cout<<endl;//栈溢出没有执行这一行就直接打印出来了,最后栈溢出才退出所以一直没执行这一行
}
int main()
{
char *str="ABC##DE##F##G#H##";
BiThrNode *root=NULL;
root=CreateTree(str);

CreatePreThrTree(root);
ThreadPreOrder(root);

root=CreateTree(str); //反复的去创建root
CreateInThrTree(root);
ThreadInOrder(root);

CreatePastThrTree(root);
ThreadPastOrder(root);

return 0;
}

注意:线索化二叉树不可以反复创建,比如说,先序已经创建好了,如果再用这一颗先序线索化二叉树来创建中序的话就会导致栈溢出,因为在创建先序时它的左右子树无论有没有都不会为NULL,所以如果此时再拿它来创建中序线索化二叉树那就是找死,会出现死递归,最后栈溢出

然后很快想到不如拿str重新创建一个root,可是去忽略了str是引用传入,已经移到最后,所以创建不成功(拿c++方式创建没有引用,可以反复创建,即初始化);

先中后序在创建时较简单,有着异曲同工之妙,值得注意的是先序创建时,由于先对左子树进行了指向的改变(即没有左子树的被线化),这里需注意不要出现死递归,在递归调动时加上if(p->Ltag != THREAD)即可(具体情况看代码),创建好后就是遍历了,在遍历上后序会稍加复杂,它涉及到找双亲节点的基础上(当然,可能会有更好的方法),这里我曾出现一个小细节,就是在调用ThreadPastOrder(root)时cout<<endl没有被执行,为什么?经调试方知在查找双亲节点的时掉了条件ptr==child就退出的情况,从而导致出现死递归进而栈溢出,直到最后栈满才打印出结果,也就没有执行到这一句了,可见,代码结果上的每一个小小的偏差都是有原因的,要追根求本,探索每一个问题背后的根源!

 

posted @ 2015-04-26 11:36  mumuxi123  阅读(1836)  评论(0)    收藏  举报