《数据结构(C语言版)第二版》第五章-树和二叉树(5.5.2 线索二叉树)

5.5.2 线索二叉树

该二叉树的先序序列为:-+a##*b##-c##d##/e##f##
该二叉树的中序序列为:a + b * c - d - e / f (需要增加括号说明)

在这里插入图片描述

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

typedef char TElemType;

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

BiThrTree pre = NULL;  //全局变量

void CreateBiTree(BiThrTree& T);
void InThreading(BiThrTree& p);
void InOrderThreading(BiThrTree& Thrt, BiThrTree T);
void InOrderTraverse_Thr(BiThrTree T);

int main()
{
	BiThrTree Tree = NULL;
	BiThrTree Thrt = NULL;

	printf("请输入要用二叉链表表示的字符序列: ");
	CreateBiTree(Tree);

	InOrderThreading(Thrt, Tree);
	InOrderTraverse_Thr(Thrt);

	return 0;
}


//按先序序列建立二叉树
void CreateBiTree(BiThrTree& T)
{
	TElemType ch = '\0';
	ch = getchar();

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiThrTree)malloc(sizeof(BiThrNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//算法 5.7  以结点p为根的子树中序线索化
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指向头结点Thrt,此步会将Thrt->RTag值修改为0.
			//所以在执行完该函数之后,要在InOrderThreading函数中重新将Thrt->RTag赋为1
		}
			
		pre = p;

		InThreading(p->rchild);
	}
}

//算法 5.8 带头结点的二叉树中序线索化
void InOrderThreading(BiThrTree& Thrt, BiThrTree T)
{
	Thrt = (BiThrTree)malloc(sizeof(BiThrNode));
	Thrt->LTag = 0; 
	Thrt->RTag = 1;
	Thrt->rchild = Thrt; 
	//Thrt->rchild被初始化为指向它本身,若上面thrt分配内存成功,则Thrt->rchild也不为空

	if (!T)
	{
		Thrt->lchild = Thrt;
	}
	else
	{
		Thrt->lchild = T;
		pre = Thrt;
		InThreading(T); 
		pre->rchild = Thrt;
		pre->RTag = 1;
		Thrt->RTag = 1; //InThreading函数会将Thrt->RTag改为0
		Thrt->rchild = pre;
	}	
}


//算法 5.9 遍历中序线索二叉树
void InOrderTraverse_Thr(BiThrTree Thrt)
{ 
	BiThrTree p =Thrt-> lchild; 
	
	while (p != Thrt)
	{
		while (p->LTag == 0)
		{
			p = p->lchild;
		}

		printf(" %c", p->data);

		while (p->RTag == 1 && p->rchild != Thrt)
		{
			p = p->rchild;
			printf(" %c", p->data);
		}

		p = p->rchild;
	}
}

在这里插入图片描述

按照上面的简易代码,利用先序序列对应的二叉树图,走一遍流程即可画出其对应的带头结点的中序线索二叉树链表。
下面的代码仅用于核对与矫正。

#include <stdio.h>
#include <stdlib.h>

typedef char TElemType;

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

BiThrTree pre = NULL;  //全局变量

/*
-+a##*b##-c##d##/e##f##
ABC##DE#G##F###
-*a##b##c##
ABD##E##C##
*/


void CreateBiTree(BiThrTree& T);
void InThreading(BiThrTree& p);
void InOrderThreading(BiThrTree& Thrt, BiThrTree T);
void InOrderTraverse_Thr(BiThrTree T);

int main()
{
	BiThrTree Tree = NULL;
	BiThrTree Thrt = NULL;

	printf("请输入要用二叉链表表示的字符序列: ");
	CreateBiTree(Tree);

	InOrderThreading(Thrt, Tree);
	InOrderTraverse_Thr(Thrt);

	return 0;
}


//按先序序列建立二叉树(先不用管线索)
void CreateBiTree(BiThrTree& T)
{
	TElemType ch = '\0';
	ch = getchar();

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiThrTree)malloc(sizeof(BiThrNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//算法 5.7  以结点p为根的子树中序线索化
// (先线索化左子树,再线索化根结点,最后线索化右子树)
/* 指针pre始终指向刚刚访问过的结点
   指针p指向当前访问的结点   */
void InThreading(BiThrTree& p)
{
	if (p)
	{
		printf("\n\np = %c", p->data);
	}
	else
	{
		printf("\n\np = %c", '#');
	}

	if (p)
	{
		if (pre)
		{
			printf("\n当p不为空时:pre = %c", pre->data);
		}
		else
		{
			printf("\n当p不为空时:pre = %c", '#');
		}

		printf("\n当p不为空时:p = %c", p->data);


		if (p->lchild)
		{
			printf("\n进行p的左子树线索化前:p->lchild = %c", p->lchild->data);
		}
		else
		{
			printf("\n进行p的左子树线索化前:p->lchild = %c", '#');
		}

		InThreading(p->lchild);
		//会一直往下找,找到最左下的结点,即二叉树中序序列的第一个结点。其一定是叶子结点,所以其左子树一定为空,从而跳出InThreading(p->lchild)这个函数
		//此时p指向的就是二叉树中序序列的第一个结点

		if (!p->lchild)
		{
			if (p)
			{
				printf("\n当p的左子树为空时:p = %c", p->data);
			}
			else
			{
				printf("\n当p的左子树为空时:p = %c", '#');
			}

			if (pre)
			{
				printf("\n当p的左子树为空时:pre = %c", pre->data);
			}
			else
			{
				printf("\n当p的左子树为空时:pre = %c", '#');
			}

			if (p->rchild)
			{
				printf("\n当p的左子树为空时:p->rchild = %c", p->rchild->data);
			}
			else
			{
				printf("\n当p的左子树为空时:p->rchild = %c", '#');
			}

			p->LTag = 1;
			p->lchild = pre;  //如果此处p指向二叉树中序序列的第一个结点,那么pre指向的就是其线索二叉树的头结点Thrt
		}
		else
		{
			p->LTag = 0;
		}

		if (!pre->rchild) //当pre指向线索二叉树的头结点Thrt时,其右子树被初始化了为它本身Thrt,不为空
		{
			if (pre)
			{
				printf("\n当pre的右子树为空时:pre = %c", pre->data);
			}
			else
			{
				printf("\n当pre的右子树为空时:pre = %c", '#');
			}

			if (p)
			{
				printf("\n当pre的右子树为空时:p = %c", p->data);
			}
			else
			{
				printf("\n当pre的右子树为空时:p = %c", '#');
			}

			if (pre->lchild)
			{
				printf("\n当pre的右子树为空时:pre->lchild = %c", pre->lchild->data);
			}
			else
			{
				printf("\n当pre的右子树为空时:pre->lchild = %c", '#');
			}

			pre->RTag = 1;
			pre->rchild = p;
		}
		else
		{
			pre->RTag = 0;
		}

		pre = p;

		if (pre)
		{
			printf("\n赋值后的pre为:pre = %c", pre->data);
		}
		else
		{
			printf("\n赋值后的pre为:pre = %c", '#');
		}


		if (p->rchild)
		{
			printf("\n进行p的右子树线索化前:p->rchild = %c", p->rchild->data);
		}
		else
		{
			printf("\n进行p的右子树线索化前:p->rchild = %c", '#');
		}

		InThreading(p->rchild);
	}
}

//算法 5.8 带头结点的二叉树中序线索化
void InOrderThreading(BiThrTree& Thrt, BiThrTree T)
{
	Thrt = (BiThrTree)malloc(sizeof(BiThrNode));
	Thrt->LTag = 0;
	Thrt->RTag = 1;
	Thrt->rchild = Thrt; //初始化


	if (T)
	{
		printf("\n\n\n将二叉树T中序线索化为带头结点的线索二叉树Thrt时:T = %c", T->data);
	}
	else
	{
		printf("\n\n\n将二叉树T中序线索化为带头结点的线索二叉树Thrt时:T = %c", '#');
	}


	if (!T)
	{
		Thrt->lchild = Thrt;
	}
	else
	{
		if (Thrt)
		{
			printf("\n二叉树T不为空时:Thrt = %c", Thrt->data);
		}
		else
		{
			printf("\n二叉树T不为空时:Thrt = %c", '#');
		}

		Thrt->lchild = T;
		if (Thrt->lchild)
		{
			printf("\nThrt->lchild = %c", Thrt->lchild->data);
		}
		else
		{
			printf("\nThrt->lchild = %c", '#');
		}

		pre = Thrt;
		if (pre)
		{
			printf("\n进入单个结点线索化前,pre = %c", pre->data);
		}
		else
		{
			printf("\n进入单个结点线索化前,pre = %c", '#');
		}


		if (T)
		{
			printf("\n进入单个结点线索化前,根结点T为:T = %c", T->data);
		}
		else
		{
			printf("\n进入单个结点线索化前,根结点T为:T = %c", '#');
		}

		InThreading(T);

		if (T)
		{
			printf("\n单个结点线索化后,根结点T为:T = %c", T->data);
		}
		else
		{
			printf("\n单个结点线索化后,根结点T为:T = %c", '#');
		}


		if (pre)
		{
			printf("\n单个结点线索化后,pre = %c", pre->data);
			printf("\n单个结点线索化后,pre->lchild = %c", pre->lchild->data);
		}
		else
		{
			printf("\n单个结点线索化后,pre = %c", '#');
			printf("\n单个结点线索化后,pre->lchild = %c", '#');
		}

		pre->rchild = Thrt;

		if (pre->rchild)
		{
			printf("\n单个结点线索化后,pre->rchild = %c", pre->rchild->data);
		}
		else
		{
			printf("\n单个结点线索化后,pre->rchild = %c", '#');
		}

		pre->RTag = 1;
		Thrt->RTag = 1;
		Thrt->rchild = pre;

		if (Thrt->rchild)
		{
			printf("\nThrt->rchild = %c", Thrt->rchild->data);
		}
		else
		{
			printf("\nThrt->rchild = %c", '#');
		}
	}
}


//算法 5.9 遍历中序线索二叉树
void InOrderTraverse_Thr(BiThrTree T)
{
	BiThrTree p = T->lchild;

	if (T->lchild)
	{
		printf("\n\n遍历时:T->lchild = %c", T->lchild->data);
	}
	else
	{
		printf("\n\n遍历时:T->lchild = %c", '#');
	}

	while (p != T)
	{
		if (p)
		{
			printf("\n当p不等于T时,p = %c", p->data);
		}
		else
		{
			printf("\n当p不等于T时,p = %c", '#');
		}

		if (T)
		{
			printf("\n当p不等于T时,T = %c", T->data);
		}
		else
		{
			printf("\n当p不等于T时,T = %c", '#');
		}


		while (p->LTag == 0)
		{
			p = p->lchild;

			if (p)
			{
				printf("\n当p->LTag等于0时:新p = %c", p->data);
			}
			else
			{
				printf("\n当p->LTag等于0时:新p = %c", '#');
			}

		}

		printf("\n第一种情况输出的元素为: %c", p->data);

		while (p->RTag == 1 && p->rchild != T)
		{
			p = p->rchild;
			printf("\n第二种情况输出的元素为: %c", p->data);
		}

		p = p->rchild;
		if (p)
		{
			printf("\n新p = %c", p->data);
		}
		else
		{
			printf("\n新p = %c", '#');
		}
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值