详解线索二叉树


线索二叉树的存储结构

二叉树的存储结构

typedef struct BiTNode
{
	char data;
	struct BiTNode* lchild,*rchild;
}BiTNode,*BiTree;

结点由存放数据元素的数据域和存放放左右孩子结点地址的指针域组成

线索二叉树的存储结构

typedef struct BiThrNode
{
	char data;
	struct BiThrNode *lchild, *rchild;
	int LTag;
	int RTag;
}BiThrNode,*BiThrTree;

相较于二叉树添加了LTag和RTag标记
当标记值为0时代表该结点有儿子结点,标记值为1时其lchild指针指向上一个结点,rchild指针指向下一个结点。

建立线索二叉树的目的是最大化利用空指针,构建二叉树中许多结点并没有左右儿子结点,因此他们的lchildrchild指针均没有被利用。
我们将没有利用的指针指向该结点的前驱或后继成为线索,对二叉树以某种次序遍历使其变为线索二叉树的过程称作线索化。


一、先序遍历建立二叉链表

目的:以先序遍历的方法建立二叉链表
实现:从键盘输入,检测到“#”即设置指针为空,否则分配内存空间建立新结点,以先序遍历的方法递归建立二叉链表

void PreCreateBiTree(BiThrTree &T)
{
	char ch;
	cin>>ch;
	if (ch=='#')
	{
		T=NULL;
	}
	else
	{
		T=new BiThrNode;
		if(!T) cout<<"error!"<<endl;
		(T)->data=ch;
		PreCreateBiTree((T)->lchild);
		PreCreateBiTree((T)->rchild);
	}
}

通过先序遍历建立二叉树要求我们将没有数据的结点用“#”代替输入,输入的字符串应该是对于拼凑后的二叉树的序列

在这里插入图片描述

“拼凑”后的完全二叉树如图
此二叉树的先序遍历为“AB#D##C##”


二、二叉树的中序线索化

目的:以中序遍历的方法使二叉链表线索化
实现:
①pre是全局变量,始终指向刚刚问过的结点(当前结点的前一个结点)
②从树根开始,先遍历到最深的左孩子结点,如果该结点没有左孩子,将LTag置为1做标记,令其lchild指针指向pre前驱,否则将LTag置为0,其lchild指针仍然指向左孩子结点。
③如果前驱没有右孩子结点,将前驱的RTag置为1做标记,令其rchild指针指向当前结点p,保持pre=p继续遍历,接着遍历右子树。

BiThrTree pre;
void InThreading(BiThrTree p)
{
	if (p)
	{
		InThreading(p->lchild);
		if (!p->lchild)
		{
			p->LTag=1;
			p->lchild=pre;
		}
		else p->LTag=0;
		if (!pre->rchild)
		{
			pre->RTag=1;
			pre->rchild=p;
		}
		else pre->RTag=0;
		pre=p;
		InThreading(p->rchild);
	}
}

在这里插入图片描述

B为遍历的第一个结点,当时pre为全局变量,自动初始化为NULL,故B的lchild指针指向null


三、带头结点的二叉树中序线索化

功能:为二叉树添加头结点后中序线索化
实现:
①创建头结点,申请内存空间,将LTag置为0,左孩子结点指向二叉树的根结点。将RTag置为1,初始化时默认右孩子指针指向自己,如果树为空,左孩子指针也指向自己。
②若树非空则开始中序线索化,将左孩子指向二叉树根结点,pre前置指针指向头结点,开始中序线索化。
③中序线索化结束,pre指针指向中序遍历最后一个结点,将最后一个结点的右孩子指针指向头结点,标记RTag为1。
④最后让头结点的右孩子指针指向最后一个结点,连成双向的二叉链表。

void InOrderThreading(BiThrTree &Thrt,BiThrTree T)
{
	Thrt=new BiThrNode;
	Thrt->LTag=0;
	Thrt->RTag=1;
	Thrt->rchild=Thrt;
	if(!T) Thrt->lchild=Thrt;
	else
	{
		Thrt->lchild=T;
		pre=Thrt;
		InThreading(T);
		pre->rchild=Thrt;
		pre->RTag=1;
		Thrt->rchild=pre;
	}
}

在这里插入图片描述
此中序遍历从H开始,序列为HDIBJEAFCG,通过I可以直接得到I的前驱为D,后继为B。而不需要再次遍历找到。


四、中序遍历线索二叉树

功能:中序遍历线索二叉树
实现:
①另p=T->lchild,将p指向树根结点,循环遍历当p=T时说明回到了头结点即遍历结束。
②当p!=T时,首先移动到最深的左儿子结点,输出数据。接着判断RTag若为1,则说明p的rchild指针指向中序遍历的下一个结点,于是按照右线索访问后继结点
③p=p->rchild即转向p的右子树继续遍历,直到回到头结点结束。

void InOrderTraverse_Thr(BiThrTree T)
{
	BiThrTree p;
	p=T->lchild;
	while (p!=T)
	{
		while (p->LTag==0) p=p->lchild;
		cout<<p->data;
		while (p->RTag==1&&p->rchild!=T)
		{
			p=p->rchild;
			cout<<p->data;
		}
		p=p->rchild;
	}
}

在这里插入图片描述
如图为带有头结点的双向二叉链表,灰色箭头为前驱,黑色箭头为后继


总结

本篇介绍了线索二叉树的结构和中序线索化二叉树,中序线索化带有头结点的二叉树,最后中序遍历线索二叉树。
线索二叉树的应用可以方便地得到节点的前驱和后继信息。

测试代码及运行实例

int main()
{
	BiThrTree T,M;
	PreCreateBiTree(T);
	InOrderThreading(M,T);
	InOrderTraverse_Thr(M);
	return 0;
}

在这里插入图片描述

  • 29
    点赞
  • 130
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新西兰做的饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值