二叉树的线索化&&线索二叉树的遍历(中序)

二叉树的线索化:对于N个节点的二叉树,在二叉存储链表中有N+1个空链域,利用这些空链域存放某种遍历次序下的指向该节点的前驱和后继的指针,这些指针成为线索,被线索的二叉树成为线索二叉树。这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
中序线索二叉树:指在中序遍历的同时,对二叉树进行线索化,只需要在原先的中序遍历中添加相应的线索话语句即可,设置两个指针,P和Pre,P指向当前访问的节点,Pre指向上一个访问的节点,修改指针:如果P->LchNULL,则P->Lch=Pre,P->Ltag=1;如果Pre->RchNULL,则Pre->Rch=P,Pre->Rtag=1。随着P和Pre的不断更新,即可完成线索化过程
void InOrder(node *now)//中序递归将二叉树进行线索化 
{
	if(now!=NULL)
	{
		InOrder(now->lch);
		/****线索化的语句*****/
		if(now->lch==NULL)
		{
			now->lch=pre;
			now->Ltag=1;
		}
		if(pre!=NULL&&pre->rch==NULL)
		{
			pre->rch=now;
			pre->Rtag=1;
		}
		pre=now;
		/*********/
		InOrder(now->rch);
	} 
	return ;
}
如果一个节点的左孩子为空,我们让这个lch指针指向指向该节点的前驱,如果该节点的右孩子为空,则将rch指针指向该节点的后继,此时,我们需要增加两个标记,表明指针是指向孩子的还是指向前驱或者后继。
Ltag:为0,表示Lch指向左孩子;为1,表示Lch指向前驱节点
Rtag:为0,表示Rch指向左孩子;为1,表示Rch指向后继节点
线索化之后,该如何遍历呢?以中序遍历为例,遍历分为两个步骤:
1.访问遍历的第一个节点,位于树中最“左下端的节点”,从根节点沿着左孩子指针,找到没有左孩子的节点即可
node* First_node(node *now)//寻找线索二叉树遍历的第一个节点 
{
	node *first=now;
	if(first==NULL)
	return first;
	while(first->Ltag==0)
	first=first->lch;
	return first;
}
2.寻找并访问当前节点的后继节点,重复执行步骤2,直到所有的节点都被访问到。如何寻找后继节点呢?如果此时节点的Rtag==1时,Rch指针指向的就是后继节点,否则,根据中序遍历的思想,遍历完该节点后,接下来应该访问其右子树,话句话说,后继节点一定是右子树中第一个被访问的节点,这不正是First_node函数的功能吗?
node* Next_node(node *now)//寻找遍历的下一个节点 
{
	node *next=NULL;
	if(now->Rtag==1)
	next=now->rch;
	else
	next=First_node(now->rch);//根据中序遍历的思想,下一个要访问的节点一定是此时节点的右子树,而右子树第一个要访问的节点可以用First_node 函数求出 
	return next;
}
完整代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;

#define pi acos(-1.0)
#define e exp(1.0)
typedef long long ll;
struct node 
{
	char data;
	bool Ltag;//0,lch指向左孩子,1,lch指向的是前驱 
	bool Rtag;//0,rch指向右孩子,1,rch指向的是后驱 
	node *lch;
	node *rch;
};
node *pre=NULL;
void Create(node *&root)//前序创建二叉树 
{
	char c;
	c=getchar();
	if(c=='\n')
	return ;
	if(c=='#')
	root=NULL;
	else
	{
		root=new node;
		root->data=c;
		root->Ltag=0;//这两条千万别忘了——初始化 
		root->Rtag=0;// 
		Create(root->lch);
		Create(root->rch); 
	}
	return ;
}
void InOrder(node *now)//中序递归将二叉树进行线索化 
{
	if(now!=NULL)
	{
		InOrder(now->lch);
		/****线索化的语句*****/
		if(now->lch==NULL)
		{
			now->lch=pre;
			now->Ltag=1;
		}
		if(pre!=NULL&&pre->rch==NULL)
		{
			pre->rch=now;
			pre->Rtag=1;
		}
		pre=now;
		/*********/
		InOrder(now->rch);
	} 
	return ;
}
node* First_node(node *now)//寻找线索二叉树遍历的第一个节点 
{
	node *first=now;
	if(first==NULL)
	return first;
	while(first->Ltag==0)
	first=first->lch;
	return first;
}
node* Next_node(node *now)//寻找遍历的下一个节点 
{
	node *next=NULL;
	if(now->Rtag==1)
	next=now->rch;
	else
	next=First_node(now->rch);//根据中序遍历的思想,下一个要访问的节点一定是此时节点的右子树,而右子树第一个要访问的节点可以用First_node 函数求出 
	return next;
}
void InOrder_chain(node *root)
{
	node *now=First_node(root);
	while(now!=NULL)
	{
		printf("%c",now->data);
		now=Next_node(now);
	}
	putchar('\n');
	return ;
}
void Delete(node *now)//后序删除二叉树
{
	if(now!=NULL)
	{
		Delete(now->lch);
		Delete(now->rch);
		delete now;
	}
	return ;
} 
int main()
{
//	freopen(".../.txt","w",stdout);
//	ios::sync_with_stdio(false);
	node *root=NULL;
	Create(root);
	InOrder(root);
	InOrder_chain(root);
	Delete(root);
	return 0;
}

后续再补充线索二叉树的后续遍历算法吧……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值