已知二叉树的先序排列和中序排列,重构该二叉树,并输出该树的后序遍历

本文详细介绍了如何通过先序遍历和中序遍历数组重构二叉树的过程,并提供了完整的C语言实现代码。通过递归的方式,逐步分解问题,直至构建出完整的二叉树结构。

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

###前言
好久没写算法题,第一次碰到居然懵了,心里想着用递归用递归,却怎么也想不出思路来。
###实现

  • 思路

举例:
[外链图片转存失败(img-NbnAnlRo-1562160174655)(//img-blog.youkuaiyun.com/20180313191420952?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L2xpa2V3aW5kMTk5Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]

前序遍历为:1 2 4 5 3 6 7
中序遍历为:4 2 5 1 6 3 7

  1. 我们可以由先序遍历的顺序得到二叉树中节点的顺序,如从1开始,这样在中序遍历中找到1的位置的时候,在1左边的即为1节点的左子树元素(4 2 5 ),在1右边的即为1节点的右子树元素(6 3 7),这是由中序遍历的定义所决定的。

  2. 然后我们再依据先序遍历,找到下一个节点2,再从中序遍历中找到2的位置,这样中序遍历中2的左子树元素有4, 2的右子树元素只有5(这里注意,我们在查找的时候只在1的左子树元素范围内查找,即4 2 5,中序遍历中除此之外的元素我们是不涉及的)。

依次往下重复…

以上的部分就构成了我们的递归程序,那么作为递归所必须的递归出口该如何定义?

回想我们步骤中隐含的操作是遍历先序遍历,那么当给出的先序遍历数组遍历结束之后,我们的递归程序也应当结束,这可以算作一个递归出口**,再有,我们在中序遍历中给左右子树元素划范围的时候,会涉及到左边界(left)以及右边界(right),其中隐含着的条件是左边界不能大于右边界(可以等于,表示只有一个元素)。**

  • 代码
/*!Copyright (c) 2017 Cheng Ligang . All rights reserved.
 * \author: Cheng Ligang
 * \mail:   chengligang@buaa.edu.cn
 * \date:   2018/3/13
 */
#include <stdio.h>
const int max_nums = 100;
//preOrder先序遍历数组,inOrder中序遍历数组
int preOrder[max_nums], inOrder[max_nums];
int nums = 0;
//二叉树节点的定义
typedef struct BNode {
    int val;
    BNode * left_child;
    BNode * right_child;
}BTree;
//在中序遍历数组中返回对应先序遍历中item对应的位置值
int search(int item) {
    for (int i = 0; i < nums; i++) {
        if(item == inOrder[i])
            return i;
    }
    return -1;
}
//创建给定val的新节点
BNode * createNode(int val)
{
    BNode * node = new BNode;
    node->val = val;
    node->left_child = NULL;
    node->right_child = NULL;
    return node;
}
//给定当前指向先序遍历节点的下标以及该节点左右子树元素的在中序遍历中的范围(左、右边界)
//返回重构好的二叉树
BTree * createTree(int &cur_pos, int left, int right)
{
	//递归出口,遍历结束以及左边界小于右边界
    if(cur_pos > nums -1 || left>right){
		if(left>right)
			cur_pos-=1;
		return NULL
	}
    if(left == right)
        return createNode(preOrder[cur_pos]);
    int val = preOrder[cur_pos];
    int pos = search(val);
    BNode * root = createNode(val);
    //递归调用自身,同时保证遍历指针指向先序遍历中的下一个元素。
    cur_pos += 1;
    root->left_child = createTree(cur_pos, left, pos - 1);
    cur_pos += 1;
    root->right_child = createTree(cur_pos, pos + 1, right);
	//返回树的根节点
    return root;
}
//递归实现后序遍历
void printPostOrder(BNode * root)
{
    if(root == NULL)
        return ;
    printPostOrder(root->left_child);
    printPostOrder(root->right_child);
    printf("%d ", root->val);
}

int main() {
    scanf("%d", &nums);//输入元素个数
    int i = 0;
    for(i = 0; i<nums; i++) scanf("%d", &preOrder[i]);//输入先序遍历
    for(i = 0; i<nums; i++) scanf("%d", &inOrder[i]);//输入中序遍历
    int cur_pos = 0;//当前指向先序遍历下标值
    BTree * root = createTree(cur_pos, 0, nums - 1);
    printPostOrder(root);//后序遍历重构好的树
    return 0;
}
//测试数据
//7
//1 2 4 5 3 6 7
//4 2 5 1 6 3 7

测试结果:
这里写图片描述

在C语言中,如果你已经知道了二叉树序遍历(Preorder Traversal)序遍历(Inorder Traversal),可以通过这两个重构后序遍历(Postorder Traversal)。这是因为对于任何一个节点,它的后序遍历通常是左子 -> 右子 -> 节点本身。 首,我们需要三个指针分别表示当前节点、前驱节点待访问的左子后序遍历算法步骤如下: 1. 初始化后序遍历结果数组 `postorder` 长度 `size`。 2. 使用序遍历构建线索(即通过第一个元素找到根节点): - 序遍历的第一个元素作为根节点的线索。 3. 对于线索所指的节点,递归地处理左子右子: - 如果线索指向的是左子节点,那么它就是后序遍历中的下一个节点,将其添加到 `postorder` 更新线索到下一个元素。 - 如果线索指向的是右子节点,那么需要完成左子后序遍历,然后继续这个右子节点。 4. 当线索为空时,说明已经处理完了当前节点及其所有子节点,将当前节点添加到 `postorder` 的最后一位,返回 `size`。 5. 最终 `postorder[0:size-1]` 就是后序遍历的结果。 以下是一个简单的C语言实现示例: ```c #include <stdio.h> typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 从序遍历序遍历构造后序遍历 void buildPostorder(int preorder[], int inorder[], TreeNode* root, int size, int *postorder, int postSize) { if (root == NULL || size <= 0) return; // 找到根节点在中序遍历中的位置 for (int i = 0; i < size && inorder[i] != root->val; i++) ; // 递归处理左右子 buildPostorder(preorder, inorder, root->left, i, postorder, postSize); buildPostorder(preorder + i + 1, inorder + i + 1, root->right, size - (i + 1), postorder, postSize); // 将根节点添加到后序遍历的末尾 postorder[postSize++] = preorder[size - 1]; } int main() { // 示例输入:序遍历 [1, 2, 4, 5, 3, 6] // 中序遍历 [4, 2, 5, 1, 3, 6] int preorder[] = {1, 2, 4, 5, 3, 6}; int inorder[] = {4, 2, 5, 1, 3, 6}; int size = sizeof(preorder) / sizeof(preorder[0]); int postSize = 0; TreeNode* root = createTreeFromPreAndInOrder(preorder, inorder); // 根据给定创建二叉树 int postorder[size]; // 后序遍历结果数组 buildPostorder(preorder, inorder, root, size, postorder, &postSize); // 输出后序遍历结果 for (int i = 0; i < postSize; i++) { printf("%d ", postorder[i]); } return 0; } ``` 注意,这里假设有一个 `createTreeFromPreAndInOrder` 函数用于根据给定序遍历序遍历构建二叉树,你需要自定义这个函数。此外,上述代码未包含错误处理边界条件检查,实际应用时请确保适当增加。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值