#include <stdio.h>
#include <stdlib.h>
#define MaxSize
/*
* 这里是不带头结点的线索二叉树,带头结点的以后再写
* 线索二叉树:
* 把树型逻辑结构变成线性逻辑结构,可以顺序访问二叉树中的元素,用来加速查找前驱和后继
* pay attention to:只是逻辑结构改变了,物理结构不受影响
* 线索二叉树的基本操作:
* 1.找线索二叉树的第一个结点
* 2.找线索二叉树的最后一个结点
* 3.找线索二叉树中某个结点的前驱结点
* 4.找线索二叉树中某个结点的后继结点
* 5.线索二叉树的遍历(中序) 因为线索二叉树逻辑结构是线性的,找到开始结点,然后一直访问右指针即可
* LNR线索二叉树的创建:是递归的,这里仅仅介绍中序递归遍历创建线索二叉树
* 分两个部分函数实现:1.中序线索化二叉树算法 2.中序创建线索化二叉树算法
* LNR线索二叉树的盲点:
* 注意:必须牢记
* 1.一个节点的前驱和后继可能都有两种情况,因为后继或前驱可能是孩子结点或没关系的结点
* 2.因为你把二叉树变成了线性结构,所以才会出现这种情况,正常LNR二叉树后继结点就是右孩子,前驱结点就是左孩子
*/
typedef char ElemType;
//线索二叉树的存储结构
typedef struct node
{
ElemType data; //数据域
struct node *lchild,*rchild; //左右孩子指针
int ltag,rtag; //线索标志位 0指向孩子,1指向前驱或后继
}ThreadNode,*ThreadTree;
// 不带头结点的递归创建线索二叉树
void CreateThreadTree(ThreadTree &tree)
{
char ch;
if ((ch=getchar())=='#')
tree=NULL;
else
{
tree=(ThreadTree)malloc(sizeof(ThreadNode));
tree->data=ch;
CreateThreadTree(tree->lchild);
CreateThreadTree(tree->rchild);
}
}
/*
* pre是一个指向刚刚访问过的结点的指针
* 中序线索化 递归问题,大问题是给所有结点都线索化,小问题有三个左子树先线索化,根节点线索化,右子树线索化
* 设大问题为:f(tree,pre)
* 又因为是中序遍历,所以
* 大问题f(tree,pre)等价于f(b->lchild,pre)+根节点线索化+f(b->rchild,pre)
* 所以递归模型是:
* return NULL; 当tree==NULL时,递归出口
* f(b->lchild,pre);根节点线索化+f(b->rchild,pre) 其他情况时
* 假设,左子树已经线索完了,那么我们只要写线索根节点的代码即可
* 至此,递归模型建立完成
*
* 最后我们发现,这个线索化代码,没有处理pre的有指针,所以,我们要在写一个专门建立线索二叉树的算法(CreateInThread)
* 并且在线索完了之后,处理pre的有孩子指针和rtag标志位
*/
void InThread(ThreadTree &tree,ThreadTree &pre)
{
//pre是一个指向刚刚访问过节点的指针
if (tree!=NULL)
{
InThread(tree->lchild,pre); //线索完左子树
//处理根节点 有三种情况
if (tree->lchild==NULL) //根节点左子树不存在时
{
tree->lchild=pre; //左孩子指针指向前驱结点 pre,其实是指向了空
tree->ltag=1;
}
if (pre!=NULL&&pre->rchild==NULL)
{
pre->rchild=tree;
pre->rtag=1;
}
pre=tree;
InThread(tree->rchild,pre);
}
}
//不带头结点的建立中序线索二叉树算法
void CreateInThread(ThreadTree &tree)
{
ThreadTree pre=NULL;
if (tree!=NULL)
{
InThread(tree,pre);
pre->rchild=NULL;
pre->rtag=1;
}
}
//不带头结点的求中序线索二叉树的第一个结点
ThreadTree FirstNode(ThreadTree tree)
{
while (tree->ltag==0) //返回最左下结点
tree=tree->lchild;
return tree; //左子树为空,返回根节点
}
//不带头结点的中序线索二叉树的最后一个节点
ThreadTree LastNode(ThreadTree tree)
{
while (tree->rtag==0) //找到第一个最右下角结点
{
tree=tree->rchild;
}
return tree; //返回最后一个的结点指针
}
//求不带头结点的中序线索二叉树中某个节点的后继结点
ThreadTree NextNode(ThreadTree p)
{
/*思路:因为是LNR访问方式,所以结点p的后继有两种情况
* 1.当p的右子树存在时,p的后继结点是p的右子树上的第一个结点(p的右子树上的最左下结点) p的子孙
* 2.当p的右子树不存在时,p的后继结点是p的后继 p的后继
*/
if (p->rtag==0) //p的后继是p的子孙结点
return FirstNode(p->rchild);
else
return p->rchild; //否则返回p的后继结点
}
//求不带头结点的中序线索二叉树中某个节点的的前驱结点
ThreadTree PriorNode(ThreadTree p)
{
/*
* 思路:p的前驱有两种情况 LNR时
* 1.当p的左子树存在时,p的前驱是左子树上的最后一个结点 p的前驱是p的子孙 ltag=0情况
* 2.当p的左子树不存在时,p的前驱是p的前驱 即ltag=1情况
*/
if (p->ltag==0)
return LastNode(p->lchild);
else
return p->lchild; //直接返回前驱结点
}
//遍历线索二叉树的代码(中序LNR) 一直访问右指针即可
void InOrderThread(ThreadTree &tree)
{
tree=FirstNode(tree);
while (tree) //当tree存在时,一直沿着右指针遍历到最后一个结点
{
printf("%c",tree->data);
tree=NextNode(tree);
}
}
//销毁线索二叉树
void DestoryTree(ThreadTree tree)
{
if (tree)
{
DestoryTree(tree->lchild);
DestoryTree(tree->rchild);
free(tree);
}
}
int main()
{
ThreadTree tree;
CreateThreadTree(tree);
CreateInThread(tree);
printf("中序遍历线索二叉树为:");
InOrderThread(tree);
DestoryTree(tree);
return 0;
}