二叉树的线索化

 

/*
Tree: 	
						A
				B				C
			D				E		F		
		 G	  H			  I	


前序遍历:ABDGHCEIF
前序输入:ABDG##H###CEI###F## 

*/
#include <iostream>
#include <queue>
#include <stack>

using namespace std;

typedef char TElemType;
typedef enum{link, thread} PointTag;

typedef struct BThrNode{
	TElemType val;
	PointTag ltag, rtag;
	struct BThrNode *lchild, *rchild;
}BThrNode, *BThrTree;

// 上一结点 
BThrTree pre;
 

// 前序遍历线索化:递归线索化 
// 由于前序遍历是从根结点开始,而线索化主要出现在两层以后,
//  
void PreThrTraverse(BThrTree T){
	if (T){
		if (!T->lchild){
			T->ltag = thread;
			T->lchild = pre;
		}
		if (!pre->rchild){
			pre->rtag = thread;
			pre->rchild = T;
		}
		pre = T;
		if (T->ltag == link)	// 防止叶子结点的前驱被当成子树 
			PreThrTraverse(T->lchild);
		if (T->rtag == link)
			PreThrTraverse(T->rchild);
	}
} 

void PreThreading(BThrTree *t, BThrTree T){
	*t = (BThrTree)malloc(sizeof(BThrNode));		// 创建一个头结点
	(*t)->ltag = link;
	(*t)->rtag = thread;
	(*t)->rchild = *t;	// 后继暂时指向自己 
	if (T == NULL){
		(*t)->lchild = *t;
	}
	else{
		pre = *t;
		(*t)->lchild = T;
		PreThrTraverse(T);
		pre->rtag = thread;		// 最后一个结点后继为头结点,遍历时可作判断条件**** 
		pre->rchild = *t;
		(*t)->rchild = pre;		// 头结点的后继为最后一个结点(它的左子树为根结点) 
	} 

}

/*
二叉树前序遍历输出 
思路:由于前序二叉树的遍历顺序为  顶点-->左子树-->右子树,则直接开始输出,
先找左子树,左子树找不到后直接找其右子树(包含后继) 
*/ 
void PreThrOrderTraverse(BThrTree T){
	BThrTree p = T->lchild;	// p指向根结点
	while (p != T){
		printf ("%c", p->val);
		if (p->ltag == link)
			p = p->lchild;
		else
			p = p->rchild;		
	}	
}

// 中序遍历线索化:递归线索化 
void InThrTraverse(BThrTree T){		//  
	if (T){
		InThrTraverse(T->lchild);	// 到叶子结点尽头 
		if (!T->lchild){	// 判断是否有左子树,若无则设置前驱 
			T->ltag = thread;
			T->lchild = pre;
		}
		if (!pre->rchild){	
			pre->rtag = thread;
			pre->rchild = T;
		}
		pre = T;
		InThrTraverse(T->rchild);
	}
}
/*
中序遍历线索化
需设立一个头结点(左子树指向根结点,右子树为后继,指向树遍历的最后一个结点) 
*/
void InThreading(BThrTree *t, BThrTree T){
	*t = (BThrTree)malloc(sizeof(BThrNode));		// 创建一个头结点
	(*t)->ltag = link;
	(*t)->rtag = thread;
	(*t)->rchild = *t;	// 后继暂时指向自己 
	if (T == NULL){
		(*t)->lchild = *t;
	}
	else{
		pre = *t;
		(*t)->lchild = T;
		InThrTraverse(T);
		pre->rtag = thread;		// 最后一个结点后继为头结点,遍历时可作判断条件**** 
		pre->rchild = *t;
		(*t)->rchild = pre;		// 头结点的后继为最后一个结点(它的左子树为根结点) 
	} 

}

/*
二叉树中序遍历输出 
思路:由于中序二叉树的遍历顺序为  左子树-->顶点-->右子树,则先找到尽头的左子树,
输出,若 rtag = link,则存在右子树,输出右子树(此时左子树看作顶点)。若 rtag =
thread,由于该二叉树线索化了,则右子树指向后继,指针往后进即可。 
*/ 
void InThrOrderTraverse(BThrTree T){
	BThrTree p = T->lchild;	// p指向根结点
	while (p != T){
		while (p->ltag == link){
			p = p->lchild;
		} 
		printf ("%c", p->val);
		while ((p->rtag == thread) && (p->rchild != T)){	// 当p有后继且后继不是头结点 
			 p = p->rchild;
			 printf ("%c", p->val);
		}
		p = p->rchild;		
	}	
}



// 后序遍历线索化:递归线索化 
void PostThrTraverse(BThrTree T){		//  
	if (T){
		InThrTraverse(T->lchild);	// 到叶子结点尽头
		InThrTraverse(T->rchild);
		if (!T->lchild){	// 判断是否有左子树,若无则设置前驱 
			T->ltag = thread;
			T->lchild = pre;
		}
		if (!pre->rchild){	
			pre->rtag = thread;
			pre->rchild = T;
		}
		pre = T;
	}
}
/*
后序遍历线索化
需设立一个头结点(左子树指向根结点,右子树为后继,指向树遍历的最后一个结点) 

*/
void PostThreading(BThrTree *t, BThrTree T){
	*t = (BThrTree)malloc(sizeof(BThrNode));		// 创建一个头结点
	(*t)->ltag = link;
	(*t)->rtag = thread;
	(*t)->rchild = *t;	// 后继暂时指向自己 
	if (T == NULL){
		(*t)->lchild = *t;
	}
	else{
		pre = *t;
		(*t)->lchild = T;
		PostThrTraverse(T);
		pre->rtag = thread;		// 最后一个结点后继为头结点,遍历时可作判断条件**** 
		pre->rchild = *t;
		(*t)->rchild = pre;		// 头结点的后继为最后一个结点(它的左子树为根结点) 
	} 

}

/*
二叉树后序遍历输出 
思路:由于中序二叉树的遍历顺序为  左子树-->右子树-->顶点,则先找到尽头的左子树,
输出,若 rtag = link,则存在右子树,输出右子树(此时左子树看作顶点)。若 rtag =
thread,由于该二叉树线索化了,则右子树指向后继,指针往后进即可。 
*/ 
void PostThrOrderTraverse(BThrTree T){
	BThrTree p = T->lchild;	// p指向根结点
	while (p != T){
		while (p->ltag == link && p->lchild != pre) {
			p = p->lchild;
		} 
		while (p->rtag == link && p->rchild != pre){
			p = p->rchild;
		} 
		if ((p->rtag == thread) && (p->rchild != T)){	// 当p有后继且后继不是头结点 
			 printf ("%c", p->val);
			 pre = p;
			 p = p->rchild;
			 
		}

//		p = p->rchild;
//		printf ("%c", p->val);
				
	}	
}






// 前序遍历创建线索树 
void CreateBiTree(BThrTree *T){

	char c;
	scanf("%c", &c);
	if (c == '#'){
		*T = NULL;
		return;
	}	
	else{
		*T = (BThrTree)malloc(sizeof(BThrNode));
		(*T)->val = c;
		(*T)->ltag = link;
		(*T)->rtag = link;
	} 
	CreateBiTree(&(*T)->lchild);
	CreateBiTree(&(*T)->rchild);
}

void delBiTree(BThrTree *T){
	if (*T){
		delBiTree(&(*T)->lchild);
		delBiTree(&(*T)->rchild);
		free(*T);
		*T = nullptr;		
	}
}


int main(int argc, char *argv[])
{
	BThrTree T = NULL,t = NULL;
	printf("请前序遍历输入结点:");
	CreateBiTree(&T);
	printf("中序遍历线索化后输入结点:");
	InThreading(&t,T);
	InThrOrderTraverse(t);
	delBiTree(&T);
	delBiTree(&t);
/*
	printf("前序遍历线索化后输入结点:");
	PreThreading(&t,T);
	PreThrOrderTraverse(t);
	delBiTree(&T);
	delBiTree(&t); */
/*	
	printf("后序遍历线索化后输入结点:");
	PostThreading(&t,T);
	PostThrOrderTraverse(t);
	delBiTree(&T);
	delBiTree(&t); */
	return 0;
}

 

参考资料:

https://blog.csdn.net/qq_29542611/article/details/79331315

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值