数据结构之二叉树的线索化

线索二叉树
     指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树

lchild ltag data rtag rchild

当ltag 为0 时指向该结点的做孩子,为1 时指向该结点的前驱

当rtag为0 时指向该结点的右孩子,为1时指向该结点的后继

 
线索化:二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化, 实质:是将二叉链表中的空指针改为指向前驱或后继的线索,由于前驱和后继的信息只有在遍历该二叉树时才能得到,所以线索化的过程就是 在遍历的过程中修改空指针的过程
#include<stdio.h>
#include<malloc.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define EEROR 

typedef int Status ;
typedef enum{Link,Thread}tag;//记录是指向前驱后继还是指向其子树,link代表指向其子树,thread代表指向其前驱或者后继


typedef struct treeNode{
	tag lTag;//是否指向前驱
	tag rTag;//是否指向后继
	char data;//数据域
	treeNode *lchild;
	treeNode *rchild;
}treeNode,*Tree;

Tree pre;//全局变量,代表指向刚刚访问过的结点

void create(Tree *tree){
	char ch ;
	scanf("%c",&ch);//输入结点的数据
	if(ch == '#'){//如果输入#,则为空树
		*tree = NULL;
	}
	else{
		*tree = (treeNode *)malloc(sizeof(treeNode));

		(*tree)->data = ch;
		create(&(*tree)->lchild);//创建左子树
		if((*tree)->lchild){//如果有左子树,则设置标志 lTag为 link
			(*tree)->lTag = Link;
		}
		create(&(*tree)->rchild);//创建右子树
		if((*tree) -> rchild){
			(*tree)->rTag = Link;
		}
	}
}

/*

  中序遍历线索化
  当此结点没有左孩子(或者没有右孩子)时,修改其指针,lchild指向上一结点,也就是前驱(修改rchild,使其指向后继)
*/

void threadTree(Tree tree){//把二叉树线索化:在遍历过程修改空指针的过程
	if(tree){
		
		threadTree(tree->lchild);

		if(!tree->lchild){//如果当前结点没有左孩子,则修改lTag为thread,并把lchild指向上一结点
			tree->lTag = Thread;
			tree->lchild = pre;
		}
		if(!pre->rchild){//如果上一结点没有右孩子,则修改上一结点的rTag为thread,并把rchild指向当前结点
			pre->rTag = Thread;
			pre->rchild = tree;
		}
		pre = tree;//更换pre
		threadTree(tree->rchild);
	}
}


/*
给线索化后的二叉树添加上头结点,并使头结点的lchild指向二叉树的根,让二叉树遍历的第一个结点lchild指向头结点,最后一个结点的rchild指向头结点,头结点的rchild指向二叉树遍历的最后一个
结点。这样既可以从第一个结点起顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历

*/
Status addHeadNode(Tree tree,Tree *th){//th指向头结点,为二重指针
	*th = (treeNode*)malloc(sizeof(treeNode));//为头结点分配内存空间
	(*th)->lTag = Link;
	(*th)->rTag = Thread;
	(*th)->rchild = *th;//右指针回指

	if(!tree){//如果二叉树为空树,则左指针回指
		(*th)->lchild = (*th);
	}

	else{
		pre = (*th);//使pre指向头结点
		(*th)->lchild = tree;//头结点的lchild指向二叉树的根
		threadTree(tree);//线索化,起始时,pre指向头结点,结束时指向最后一个结点,所以可以使二叉树遍历的一个结点的lchild指向该头结点
		pre->rTag = Thread;
		pre->rchild = (*th);//pre现在是指向二叉树的最后一个结点,所以把rchild指向第一个结点
		(*th)->rchild = pre;//把头结点指向最后一个结点
	}
	return OK;
}


void inOrder(Tree tree){//遍历二叉树线索链表
	Tree p;
	p = tree->lchild;//指向根结点

	while(p != tree){
		while(p->lTag == Link){//循环至第一个结点
			p = p->lchild;
		}
		printf("%c",p->data);
		
		while(p->rTag == Thread && p->rchild != tree){//如果有后继,则打印其后继的值,否则移至其右子树
			p = p->rchild;
			printf("%c",p->data);
		}
		
		p = p ->rchild;
	}
}


void main(){
	Tree tree,th;
	printf("请用前序输入一棵二叉树:");
	create(&tree);
 
	addHeadNode(tree,&th);
	inOrder(th);
}

     
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值