数据结构 -> 后序创建二叉树


二叉树的前,中,后序遍历 以及通过补‘#’字符补充二叉树空分支,按照前序顺序构造二叉树,
这些都比较简单,我这就不过多地赘述;直接贴代码
#include "stdafx.h"

#include<iostream>
using namespace std;
typedef char DataType;
typedef struct Node
{
	DataType data;          //数据域
	struct Node * lchild;
	struct Node * rchild;   //结点的左右子数指针
}BTNode;                    //二叉树结点类型


							//初始化空二叉树
void TreeInit(BTNode * &root);

//按照前序遍历序列建立二叉树
void CreateBTree_Pre(BTNode * &root, DataType Array[]);

//前序遍历二叉树
void PreOrder(BTNode * root);

//中序遍历二叉树
void InOrder(BTNode * root);

//后序遍历二叉树
void PostOrder(BTNode * root);

//计算二叉树的深度
int BTreeDepth(BTNode * root);

//释放二叉树中所有结点
void ClearBTree(BTNode * &root);
#include"stdafx.h"
#include"BiTree.h"

//初始化空二叉树
void TreeInit(BTNode * &root)
{
	root = NULL;
}

//按照前序遍历序列建立二叉树
void CreateBTree_Pre(BTNode * &root, DataType Array[])
{
	static int count = 0;       //静态变量count
	char item = Array[count];   //读取Array[]数组中的第count 元素
	count++;

	if (item == '#')
	{
		root = NULL;
	}
	else
	{
		root = new BTNode;
		root->data = item;
		CreateBTree_Pre(root->lchild, Array);    //建立左子树
		CreateBTree_Pre(root->rchild, Array);    //建立右子树
	}
}
//前序遍历二叉树
void PreOrder(BTNode * root)
{
	if (root != NULL)
	{
		cout << root->data;			//访问根结点
		PreOrder(root->lchild);		//前序遍历左子树
		PreOrder(root->rchild);		//前序遍历右子树
	}
}

//中序遍历二叉树
void InOrder(BTNode * root)
{
	if (root != NULL)
	{

		InOrder(root->lchild);				//中序遍历左结点
		cout << root->data;					//访问根结点
		InOrder(root->rchild);				//中序遍历右子树
	}
}


//后序遍历二叉树
void PostOrder(BTNode * root)
{
	if (root != NULL)
	{

		PostOrder(root->lchild);				//后序遍历左结点
		PostOrder(root->rchild);				//后序遍历右子树
		cout << root->data;					//访问根结点
	}
}

//释放二叉树中所有结点
void ClearBTree(BTNode * &root)
{
	if (root != NULL)
	{
		ClearBTree(root->lchild);
		ClearBTree(root->rchild);
		delete root;
		root = NULL;
	}
}

//计算二叉树的深度
int BTreeDepth(BTNode * root)
{
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		int depl = BTreeDepth(root->lchild);
		int depr = BTreeDepth(root->rchild);
		if (depl > depr)
		{
			return depl + 1;
		}
		else
		{
			return depr + 1;
		}
	}

#include "stdafx.h"
#include"BiTree.h"

int main()
{
	BTNode *root;
	DataType A[] = "ABD##E##CF#G###";	//以“#”补充空分支后的某个遍历序列


	TreeInit(root);						//初始化空二叉树
	CreateBTree_Pre(root, A);			//以前序遍历序列建立二叉树

	cout << "中序遍历序列:";
	InOrder(root);
	cout << endl;						//输出中序遍历树

	cout << "后序遍历序列:";
	PostOrder(root);
	cout << endl;						//输出后序遍历树

	cout << "深度:" << BTreeDepth(root) << endl;	//计算二叉树深度
	system("pause");
	return 0;
}


配合这张图片以及测试代码,我相信应该比较好理解二叉树的三种遍历顺序以及前序构造二叉树;
好,下面我们重点来看看另外一种构建二叉树的方式:后序构造二叉树
首先呢,我们得清楚一个概念,我所谓的构建二叉树的方式,是通过把二叉树的后序遍历得到的
结果存放在一个字符串中(用‘#’表示二叉树的空结点),再依据这个字符串构建出相应的二叉树

ok.清楚了我们要做什么以后,开始动手!

参照前序遍历顺序,以及后序遍历的特点,很自然的认为这通过两种方式构建树的代码应该也是非常
相似的,只需要把前序遍历代码中生成根结点的部分放在生成左右孩子之后,应该能轻松写出后序创
建二叉树的函数
//按照后序遍历序列建立二叉树 --error
void CreateBTree_Post(BTNode * &root, DataType Array[])
{
	static int count = 0;       //静态变量count
	char item = Array[count];   //读取Array[]数组中的第count 元素
	count++;

	if (item == '#')
	{
		root = NULL;
	}
	else
	{
		CreateBTree_Post(root->lchild, Array);    //建立左子树
		CreateBTree_Post(root->rchild, Array);    //建立右子树
		root = new BTNode;
		root->data = item;
	}

}

程序一跑,马上就断掉了。。。
调试跟进后发现,后序创建二叉树,无论如何,第一个位置一定是‘#’
(后序遍历只有遇到空结点才会停止往下延伸),那么条件if(item == '#')root == NULL;
成立,程序直接断掉。

那这就麻烦了,不仅后序创建二叉树无解,中序创建二叉树也无解(他们都先检索左孩子
直到遇见空结点才返回)


显然,这种思路是走不通的;计算机不像我们人一样,可以通过对叶子结点的分析,一步
一步反推出整棵树的形状,你只有把所有数据都传给它,它才能帮你分析出树的模样;换
句话说,你只有确确实实地生成了一棵树,计算机才知道它到底长什么样子,而不是像我
们人类通过一样能够想象在头脑中描绘出树的模样

很自然的,想让计算机和我们一样通过叶子反推出根这一方法行不通。那么我们就让这棵
树从根部往下生长!

通过后序遍历的特点我们可以发现:生成树的字符串的最后一个字符,代表的就是它的根结
点,倒数第二个就是它的右孩子。。。很容易发现,如果我们从字符串后面开始推,按照
根结点 -> 右结点 ->左节点 的顺序就能通过递归构造出一棵二叉树了! 

//按照后序遍历序列建立二叉树
void CreateBTree_Post2(BTNode * &root, DataType Array[])
{
	static int count = strlen(Array);       //静态变量count
	char item = Array[count - 1];   //读取Array[]数组中的第count 元素
	count--;

	if (item == '#')
	{
		root = NULL;
	}
	else
	{
		root = new BTNode;
		root->data = item;
		CreateBTree_Post2(root->rchild, Array);    //建立右子树
		CreateBTree_Post2(root->lchild, Array);    //建立左子树
	}

}

测试代码:

int main()
{
	
	BTNode *root;
	TreeInit(root);						//初始化空二叉树
	DataType A[] = "##C##DB##EA";	//以“#”补充空分支后的某个遍历序列
	CreateBTree_Post2(root, A);			//以前序遍历序列建立二叉树


	cout << "前序遍历序列:";
	PreOrder(root);
	cout << endl;						//输出前序遍历树

	cout << "中序遍历序列:";
	InOrder(root);
	cout << endl;						//输出中序遍历树

	cout << "深度:" << BTreeDepth(root) << endl;	//计算二叉树深度
	system("pause");
	return 0;
}

### 绘制后序线索二叉树 对于后序线索二叉树的构建,其核心在于理解后序遍历的特点以及如何在线索化过程中处理节点之间的关系。后序遍历遵循左子树 -> 右子树 -> 根节点的原则。 #### 后序线索二叉树的概念 在一个具有n个结点的二叉链表中存在n+1个空指针域。通过利用这些空指针域来保存指向各结点在特定遍历顺序下的前驱和后继的信息,可以形成所谓的“线索”。当针对后序遍历时,则会创建后序线索二叉树[^4]。 #### 构造过程详解 为了更好地解释这一概念并展示具体的实现方法,这里提供了一个详细的图解步骤: 1. **初始化** - 开始时设定当前访问的是根节点。 2. **寻找最右下角叶子节点作为起点** - 对于任意给定的一棵树来说,在执行后序遍历之前应该先找到最右边的那个叶节点(即最后一个被访问到的位置),以此为起始位置进行后续操作。 3. **设置线索连接** - 当沿着某条路径向下移动直到遇到一个无右孩子的节点时,就将其设为其父节点的后继;同样地,如果某个节点没有左孩子,则应建立从前一节点至该节点的链接。 4. **回溯至上层节点继续线索化** - 完成上述工作之后应回退回到上一层级重复相同的操作直至整个结构都被完全线索化为止。 5. **最终状态** - 所有内部节点都将拥有至少一条有效的前后向线索指示其他相邻成员的关系。 以下是Python代码片段用于演示此逻辑: ```python class Node: def __init__(self, data=None): self.data = data self.left = None self.right = None self.ltag = 0 # ltag=1表示left是指向前驱 self.rtag = 0 # rtag=1表示right是指向后继 def post_order_threading(root): prev_node = None def thread_tree(node): nonlocal prev_node if node is not None: # 左子树递归调用 thread_tree(node.left) # 右子树递归调用 thread_tree(node.right) if node.left is None and prev_node is not None: node.left = prev_node node.ltag = 1 if prev_node is not None and prev_node.right is None: prev_node.right = node prev_node.rtag = 1 prev_node = node thread_tree(root) # 创建测试用例 root = Node(1) node_2 = Node(2) node_3 = Node(3) node_4 = Node(4) node_5 = Node(5) node_6 = Node(6) root.left = node_2 root.right = node_3 node_2.left = node_4 node_2.right = node_5 node_3.left = node_6 post_order_threading(root) ```
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值