线索化-----二叉树

说明:

一、二叉树为什么要线索化:

二叉树线索化之后,可以使二叉树像链表一样对其中的元素进行访问,而不需要再利用递归来遍历二叉树,提高了代码的运行效率。

二、 二叉树线索化视图:

c96fbe5aa352487aab250a16b8ced883.png


代码实现: 

一、创建一个结构体:

typedef struct Node{
	int key,ltag,rtag;  //key表示二叉树的值,ltag,rtag分别表示左线索,右线索
	struct Node *lchild,*rchild; //lchild,rchild分别表示左子树,右子树
}Node; //Node可以理解为一个树节点

二、实现一个函数(能够初始化树节点数据):

Node *getNewNode(int key){
	Node *p=(Node *)malloc(sizeof(Node)); //给指针开辟一个内存空间
	p->key=key; //为二叉树的节点赋值
	p->ltag=p->rtag=0; //左、右线索初始化为0,表示每条线索头尾都有真实节点连接
	p->lchild=NULL; //初始化左子树
	p->rchild=NULL; //初始化右子树
	return p;
}

三、实现一个函数(能够生成二叉树结构):

Node *insert(Node *head,int key){
	if(head==NULL)return getNewNode(key); //如果头节点为空,就返回一个新的节点
	if(rand()%2) head->lchild=insert(head->lchild,key); //随机生成二叉树的左子树(递归)
	else head->rchild=insert(head->rchild,key); //随机生成二叉树的右子树(递归)
	return head;
}

四、实现一个函数(能够释放指针所占用的内存空间):

void clear(Node *root){
	if(root==NULL)return; //判断头节点是否为空
	if(root->ltag==0)clear(root->lchild); //ltag为0,表示有真实左子树节点存在(递归)
	free(root); //释放空间
	if(root->rtag==0)clear(root->rchild); //ltag为0,表示有真实右子树节点存在(递归)
	return;
}

 五、实现一个函数(能够将二叉树的每个节点线索化):

Node *pre_Node=NULL,*lineNode=NULL; //pre_Node表示前一个节点,lineNode表示二叉树的中间节点
void line(Node *root){ //中序线索化
	if(root==NULL)return; //判断头节点是否为空
	if(root->ltag==0)line(root->lchild); //如果ltag为0,则表示真实的左子树节点存在,可以递归操作
	if(lineNode==NULL) lineNode=root; //如果lineNode为空,则需要将root赋值给lineNode(二叉树的起始节点)
	if(root->lchild==NULL){ //如果左子树为空
		root->lchild=pre_Node; //左子树指向其前驱
		root->ltag=1; //表示不存在的节点需要线索化,ltag赋值为1
	}
	if(pre_Node&&pre_Node->rchild==NULL){ //如果pre_Node存在且其右子树为空
		pre_Node->rchild=root; //右子树指向其后继
		pre_Node->rtag=1; //表示不存在的节点需要线索化,ltag赋值为1
	}
	pre_Node=root; //下一个节点看上一个节点
	if(root->rtag==0)line(root->rchild); 如果rtag为0,则表示真实的右子树节点存在,可以递归操作
	return;
}
void line1(Node *root){ //封装
	line(root); //中序线索化
	pre_Node->rchild=NULL; //最右边的尾节点无节点可以连接,强制为空
	pre_Node->rtag=1; //表示尾节点需要线索化,ltag赋值为1
	return;
}

六、实现一个函数(能够遍历线索化后的二叉树):

Node *output(Node *p){
	if(p->rtag==1) return p->rchild; //如果为rtag为1,则返回其右子树节点
	p=p->rchild; //获取下一个右节点
	while(p->ltag==0&&p->lchild){ //如果左子树节点存在
		p=p->lchild; //循环获取左子树节点
	}
	return p;
}

完整代码:

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

typedef struct Node{
	int key,ltag,rtag;
	struct Node *lchild,*rchild;
}Node;
Node *getNewNode(int key){
	Node *p=(Node *)malloc(sizeof(Node));
	p->key=key;
	p->ltag=p->rtag=0;
	p->lchild=NULL;
	p->rchild=NULL;
	return p;
}
Node *insert(Node *head,int key){
	if(head==NULL)return getNewNode(key);
	if(rand()%2) head->lchild=insert(head->lchild,key);
	else head->rchild=insert(head->rchild,key);
	return head;
}
void clear(Node *root){
	if(root==NULL)return;
	if(root->ltag==0)clear(root->lchild);
	free(root);
	if(root->rtag==0)clear(root->rchild);
	return;
}
Node *pre_Node=NULL,*lineNode=NULL;
void line(Node *root){
	if(root==NULL)return;
	if(root->ltag==0)line(root->lchild);
	if(lineNode==NULL) lineNode=root;
	if(root->lchild==NULL){
		root->lchild=pre_Node;
		root->ltag=1;
	}
	if(pre_Node&&pre_Node->rchild==NULL){
		pre_Node->rchild=root;
		pre_Node->rtag=1;
	}
	pre_Node=root;
	if(root->rtag==0)line(root->rchild);
	return;
}
void line1(Node *root){
	line(root);
	pre_Node->rchild=NULL;
	pre_Node->rtag=1;
	return;
}
Node *output(Node *p){
	if(p->rtag==1) return p->rchild;
	p=p->rchild;
	while(p->ltag==0&&p->lchild){
		p=p->lchild;
	}
	return p;
}
void output1(Node *p){
	if(p->lchild)output1(p->lchild);
	printf("%d ",p->key);
	if(p->rchild)output1(p->rchild);
	return;
}
int main(){
	srand(time(0));
	Node *p=NULL;
	for(int i=0;i<10;i++){
		p=insert(p,rand()%100+1);
	}
	output1(p);
	printf("\n");
	pre_Node=lineNode=NULL;
	line1(p);
	p=lineNode;
	while(p){
		printf("%d ",p->key);
		p=output(p);
	}
	clear(p);
	return 0;
}

文章到此结束!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值