//二叉树中序线索化,中序遍历线索化二叉树
//线索化意为填充结点中的空指针,若原为左子树则放入前驱结点,右子树则放入后继结点
//相比二叉链表表示法,增加左右标签,1为线索(实际访问),0为子树(图上看到的)
#include<stdio.h>
#include<stdlib.h>
typedef struct BinaryTree
{
int data;
struct BinaryTree* lchild;
struct BinaryTree* rchild;
int LTag;//左线索
int RTag;//右线索
}Tree;
void CreateTree(Tree** t)
{
int ch;
printf("输入数字\n");
scanf("%d", &ch);
if (!ch)
*t = NULL;
else
{
*t = (Tree*)malloc(sizeof(Tree));
(*t)->data = ch;
(*t)->LTag = 0;
(*t)->RTag = 0;
CreateTree(&(*t)->lchild);
CreateTree(&(*t)->rchild);
}
}
//中序线索化
//主体思路:先创建一个头节点Thrt,左指针指向根节点,右侧存放最后一个遍历到的结点
//中序遍历到的首节点左指针与末节点右指针都指向Thrt,方便从末节点反向遍历
//线索化的过程中,用pre保存前驱结点,由于调用的函数要用到Thrt和pre,故设全局变量
//由于只有遍历时才能得到前驱结点,所以线索化时需要递归,故将线索化的准备工作(如
//创建头结点并对其赋值及完整最后一个遍历到的结点)与需递归的函数分开
//递归函数中,若有需要(原先为空指针,需赋线索)
//则在执行结点时对其前驱结点及其前驱结点的后驱(即当前结点)赋值
//为使赋值成功,此处函数调用中传参均为指向节点指针的地址(Tree**)
//故调用完递归函数后还要对最后一个结点的后继结点赋值
Tree* Thrt = NULL;
Tree* pre = NULL;
void InThreading(Tree** p);
void InorderThreading(Tree** t)
{
Thrt = (Tree*)malloc(sizeof(Tree));
if (!Thrt)
{
printf("建立头结点失败\n");
return;
}
Thrt->data = 0;
Thrt->LTag = 0;
Thrt->RTag = 1;
Thrt->lchild = Thrt;
if (!*t)
Thrt->rchild = Thrt;
else
{
Thrt->lchild = *t;
pre = Thrt;
InThreading(t);
pre->RTag = 1;
pre->rchild = Thrt;
Thrt->rchild = pre;
}
}
//调用的递归函数
void InThreading(Tree** p)
{
if (*p)
{
InThreading(&(*p)->lchild);
if (!(*p)->lchild)
{
(*p)->LTag = 1;
(*p)->lchild = pre;
}
if(!pre->rchild)
{
pre->RTag = 1;
pre->rchild = *p;
}
pre = *p;
InThreading(&(*p)->rchild);
}
}
//中序遍历线索二叉树
//先向左遍历,直到左标签为1(为1即原本此处指针为空,无子树)
//执行该节点,若右侧是后继结点且非头结点,则直接遍历右侧直到其右侧不是后继结点
//若是普通的子树,则回到第一步,对该右侧结点向左遍历
void Print(Tree* p)
{
printf("%d ", p->data);
}
void InorderThreadingTraverse(Tree* p)
{
while (p != Thrt)
{
while (!p->LTag)
p = p->lchild;
Print(p);
while (p->RTag && p->rchild != Thrt)
{
p = p->rchild;
Print(p);
}
p = p->rchild;
}
}
int main()
{
Tree* t = NULL;
CreateTree(&t);
InorderThreading(&t);
InorderThreadingTraverse(t);
}
线索二叉树,中序遍历线索二叉树
最新推荐文章于 2024-08-05 00:04:51 发布