树4——二叉树的线索化

零、说明

  1. 线索化有点复杂,仔细看,画图
  2. 线索化意义在于充分利用空置指针,以提高遍历的效率
  3. 完成后,遍历二叉树相当于遍历一个双向循环链表(以下说的是是中序遍历
    ①头节点左指针 指向 树的根节点,右指针 指向 遍历的最后一个节点。
    ②树中,遍历的第一个节点的左指针 指向 头节点,
    ③原来的左空指针指向上一个遍历到的节点,右空指针指向下一个遍历到的节点
    ④最后一个遍历到的节点的右指针指向头节点

头节点->根节点->…中序遍历到的第一个节点->…遍历的最后一个节点
 ↑----------------------------------------↓(左指针)<-------------↓(右指针)

  1. 先序和后序待完成

一、数据类型

typedef char Eltp;
typedef struct BTreenode
{
	Eltp data;
	int ltag,rtag;//0为指左右孩子,1为指下一线索 
	struct BTreenode *lch,*rch;
}BTreenode,*BTree;

二、准备工作

  1. Create函数,带#先序输入二叉树内容(见树3——二叉树(链式)),注意还要让p->ltag=0,p->rtag=0,每个节点在开始时左右tag都应为0
BTree pre;//全局变量,始终指向上一个访问的节点 
  1. 主函数中要声明两个BTree类型H,T,一个是树的根节点T,一个作为遍历的头节点H,到时候遍历的时候不用根节点T,就用这个头节点H

三、线索化

(前面准备阶段声明了一个全局变量BTree pre,现在就要用上)
主角是头节点H,处理得最多之后遍历用H

void Inthread(BTree T,BTree *H)
{
	(*H)=new BTreenode;//下五行是这个“头节点”的设定
	(*H)->ltag=0;//lch是正常的左孩子,指向根节点
	(*H)->lch=T;
	(*H)->rtag=1;//rch其实要指向最后一个节点,但是现在还没,先指向自己,待下面的函数使用
	(*H)->rch=(*H);
	
	pre=(*H);//第一个遍历根节点,则前一个结点是(*H)
	Inthreading(T);
	pre->rtag=1;//Inthreading调用结束后,pre就是遍历的最后一个节点了
	pre->rch=(*H);//其实,中序遍历,最后一个节点必然没有右孩子,如果有,它就不是最后一个节点,右孩子才是了。所以直接让右孩子等于头节点
	(*H)->rch=pre;//理由见本文零、3.①
}
void Inthreading(BTree p)//可能并非整棵树,而是部分节点,所以用p 
{
	if(p)//p为空就直接返回
	{
		Inthreading(p->lch);//中序,所以先来个p->lch,直到没有左孩子,就过去了
		if(p->lch==NULL)//如果左指针为空,想办法利用上
		{
			p->lch=pre;
			p->ltag=1; 
		} 
		if(pre->rch==NULL)//重要:现在未知下一个遍历的节点到底在哪,所以处理pre即可,p的右孩子等下一轮现在的p成为pre之后再搞
		{
			pre->rch=p;
			pre->rtag=1;
		}
		pre=p;//p处理完了,p就是前一个遍历到的节点了
		Inthreading(p->rch);
	}
}

四、遍历

注意传入的是上面线索化完得到的头节点H,而不是树的根节点T
再注意:这个遍历和普通二叉树不一样,是非递归写法

void Inorder(BTree H)
{
	BTree p;
	p=H->lch;//从树的根节点开始
	while(p!=H)//如果T为空树,结束,如果遍历完了(此时p指到T),也结束
	{
		while(p->ltag==0)//先到能下去的最左的左孩子,这个节点就是中序遍历到的第一个 
		{
			p=p->lch;
		}	
		cout<<p->data;//输出
		while(p->rtag==1&&p->rch!=H)//接下来一直跟随线索走,直到这个节点有右孩子,
		//那它下一个就不是线索了,或者下一个是H,那就是遍历完了,马上出循环
		{
			p=p->rch;
			cout<<p->data; 
		}
		p=p->rch;//如果p的rtag不为1,即它有右子树(这还不一定只有一个右孩子节点,可能是右子树了)
		//那么下一个被遍历到的其实是它的右子树最靠左的节点,思路同循环第一行的while(p->ltag==0)
	} 	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值