中序线索二叉树(C语言实现)

本文介绍了线索二叉树的概念、存储结构及基本操作,包括创建、遍历、查找前驱和后继节点等,并提供了具体的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.线索二叉树的定义:

2.线索二叉树的存储结构:

3.创建中序线索二叉树

4.遍历中序线索二叉树

5.在中序线索二叉树上查找任意结点的中序前驱结点

6.在中序线索二叉树上查找任意结点的中序后继结点

7.在中序线索二叉树上查找值为x的结点  (实质为遍历) 


1.线索二叉树的定义:

        为了保留结点在某种遍历序列中直接前驱结点和直接后继结点的位置信息。可以利用二叉树的二叉链表存储结构中的空指针域来指示。这些指向直接前驱结点和直接后继结点的指针被称为线索。加了线索的二叉树称为线索二叉树。

2.线索二叉树的存储结构:

        标记域:用来识别指针域内存放的是指针还是线索(即存放的是左右孩子,还是前驱后继)

标记域为0则存储孩子,为1则存储线索。

typedef char ElemType;

typedef struct node
{
	ElemType data;       //数据域
	int ltag,rtag;           //标记域可以为char类型,占的空间较小
	struct node *left,*right;      //指针域
}BiTree;

3.创建中序线索二叉树

        1.首先申请头结点,建立头结点跟根结点的关系(头结点的左指针指向根结点,右指针先指向自己(最后指向最后一个结点));

        2.找到中序遍历的第一个结点(使其左指针指向头结点);

        3.对二叉树线索化(在遍历过程中加线索);

        4.建立最后一个结点和头结点的关系(即最后一个结点右指针指向头结点)

BiTree *ThrtBiTree(BiTree *t)
{
	BiTree *p,*pre,*thrt,*s[N];
	int top=0;
	thrt=(BiTree *)malloc(sizeof(BiTree));      //开辟头结点 
	thrt->ltag=0;thrt->rtag=1;     //设置头结点的标记域 
	thrt->right=thrt;        //头结点右指针指向自己
	if(t==NULL)              //根结点为空,头结点左指针域指向自己  
	{
		thrt->left=thrt;
	}
	else
	{
		thrt->left=t;                  //根结点左指针指向根结点
		pre=thrt;                      //前驱指针指向头结点
		p=t;                           //后继指针指向根结点
		do{
			while(p!=NULL)             //入栈向左走
			{
				s[top]=p;
				top++;
				p=p->left;
			}
			if(top>0)                 //栈非空出队
			{
				top--;
				p=s[top];
				if(p->left==NULL)       //加左线索 
				{
					p->left=pre;
					p->ltag=1;
				}
				if(pre->right==NULL)   //加右线索 
				{
					pre->right=p;
					pre->rtag=1;
				}
				pre=p;          //指针跟进 
				p=p->right;
			}

		}while(p!=NULL||top>0);       //后继指针指向空,并栈空循环结束
		pre->right=thrt;      //最后结点右指针指向头结点 
		pre->rtag=1;
		thrt->right=pre;     //头结点右指针指向最后一个结点 
	}
	return thrt;	  //返回头结点
}

4.遍历中序线索二叉树

        线索二叉树中隐含后继或前驱,故可先找到第一个结点(某种遍历时),顺着后继线索遍历;或找到最后一个结点,顺着前驱线索遍历。

void InOrderthrt(BiTree *thrt)
{
	BiTree *p;
	p=thrt->left;      //从根结点出发 
	while(p!=thrt)       //指向头结点时循环结束,即算法结束
	{
		while(p->ltag==0)
		{
			p=p->left;      //向左走到第一个结点 
		}
		printf("%d\t%c\t%d\t",p->ltag,p->data,p->rtag);
		while(p->rtag==1&&p->right!=thrt)       //判断有没有后继线索且是否指向头结点 
		{
			p=p->right;
			printf("%d\t%c\t%d\t",p->ltag,p->data,p->rtag);
		}
		p=p->right;     //否则向右走 
	}
} 

5.在中序线索二叉树上查找任意结点的中序前驱结点

        若此结点有左线索则左指针指向前驱结点,若无前驱线索,则其左孩子为根结点的最右边的结点为前驱结点。

BiTree *InPreNode(BiTree *p)   //查找P结点的中序前驱结点 
{
	BiTree *pre;
	pre=p->left;        //先指向其左孩子
	if(p->ltag!=1)    //判断此结点是否有左孩子 
	{
		while(pre->rtag==0)  //则沿着其左子树深入到最右边 
		{
			pre=pre->right;
		}
	}
	return pre;      //返回前驱结点
}

6.在中序线索二叉树上查找任意结点的中序后继结点

        若此结点有右线索则右指针指向后继结点,若无后继线索,则其右孩子为根结点的最左边的结点为后继结点。

BiTree *InPostNode(BiTree *p)   ////查找P结点的中序后继结点
{
	BiTree *post;
	post=p->right;     //先指向其右孩子
	if(p->rtag!=1)    //判断此结点是否有右孩子
	{
		while(post->ltag==0)
		{
			post=post->left;   //沿着此结点的右子树深入到最左边 
		}
	}
	return post;          //返回后继结点
}

7.在中序线索二叉树上查找值为x的结点  (实质为遍历) 

        线索二叉树求前驱,后继结点的操作可遍历整个树,故可先找到第一个结点(某种遍历时),顺着求后继算法遍历;或找到最后一个结点(某种遍历时),顺着求前驱算法遍历。

BiTree *Search(BiTree *head,ElemType x)   //在线索二叉树head中查找数据域为x的结点
{
	BiTree *p;
	p=head->left;    //指向根结点
	while(p->ltag==0&&p!=head) //寻找中序遍历的第一个结点 
	{
		p=p->left;
	}
	while(p!=head&&p->data!=x)
	{
		p=InPostNode(p);           //调用在中序线索二叉树上寻找p结点的后继结点操作,实现遍历效果 
	}
	if(p==head)             //p指向头结点说明未找到
	{
		printf("Not find the data!\n");
		return 0;
	}
	else
	{
		return p;		
	}
} 

以上内容均属于自己学习总结,若有错误,请指正,转载请注明出处

### C语言遍历线索二叉树数据结构实现 在C语言中,为了实现遍历的线索化处理,通常会定义一种特殊的二叉树节点结构。这种结构不仅包含普通的左右子节点指针,还额外增加了两个成员变量用于指示当前节点是否有前驱和后继节点以及它们的具体位置。 #### 定义线索二叉树节点结构体 ```c struct ThreadedBinaryTreeNode { int value; struct ThreadedBinaryTreeNode *left, *right; bool lthread, rthread; // 左右线程标志位 }; ``` 此结构中的`lthread`和`rthread`布尔字段用来标记对应的链接是指向真实的子树还是作为线索指向其前驱或后继节点[^3]。 #### 创建并初始化线索二叉树 对于新创建的节点,默认情况下将其视为叶子节点,即设置`lthread=true`, `rthread=true`表示这两个方向上的连接都将是线索而不是真正的子树关系。 ```c // 初始化单个节点函数 struct ThreadedBinaryTreeNode* createNode(int val){ struct ThreadedBinaryTreeNode* newNode = (struct ThreadedBinaryTreeNode*)malloc(sizeof(struct ThreadedBinaryTreeNode)); newNode->value = val; newNode->left = NULL; newNode->right = NULL; newNode->lthread = true; newNode->rthread = true; return newNode; } ``` #### 对二叉树进行中线索化操作 通过递归的方法来构建整个二叉树的中线索链表,在这个过程中调整每个节点与其前后相邻节点之间的逻辑关联。 ```c void inorderThread(struct ThreadedBinaryTreeNode **prevPtr, struct ThreadedBinaryTreeNode *node) { if (!node) return; // 处理左子树 inorderThread(prevPtr, node->left); // 当前线索化处理 if ((*prevPtr)) { (*prevPtr)->rthread = false; (*prevPtr)->right = node; } node->lthread = (*prevPtr != NULL); node->left = *prevPtr; *prevPtr = node; // 处理右子树 inorderThread(&(*prevPtr), node->right); } ``` 上述代码片段实现了对给定二叉树执行一次完整的中遍历,并在此基础上建立了相应的线索连接[^5]。 #### 使用已线索化二叉树完成快速访问 一旦完成了对整棵树的线索化之后,则可以通过简单的迭代过程来进行高效的中遍历而无需再次调用栈或者队列辅助结构: ```c void threadedInorderTraversal(struct ThreadedBinaryTreeNode *root) { while (root && !root->lthread) root = root->left; while (root) { printf("%d ", root->value); if (root->rthread) root = root->right; else { root = root->right; while (root && !root->lthread) root = root->left; } } } ``` 这段程展示了如何利用已经建立好的线索机制有效地打印出所有元素值,从而验证了之前所做的工作确实能够简化后续的操作流程[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值