二叉树的线索化思想解析与代码实现

雨燕双飞 提交于 2019-12-02 06:47:01

二叉树线索化

思想重于代码:写程序是为了验证思想,这里讲解部分比较多,还望耐心哈!!

二叉树线索化目的是想将二叉树的中序遍历不用递归方式实现,同时也充分的利用叶子结点的左右孩子空间,但是需额外引入一个标志,该标志用于判断该结点的左右孩子是线索连接的前驱后继还是直接连接左右孩子。并通过该链表将中序遍历的结点连成一条链,即遍历链表相当于二叉树的中序遍历。

问题:为什么要引入线索化这个概念?
1.对叶子的左右孩子的充分利用
2.当二叉树有大量结点时,需要进行很多次递归调用,需要消耗很大的栈空间。
3.可以直接访问当前结点的前驱后继,不需要重新从根节点往下再次遍历,效率高。

那么如何实现呢?

  1. 引入标志位 tag,一般使用枚举类型 enum{ Link,Thread }; Link表示孩子,Thread表示线索指向前驱后继
  2. 创建一个普通二叉树(即无线索化)
  3. 中序遍历二叉树进行线索化,线索化时需要引入一个辅助结点”pre”,这个结点左孩子一开始指向二叉树的根节点,右孩子指向空,我们知道在线索化时二叉树每个叶子都将被标志位Thread,指向他们的前驱后继,这时候考虑一个问题,在中序遍历时我们是无法知道当前结点的前驱或后继对应的是哪个结点,所以pre变量可以作为上一个结点的缓存。可以发现每一个叶子的前驱需要由pre指定,而后继需要在下一次(中序遍历的下一个结点)进行确定。因此pre在进行每一次的结点访问都要重新赋值,用以保存上一次结点。
  4. 这里提一下为什么使用中序遍历来实现,因为代码实现简单,它所遍历的结果是 “左孩子结点1右孩子,左孩子结点2右孩子”,这样每个结点间想距一个结点距离。举一个例子,如果为先序遍历实现的话 “根结点1左孩子右孩子,根结点2左孩子右孩子”,每个结点间隔两个结点距离,那么pre值需要缓存两个递归周期到下一个根节点在能给其左孩子赋值。
    5.一般我们对线索化会实现环形表结构,即首尾相连,引入多一个结点,这个不必多讲述吧…我代码这里没有讲解到

代码实现

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

typedef char Elemtype;
typedef enum{Link,Thread}Pointtyper;

typedef struct BiThrnode{
	Elemtype data;
	struct BiThrnode *lchild, *rchild;
	Pointtyper ltag,rtag;
}BiThrNode,*BiThrTree;
//辅助结点
BiThrTree pre = NULL;

//先序创建节点
void CreateBithrTree(BiThrTree *T)
{
	char c;
	scanf(" %c", &c);
	if( '#' == c ){
		*T = NULL;
		return;
	}
	*T = (BiThrTree)malloc(sizeof(BiThrNode));
	(*T)->data = c;
	(*T)->ltag = Link;
	(*T)->rtag = Link;
	CreateBithrTree(&(*T)->lchild);
	CreateBithrTree(&(*T)->rchild);
}

//中序遍历树找到叶子,并通过建立线索
void InOrderThreading(BiThrTree T)
{
	if(T){
		InOrderThreading(T->lchild);
		
		if( !T->lchild ){
			T->ltag = Thread;
			T->lchild = pre;
		}
		if( !pre->rchild ){
			pre->rtag = Thread;
			pre->rchild = T;
		}
		pre = T;
		
		InOrderThreading(T->rchild);
	}
}

//线索遍历
void ThreadTravel(BiThrTree T)
{
	while(T != pre){
	//遍历到左下角
		while( T->ltag == Link )
			T = T->lchild;
		while( T->rtag == Thread ){
			printf("%c",T->data);
			T = T->rchild;
		}
		printf("%c",T->data);
		T = T->rchild;
	}
	printf("%c",T->data);
	printf("遍历结束");
}

//递归遍历
void PreOrder(BiThrTree T)
{
	if( !T )
		return;
	printf("%c",T->data);
	PreOrder(T->lchild);
	PreOrder(T->rchild);
}

int main()
{
	BiThrTree T = NULL;
	pre = (BiThrTree)calloc(sizeof(BiThrNode),1);
	CreateBithrTree(&T);
	printf("递归遍历:");
	PreOrder(T);
	InOrderThreading(T);
	printf("\n线索遍历");
	ThreadTravel(T);
	printf("\n");
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!