一步一步复习数据结构和算法基础-后序线索二叉树

本文介绍了一种后序线索二叉树的实现方法,包括如何创建二叉树、进行后序线索化以及遍历线索二叉树。通过具体的C语言代码示例,详细解释了每个步骤的实现细节。

转自:http://blog.youkuaiyun.com/flying0033/article/details/6937477

后序线索二叉树的线索化有些麻烦:

1:若节点是二叉树的根,则后继为空;

2:若节点X是双亲的右孩子或者是双亲的左孩子且双亲没有右子树,则后继为双亲节点;

3:若双亲有左孩子而且双亲有右孩子,则后继为双亲右子树上面按后序遍历列出的第一个节点。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef enum{Link,Thread} PointTag;
typedef char Element;
typedef int Status;
typedef struct Node{
	Element data;
	struct Node* left;  //指向左孩子
	struct Node* right; //指向右孩子
	PointTag Ltag;   //左右标志
	PointTag Rtag;
}BitNode,*BitTree;
Status visit(Element e);
Status CreateTree(BitTree *T);
void InThreading(BitTree T);
void InOrderThreading(BitTree *H,BitTree T);
void InOrderTraverse_Thr(BitTree L);


BitTree pre;
Status visit(Element e)
{
	printf("%c ",e);
	return OK;
}
Status CreateTree(BitTree *T) //前序创建二叉树
{
	Element ch;
	scanf("%c",&ch);
	if(ch == '#')
		(*T) = NULL;
	else
	{
		(*T) = (BitTree)malloc(sizeof(BitNode));
		if(!(*T))
			exit(OVERFLOW);
		(*T)->data = ch;
		(*T)->Ltag = Link;
		(*T)->Rtag = Link;
		CreateTree(&(*T)->left);
		CreateTree(&(*T)->right);
	}
	return OK;
}
void InThreading(BitTree p) //后序线索二叉树
{
	if(p)
	{
		InThreading(p->left);
		InThreading(p->right);
		if(!p->left)
		{
			p->left = pre;
			p->Ltag = Thread;
		}
		if(!pre->right)
		{
			pre->right = p;
			pre->Rtag = Thread;
		}
		pre = p;
	}
}
void InOrderThreading(BitTree *H,BitTree T) //创建头节点,后序线索二叉树
{
	(*H) = (BitTree)malloc(sizeof(BitNode));
	if(!(*H))
		exit(OVERFLOW);
	(*H)->right = (*H);
	(*H)->Rtag = Link;
	if(!T)
	{
		(*H)->left = (*H);
		(*H)->Ltag = Link;
	}
	else
	{
		pre = (*H);
		(*H)->left = T;
		(*H)->Ltag = Link;
		InThreading(T);
		(*H)->right = pre;
	}
}
BitTree Parent(BitTree Thr,BitTree p)  //取得节点的父节点
{
	BitTree temp = Thr;
	if(temp->left == p)
		return temp;
	else
	{
		temp = temp->left;
		while(temp->left != p && temp->right != p)
		{
			if(temp->Rtag == Link)
				temp = temp->right;
			else
				temp = temp->left;  //有左孩子去左孩子,没有左孩子,去前驱;
		}
	}
	return temp;
}
void InOrderTraverse_Thr(BitTree Thr)
{
	BitTree temp = Thr->left;
	BitTree par = NULL;
	while(TRUE)
	{
		while(temp->Ltag == Link)
			temp = temp->left;
		if(temp->Rtag == Link)
			temp = temp->right;
		else
			break;
	}
	while(temp != Thr)
	{
		visit(temp->data);
		par = Parent(Thr,temp);  //获得节点temp的父节点
		if(par == Thr) //若父节点是Thr则节点temp为根节点,无后继
			temp = Thr;
		else if(par->Rtag == Thread || temp == par->right) //无右兄弟的左节点或是右儿子
			temp = par;
		else				//节点temp是左孩子,且有右兄弟
		{
			while(par->Rtag == Link)
			{
				par = par->right;
				while(par->Ltag == Link)
				{
					par = par->left;
				}
			}
			temp =par;
		}
	}
}
int main()
{
	BitTree H,T;
    printf("请输入前序二叉树的数据,例('ABDH##I##EJ###CF##G##')\n");
    CreateTree(&T);
    InOrderThreading(&H,T);
    InOrderTraverse_Thr(H);
    return 0;
}


### 关于后序线索二叉树求后继节点的算法后序线索二叉树中,由于后序遍历遵循“左--根”的访问顺序,因此对于任意节点 \( p \),其后继节点可能位于不同的位置。具体来说: #### 节点 \( p \) 的后继节点判断逻辑 1. 如果节点 \( p \) 是某个子树中的最右侧叶子节点,则它的后继可能是该子树的根节点。 2. 若节点 \( p \) 不是最右侧叶子节点,则可以通过线索化的指针找到对应的后继。 以下是具体的实现方法及其解释: --- #### 实现代码(C++) ```cpp // 定义二叉树节点结构 struct TreeNode { int val; bool ltag, rtag; // 左右标志位 TreeNode *lchild, *rchild; TreeNode(int v = 0) : val(v), ltag(false), rtag(false), lchild(nullptr), rchild(nullptr) {} }; TreeNode* successor(TreeNode* node) { if (!node || !node->rtag && !node->rchild) return nullptr; // 特殊情况处理 // 如果有右线索 (rtag == true),则直接返回右线索指向的节点 if (node->rtag) { return node->rchild; // 后继由线索指定 [^5] } // 如果没有右线索,则需要向上回溯到最近的一个祖先节点 while (node->parent && node == node->parent->rchild) { // 当前节点为其父节点的右孩子 node = node->parent; // 继续向上移动直到找到合适的后继 } // 返回当前节点的父节点作为后继 return node->parent ? node->parent : nullptr; // 找不到则返回nullptr [^4] } ``` --- #### 解析与说明 1. **右线索存在的情况** 如果节点 \( p \) 的 `rtag` 标志为真 (`true`),表示已经建立了后继线索,则可以直接通过 `p->rchild` 获取后继节点[^5]。 2. **右线索不存在的情况** 如果节点 \( p \) 没有右线索 (`false`),则需沿着父节点路径向上追溯,直至找到第一个满足条件的祖先节点。这个条件通常是:\( p \) 是其父节点的左子树的一部分[^4]。 3. **特殊情况处理** - 对于某些边界情况(如 \( p \) 是整个树中最右边的叶节点),它本身并没有后继节点,应返回 `nullptr` 表示结束。 --- #### 示例验证 假设一棵简单的二叉树,其后序遍历序列为 DEBCA。按照上述规则可以得出以下结论: - D 的后继是 E; - E 的后继是 B; - C 的后继是 A; - A 没有后继。 这些关系可以在实际测试中验证正确性。 --- ### 总结 以上实现了基于后序线索二叉树求解后继节点的方法,并提供了详细的解析代码支持。这种方法充分利用了线索化的优势,避免了额外的空间开销以及复杂的递归操作。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值