先序序列第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]
表示后序序列的最后一个节点(根节点)等于先序序列的第一个节点
先序:ABDEC
后序:DEBCA
初始调用
传入pre,0,4,post,0,4
0-4表示完整的先序和后序序列的下标区间
处理根节点
-
当前递归处理的根节点
将prel1的A放入后序的最后一个位置posth2
-
计算half
half=(h1 - l1) / 2 = (4 - 0) / 2 = 2
左子树节点数为half = 2
子树区间划分:
先序左子树:pre1-2
先序右子树:pre3-4
后序左子树:post0-1
后序右子树:post2-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
-
当前递归处理的根节点
prel1 = B,把B放入后序的最后一个位置posth2
-
计算half
half = (h1 - l1) / 2 = (3 - 1) / 2 = 1;
左子树节点数为 half = 1。
子树区间划分:
左子树(先序):pre2-2
右子树(先序):pre3-3
左子树(后序):post0-0
右子树(后序):post1-1
-
递归调用左右子树
PreToPost(pre, 2, 2, post, 0, 0); // 左子树
PreToPost(pre, 3, 3, post, 1, 1); // 右子树
处理左子树的左子树
传入pre,2,2,post,0,0
-
prel1 = D,将D放入posth2
-
区间检查,左右子树都为空,递归结束
处理左子树的右子树
传入pre。3,3,post,1,1
- prel1 = E,将E放入posth2
处理右子树
传入pre,4,4,post,2,3
-
当前递归处理的根节点
prel1=C,将C放入posth2
-
区域检查
左子树和右子树均为空,递归结束
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);}
}