#include<stdio.h>
#include<stdlib.h>
//创建枚举类型
typedef enum{link,thread} PointNag;//link(0)表示是指向的是左右孩子
//thread(1)表示的是前驱结点和后继节点
typedef char Elemtype;
//创建二叉节点
typedef struct BiThrnode
{
Elemtype data;
struct BiThrnode* lchild, * rchild;
PointNag ltag;
PointNag rtag;//枚举类型,表示0和1
}BiThrnode,BiThrTree;
//创建树(通过前序遍历的方式)
void createBiThrnode(BiThrTree T)
{
char c;
scanf_s("%c", &c);
if (c == ’ ')
{
*T = NULL;
}
else
{
T = (BiThrnode)malloc(sizeof(BiThrnode));
(*T)->data = c;
(*T)->ltag = link;
(*T)->rtag = link;//在创建的时候默认为左孩子和有孩子
//在中序遍历的时候如果没有左右孩子,在修改该节点的指针
//如果该节点有左右孩子,就可以不管他
//创建左子树
createBiThrnode(&(*T)->lchild);
//创建右子树
createBiThrnode(&(*T)->rchild);
}
}
BiThrTree pre;//头指针
//中序遍历树 递归线索化
void inThreading(BiThrTree* T)
{
if (!T)//该树不是一个空树
{
inThreading(&(*T)->lchild);//一直走到最左边的节点
//节点处理
if (!(*T)->lchild)//如果T的左子树为空,那么就需要将
//该左子树的左孩子指向该节点的前驱结点
//由于已经遍历完前驱结点,那么就找不到这个前驱结点
//所以我们需要用一个全局变量来保存它
//当过了这个节点之后,全局变量的这个前驱结点就是这个刚刚经过的结点
{
(*T)->ltag = thread;//将该结点首先置为线索化的结点
(*T)->lchild = pre;
}
if (!pre->rchild)//不能用T来遍历它的右节点,因为T的上一层的右节点还没有遍历完成
{//如果右节点为空,那么需要将pre的右节点指向为pre的后继节点,
//而pre的后继结点就为T(从上到下开始想)
pre->rtag = thread;
pre->rchild = *T;
}
//这一小子树遍历完成之后又到该子树的上一级
pre = *T;
inThreading(&(*T)->rchild);
}
}
void inorderThreading(BiThrTree *p,BiThrTree T)//第一个参数为头指针
{//T为一棵树
p = (BiThrnode)malloc(sizeof(BiThrnode));
(*p)->ltag = link;//头指针的左孩子指向一个结点
(*p)->rtag = thread;//头指针的右孩子指向一个线索
//为什么要将头指针的右孩子指向为一个线索呢?因为方便首位相连接
//最后一个结点指向头指针,头指针指向最后一个结点 (首尾相接,有点像双向链表)
(*p)->rchild = *p;
if (!T)//该树为一颗空树
{
(*p)->lchild = *p;
}
else
{
(*p)->lchild = T;
pre = *p;//将刚刚创建的头指针的地址赋给全局变量pre
inThreading(&T);
//首尾连接
//pre在递归完成之后已经变成了右边最后一个结点了
pre->rchild = *p;
(p)->rchild = pre;
pre->rtag = thread;
}
}
int main(void)
{
BiThrTree T;
BiThrTree p=NULL;
createBiThrnode(&T);
inorderThreading(p, T);//注意第一个参数传递的是那个全局变量pre哦
system(“pause”);
return 0;
}