线索化二叉树
#include <iostream>
using namespace std;
struct ThreadNode{
char data;
ThreadNode *lchild,*rchild;
int ltag=0,rtag=0; //需要初始化为0,不然会出现乱码现象而不是默认为0
};
ThreadNode *pre=NULL;
ThreadNode* creatThreadNode(char a[],char b[],int n){//先序和中序构造二叉树
ThreadNode *p=new ThreadNode; //根 左 右
p->data=a[0]; //左 根 右
int i=0;
/*for(;;)
{
if(a[n]==NULL) //指针才能判断这个为NULL
break;
else
n++;
}*/
for(;;) //计算左子树的个数
{
if(a[0]==b[i])
break;
else
i++;
}
if(i!=0){ //如果有左子树递归
char a1[i],b1[i];
for(int j=0;j<i;j++)
{
a1[j]=a[j+1];
b1[j]=b[j];
}
p->lchild=creatThreadNode(a1,b1,i);
}
else //没有左子树为NULL
p->lchild=NULL;
if(n!=i+1){
char a2[n-i-1],b2[n-i-1];
for(int j=0;j<n-i-1;j++)
{
a2[j]=a[j+i+1];
b2[j]=b[j+i+1];
}
p->rchild=creatThreadNode(a2,b2,n-i-1);
}
else
p->rchild=NULL;
return p;
}
//利用visit的用处是:如果用先序线索化二叉树的话好加判断if(T->ltag==0)//T->lchild 不是前驱线索
void visit(ThreadNode *q) //每次循环设置 首为空 结点前驱的后继和结点的前驱 尾为空
{
if(q->lchild==NULL){ //首为空 + 结点的前驱
q->lchild=pre;
q->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL) //pre!=NULL是为了排除pre初始为NULL的情况
{ //尾为空 + 结点前驱的后继
pre->rchild=q;
pre->rtag=1;
}
pre=q;
}
void InThread(ThreadNode *T)
{
if(T==NULL)
return;
InThread(T->lchild);
visit(T);
/*if(T->lchild==NULL){ //首为空 + 结点的前驱
T->lchild=pre;
T->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL) //pre!=NULL是为了排除pre初始为NULL的情况
{ //尾为空 + 结点前驱的后继
pre->rchild=T;
pre->rtag=1;
}
pre=T;*/
InThread(T->rchild);
}
//CreateInThread的用处是:让最后一个右子树的右tag=1
void CreateInThread(ThreadNode *T) //中序线索化
{
if(T!=NULL) //传递root
{
InThread(T);
}
if(pre->rchild==NULL) //让最后一个右子树的右tag=1
{
pre->rtag=1;
}
}
//先序和后序线索化 和中序一样但是加点条件进入左子树用ltag变量,不然会无限循环
//中序线索化 左 根 右 先序线索化 根 (条件:T->ltag==0)左 右 后序线索化 左 右 根 (不用条件)
ThreadNode* GetNext(ThreadNode *p) //求后继结点
{
if(p->rtag==1) //如果右tag=1它的右孩子就是它的后继
return p->rchild;
p=p->rchild; //否则就是它的右子树的最左下方的结点
while(p->ltag==0)
p=p->lchild;
return p;
}
ThreadNode* GetPrev(ThreadNode *p) //求前驱结点
{
if(p->ltag==1) //同上
return p->lchild;
p=p->lchild;
while(p->rtag==0)
p=p->rchild;
return p;
}
void InOrder(ThreadNode *p) //利用线索二叉树进行中序遍历
{
while(p->ltag==0)
{
p=p->lchild;
}
while(p!=NULL)
{
cout<<p->data<<" ";
p=GetNext(p);
}
}
ThreadNode* GetParent(ThreadNode *p) //寻找父结点
{
if(p==NULL)
return NULL;
ThreadNode * parent;
parent=p;
while(parent->rtag==0) //1.如果p是父结点的左子树,寻找父结点方法:p的最右子树的后继结点
{
parent=parent->rchild; //找到p的最右下方的结点
}
parent=parent->rchild; //p的最右下方的结点的后继结点
if(parent->lchild==p) //判断假设是否成立
return parent;
while(parent->ltag==0) //2.如果p是父结点的右子树,寻找父结点方法:p的最左子树的前驱结点
{
parent=parent->lchild; //找到p的最左下方的结点
}
parent=parent->lchild; //p的最左下方的结点的前驱结点
if(parent->rchild==p)
return parent;
}
int main(){
ThreadNode *root;
char a[9]={'A','B','H','F','D','E','C','K','G'},b[9]={'H','B','D','F','A','E','K','C','G'};//p120 先+中
root=creatThreadNode(a,b,9);
//线索化二叉树
CreateInThread(root);
// 获得前驱和后继结点
/*cout<<GetNext(root)->data<<endl;
cout<<GetPrev(root)->data<<endl;*/
//利用线索遍历二叉树 中序
InOrder(root);
cout<<endl;
//寻找为什么不给ltag和rtag赋初值就会少一个K输出,原因:C的ltag出现乱码
/*cout<<"E的rtag:"<<root->rchild->rtag<<endl;
cout<<"E的后驱结点数据:"<<GetNext(root->rchild)->data<<endl;
cout<<"C的ltag:"<<root->rchild->rchild->ltag<<endl;*/
//寻找父结点
cout<<GetParent(root->lchild->lchild)->data<<endl;
}