二叉树序列相关算法题|先序序列第k节点|满二叉树先序序列转后序序列(C)

先序序列第k节点的值

假设二叉树采用二叉链存储结构存储,设计一个算法,求先序遍历序列中第k(1<=k<=二叉树中的节点个数)个节点的值

算法思想

设置一个全局遍历i(初值为1)来表示进行先序遍历时,当前访问的是第几个节点。然后可以借用先序遍历的代码模型,先序遍历二叉树。
当二叉树root为空时,返回特殊字符‘#’;当k == i时,该节点即为要找的节点,返回root->data;当k != i时。递归地在左子树中查找,若找到则返回该值,否则继续递归地在右子树中查找,并返回其结果。

  • 先序遍历的顺序为:
    • 访问根节点;
    • 遍历左子树;
    • 遍历右子树。
  • 使用全局变量 i 记录当前访问的节点是第几个。
  • 如果访问到的节点的序号等于 k,则返回该节点的值。
  • 如果当前节点不是 k,则继续递归查找左子树和右子树。
  • 若查找结束仍未找到,则返回一个特殊字符 ‘#’,表示不存在第 k 个节点。
// 遍历序号的全局变量
int i = 1;
// 查找二叉树先序遍历序列中第k个节点的值
ElemType PreNode(BTNode root, int k)
{
	// 空节点,则返回特殊字符
	if (root == NULL)
		return '#';
	// 相等,则当前节点即为第k个节点
	if (i == k)
		return root->data;
	// 下一个节点
	i++;
	// 左子树中递归查找
	ch = PreNode(root->left, k);
	// 在左子树中,则返回该值
	if (ch != '#')
		return ch;
	// 在右子树中查找
	ch = PreNode(root->right, k);
		return ch;
}

如果遇到空节点,返回#,表示没有找到k节点,如果找到k节点,返回data值
如果在左子树找到k节点,直接返回,不用去右子树找

满二叉树先序序列确定后序序列

设有一棵满二叉树(所有节点值均不相同),已知其先序序列为pre,设计一个算法求其后序序列post

算法思想

对一般二叉树,仅根据先序或后序序列,不能确定另一个遍历序列。但对满二叉树,任意一个节点的左右子树均含有相等的节点数,同时,先序序列的第一个节点作为后序序列的最后一个节点,由此得到将先序序列pre[l1, ..., h1]转换为后序序列post[l2, ..., h2]的递归模型
h1小于l1时,f(pre, l1, h1, post, l2, h2) 不做任何事情
其他情况,f(pre, l1, h1, post, l2, h2) = post[h2] = pre[11]
取中间位置half = (h1 - l1)/2
pre[l1+1, l1+half]左子树转换为post[l2, l2 + half - 1]
f(pre, l1+ 1, l1+ half, post, l2, l2+half - 1)
pre[l1 + half + 1, h1]右子树转换为post[l2+ half, h2-1]
f(pre, l1+half + 1, h1, post, 12+half, h2-1)
其中,post[h2] = pre[11]表示后序序列的最后一个节点(根节点)等于先序序列的第一个节点
![[Pasted image 20241212133542.png]]

先序:ABDEC
后序:DEBCA

初始调用

传入pre,0,4,post,0,4
0-4表示完整的先序和后序序列的下标区间
![[Pasted image 20241212213521.png]]

处理根节点
  1. 当前递归处理的根节点
    将prel1的A放入后序的最后一个位置posth2
    ![[Pasted image 20241212214206.png]]

  2. 计算half
    half=(h1 - l1) / 2 = (4 - 0) / 2 = 2
    左子树节点数为half = 2
    子树区间划分:
    先序左子树:pre1-2
    先序右子树:pre3-4
    后序左子树:post0-1
    后序右子树:post2-3
    ![[Pasted image 20241212215145.png]]

  3. 递归调用左右子树

PreToPost(pre, l1 + 1, l1 + half, post, l2, l2 + half - 1); // 左子树
PreToPost(pre, l1 + half + 1, h1, post, l2 + half, h2 - 1); // 右子树

l1 + 1 = 0 + 1 = 1;l1 + half = 0 + 2 = 2;l2 = 0;l2 + half - 1 = 1
l1 + half + 1 = 0 + 2 + 1 = 3;h1 = 4;l2 + half = 0 + 2 = 2;h2 - 1 = 3;

处理左子树

传入pre,1,3,post,0,2
![[Pasted image 20241212220509.png]]

  1. 当前递归处理的根节点
    prel1 = B,把B放入后序的最后一个位置posth2
    ![[Pasted image 20241212221236.png]]

  2. 计算half
    half = (h1 - l1) / 2 = (3 - 1) / 2 = 1;
    左子树节点数为 half = 1。
    子树区间划分:
    左子树(先序):pre2-2
    右子树(先序):pre3-3
    左子树(后序):post0-0
    右子树(后序):post1-1
    ![[Pasted image 20241212222122.png]]

  3. 递归调用左右子树

PreToPost(pre, 2, 2, post, 0, 0); // 左子树
PreToPost(pre, 3, 3, post, 1, 1); // 右子树
处理左子树的左子树

传入pre,2,2,post,0,0

  1. prel1 = D,将D放入posth2
    ![[Pasted image 20241212222359.png]]

  2. 区间检查,左右子树都为空,递归结束

处理左子树的右子树

传入pre。3,3,post,1,1

  1. prel1 = E,将E放入posth2
    ![[Pasted image 20241212224742.png]]
处理右子树

传入pre,4,4,post,2,3

  1. 当前递归处理的根节点
    prel1=C,将C放入posth2
    ![[Pasted image 20241212230715.png]]

  2. 区域检查
    左子树和右子树均为空,递归结束

void PreToPost(ElemType pre[], int l1, int h1, ElemType post[], int l2, int h2)
{
	// 子树大小的一半
	int half;
	// 确保先序区间有效
	if(h1 >= l1)
	{
		// 根节点在后序数组中的位置
		post[h2] = pre[l1];
		// 左子树的大小
		half = (h1 - l1) / 2;
		// 递归处理左子树
		PreToPost(pre, l1+1, l1+half, post, l2, l2+half-1);
		// 递归处理右子树
		PreToPost(pre, l1+half+1, h1, post, l2+half, h2-1);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值