关于线索二叉树的详解

时间:2024-11-15 17:19:11

线索二叉树的详解

目录

  • 线索二叉树的详解
  • 前言
  • 一、线索二叉树是什么?
    • 三种二叉树线索化实例图
  • 二、实现线索二叉树
    • 1.二叉树的线索化
    • 2.线索二叉树的遍历
      • 中序线索二叉树寻找遍历的首节点
      • 中序线索二叉树寻找节点的直接后继
      • 遍历中序线索二叉树
  • 总结


前言

学了二叉树,我们发现,对二叉树的遍历是一个比较复杂的问题,需要用到递归或者栈才可以进行遍历,这样子的遍历实质上就是将二叉树化为一个有序的线性序列,在这个序列中,每一个节点有且只有一个前继节点(第一个节点除外),和一个后继节点(最后一个节点除外),但是这些节点不能直接的找到当前节点的前驱和后继信息,与此同时,二叉树在存储的过程中,会有很多的空节点,为了充分利用这些节点以及遍历更加方便,我们产生了线索二叉树


一、线索二叉树是什么?

为了区分二叉树的左孩子指针和右孩子指针是否为空,或者是否指向前驱节点或后继节点,我们将节点的结构改成5个域,在原二叉树的基础上添加左标志域Ltag和右标志域Rtag,他们是两个int型的数据域。

Lchild Ltag data Rtag Rchild
  1. 如果节点有左孩子,那么Lchild依然指向他的左孩子,否则指向遍历序列中他的前驱节点。

  2. 如果节点有右孩子,那么Rchild依然指向他的左孩子,否则指向遍历序列中他的后继节点。

  3. LtagRtag的定义如下:
    Ltag : 等于0时,Lchild域指示节点的左孩子;等于1时,Lchild指示节点的遍历前驱。
    Rtag : 等于0时,Rchild域指示节点的左孩子;等于1时,Rchild指示节点的遍历后继。

一些小概念
线索:指向前驱和后继节点的指针。
线索化:将空指针改为线索的过程。

三种二叉树线索化实例图

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、实现线索二叉树

以下都是以中序的方式进行的,先序和后序只需进行小小的改动即可

1.二叉树的线索化

    首先我们会遇到的问题就是,当遇到空指针的时候我们应该如何填写相应的内容,可分为两种情况讨论。
    当遍历到左孩子指针域为空的时候,我们应该填入该节点的遍历前驱节点的指针,这时候我们可以提前声明一个全局变量pre来记录刚刚访问过的节点,在遍历过程中如果遇到左孩子为空的节点,就将pre赋给他的左孩子域,并且将Ltag设置为1。pre的初值应该为NULL,因为便利的首节点的前驱节点一定为空。
    当遍历过程中右孩子的指针域为空的时候,要填的节点应该为当前节点遍历序列的后继节点,但是我们现在无法确定,因此当前节点的右孩子指针域只能遍历到下一个节点的时候在填,并且当前节点就是pre节点的后继节点,所以我们只需要在遍历的过程中加上判断,回填pre的语句,若pre的右孩子节点为空,那么将当前的节点赋值给pre的右节点,同时pre节点的Rtag应该置为1

中序线索化代码如下(示例):

void Inthread(BiTree root) 
{
//pre为全局变量,在函数外已经声明过
	if(root != NULL)
	{
		Inthread(root->Lchild);//递归线索化root的左孩子
		if(root->Lchild == NULL) //置前置线索 
		{
			root->Lchild = pre;
			root->Ltag = 1;
		}
		else{
			root->Ltag = 0;
		}
		if(pre != NULL && pre->Rchlid == NULL)//置后置线索
		{
			pre->Rchlid = root;
			pre->Rtag = 1;
		} 
		pre = root;
		Inthread(root->Rchlid);//递归线索化root的右孩子
	}
}

2.线索二叉树的遍历

    二叉树的中序遍历的思路就是:首先访问左子树,在访问根节点,最后访问右子树。

中序线索二叉树寻找遍历的首节点

    按照这样的访问次序,首先访问的是树的最左下端,即沿着左孩子链走到最下端,找到第一个没有左孩子的节点(Ltag == 1)
代码如下(示例):

BiTree InFirst(BiTree bt)
{
	BiTree p = bt;
	if(p == NULL)
	return(NULL);
	//因为是中序遍历,所以最开始的节点一定是最左边的 
	while(p->Ltag == 0)
	
		p = p->Lchild;
	
		
	return(p);
}

中序线索二叉树寻找节点的直接后继

    对于传进来的参数节点p,如果p没有右孩子那么直接可以获得他的后继节点,如果p有右子树,那么他的后继节点应该是p右子树中第一个遍历到的节点,有中序遍历我们可以知道,p的后继节点就是他右子树的最左下端第一个没有左孩子的节点
代码如下(示例):

BiTree InNext(BiTree p) 
{
	BiTree next,q;
	if(p->Rtag == 1) 
	{
		next = p->Rchlid;//直接利用线索	 
	}
	//右边的子树查找后继节点有问题 
	else{
		//在p的右子树中查找最左下端的节点 
		for(q = p->Rchlid; q->Ltag  == 0; q = q->Lchild);
		next = q;
		
	} 
	return(next);
}

遍历中序线索二叉树

    最后利用上述的InFirst和InNext函数进行遍历
代码如下(示例):

BiTree TinOrder(BiTree root) 
{
	BiTree p;
	p = InFirst(root);
	while(p != NULL) 
	{
		printf("%c",p->data);
		p = InNext(p);
	}
}

总结

通过上述的方法我们可以不用递归和栈从而实现对二叉树的遍历