求二叉树排序树后序,http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_pro

本文介绍了一种从二叉排序树的先序遍历序列中恢复树结构,并进行后序遍历输出的方法。通过递归构建二叉树并实现后序遍历,最终输出后序遍历结果。

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

要给这个水题ORZ。。。。。。。我真的是弱爆了,这个烂题耽误我快一下午。。。。哭我他妈的弱爆了。。。各种跪烂。。。上午TC的一题各种跪。。。。下午又是各种ORZ。。就是给出二叉排序树的先序遍历,求后序,,,,,对先序排下序就有中序了,,,各种OTL,,,其实直接建树就行。。。然后直接后序。。。
#include<cstdio>
//#include<stdlib.h>
#include<algorithm>
#include<vector>
using namespace std;
 struct node
 {
   int data;
   node *lc,*rc;
   node(int x)
   {
     data=x;lc=rc=NULL;
   }
 };
 void build(node *t,int v)
 {
	 if(t->data>v)
	 {
		 if(t->lc==NULL)
		 {
			 t->lc=new node(v);
		 }
		 else
			 build(t->lc,v);
	 }
	 else
	 {
	    if(t->rc==NULL)
		{
		  t->rc=new node(v);
		}
		else
			build(t->rc,v);
	 }
 }
 void post(node *t)
 { 
   if(t!=NULL)
   { 
     post(t->lc);
	 post(t->rc);
	 printf("%d\n",t->data);
   }
 }
int main()
{
	  /*freopen("1.txt","r",stdin);
	freopen("2.txt","w",stdout); */ 
	int x;
	   
	scanf("%d",&x);
	node tm(x);
	  
	while(~scanf("%d",&x))
	{   build(&tm,x);
	}
	 post(&tm);
	 
 return 0;
}

<think>我们正在分析用户提供的博客文章:https://blog.csdn.net/FUNNYQian123/article/details/149479772 文章标题为:"二叉树递归算法解题技巧总结",作者:FUNNYQian123 根据文章内容,我们将总结二叉树递归的解题技巧。注意,用户要参考指定文章,所以我们需要从该文章中提取关键点。 文章主要结构: 1. 引言:介绍递归在二叉树问题中的重要性。 2. 递归三要素:递归函数的参数和返回值、终止条件、单层递归逻辑。 3. 二叉树遍历方式:前序、中序、后序,以及层序遍历(但层序遍历通常用迭代)。 4. 解题技巧:通过多个例题(如路径总和、翻转二叉树、对称二叉树等)说明如何应用递归。 5. 总结:强调多练习,理解递归思想。 我们将根据文章内容,总结出解题技巧,并按照用户要的结构进行整理。 注意:用户要使用中文,并按照指定的格式要(如数学表达式的格式)。同时,需要生成相关问题。 由于引用部分用户提供了其他文章的引用,但我们的总结应基于用户指定的博客(FUNNYQian123的博客),因此我们只引用该博客。但注意,用户提供的引用[1]到[5]并不是我们需要的,我们应忽略这些引用,除非在总结中确实需要引用其他资料(但用户指定了根据该博客文章)。 因此,我们只引用用户指定的博客,引用标识为[^1](因为用户要自然地添加引用标识,且该博客是用户指定的唯一来源)。 步骤: 1. 提取文章中的关键技巧。 2. 按照逻辑组织这些技巧。 3. 给出示例代码(文章中的代码示例主要是Java,我们可以用Java,但也可以适当用其他语言,但原文是Java,所以优先Java)。 4. 生成相关问题。 根据文章,总结以下技巧: 一、递归三要素 1. 确定递归函数的参数和返回值:明确每次递归需要传递什么参数,是否需要返回值。例如,在计算二叉树深度时,需要返回深度值;而在遍历二叉树时,可能不需要返回值,直接操作全局变量或容器。 2. 确定终止条件:通常为节点为空时返回。 3. 确定单层递归逻辑:即每一步需要做什么,比如访问当前节点(前序),然后递归左子树和右子树。 二、遍历方式的选择 - 前序遍历:先访问当前节点,再左右子树(如:翻转二叉树、深度优先遍历)。 - 中序遍历:先左子树,再当前节点,后右子树(如:二叉搜索树中可以得到有序序列)。 - 后序遍历:先左右子树,再当前节点(如:计算二叉树的高度,因为需要先知道子树的高度)。 三、解题技巧 1. 利用递归函数的返回值:例如在判断二叉树是否对称时,递归函数需要返回两个子树是否对称。 2. 递归过程中记录路径:例如在路径总和问题中,需要记录当前路径,并在满足条件时保存路径。 3. 分解问题:将大问题分解为子问题,例如构造二叉树(用中序和后序遍历构造),通过递归构建左右子树。 4. 递归与迭代的转换:虽然递归简洁,但有时需要迭代(如层序遍历)来避免递归的深度问题。 四、特殊技巧 - 剪枝:在递归过程中,如果已经知道某些分支不需要继续,则提前返回(例如在路径总和问题中,当已经找到一条路径时,可以提前结束?但原文没有明确说剪枝,但在路径总和III中提到避免重复计算,所以可以提一下优化)。 - 双递归:例如在路径总和III中,需要从每个节点开始递归,所以用了两个递归函数。 五、注意点 - 递归深度可能较大,需要注意栈溢出问题。 - 递归函数的时间复杂度和空间复杂度分析。 示例代码:文章中有多个例题的代码,我们选取一个典型的后序遍历的递归代码(计算节点个数)或者路径总和的代码。 由于文章内容较多,我们选取核心部分。 根据以上分析,我们组织回答如下:</think>根据博客文章《二叉树递归算法解题技巧总结》[^1]的内容,我整理了二叉树递归问题的核心解题技巧,结合关键要点和示例代码说明如下: --- ### 一、递归设计三要素 1. **参数与返回值设计** - **需要返回值**:当问题依赖子树的返回值(如计算高度、路径和) ```java // 示例:计算二叉树深度 int depth(TreeNode root) { if (root == null) return 0; int left = depth(root.left); // 依赖左子树返回值 int right = depth(root.right); // 依赖右子树返回值 return Math.max(left, right) + 1; } ``` - **无需返回值**:遍历类问题(如路径记录),通过参数传递容器 ```java void traverse(TreeNode root, List<Integer> path) { if (root == null) return; path.add(root.val); // 通过参数记录路径 traverse(root.left, path); traverse(root.right, path); } ``` 2. **终止条件** 必须覆盖所有递归出口,常见情况: - 节点为空(`root == null`) - 叶子节点(`root.left == null && root.right == null`) - 特定条件满足(如路径和等于目标值) 3. **单层递归逻辑** 根据遍历顺序选择处理时机: | 遍历方式 | 执行顺序 | 适用场景 | |------------|-----------------------|------------------------------| | **前序** | 根 → 左 → 右 | 翻转二叉树、先根操作 | | **中序** | 左 → 根 → 右 | 二叉搜索树排序 | | **后序** | 左 → 右 → 根 | 子树状态推导(高度、平衡性) | | **回溯** | 递归后撤销操作 | 路径记录 | --- ### 二、高频问题技巧 1. **路径问题** - **路径记录**:传递 `List<Integer> path` 参数,递归后需回溯(移除当前节点) ```java void findPath(TreeNode root, List<Integer> path, List<List<Integer>> result) { if (root == null) return; path.add(root.val); // 选择当前节点 if (isLeaf(root) && sum(path)==target) result.add(new ArrayList(path)); findPath(root.left, path, result); findPath(root.right, path, result); path.remove(path.size()-1); // 回溯:撤销选择 } ``` - **路径总和**:利用后序遍历累加值,避免额外容器[^1] 2. **树结构操作** - **翻转二叉树**:前序位置交换左右子树 ```java TreeNode invert(TreeNode root) { if (root == null) return null; // 前序位置:先交换 TreeNode temp = root.left; root.left = root.right; root.right = temp; invert(root.left); // 递归处理左 invert(root.right); // 递归处理右 return root; } ``` - **对称判断**:双递归参数比较左右子树 ```java boolean isSymmetric(TreeNode left, TreeNode right) { if (left==null && right==null) return true; if (left==null || right==null) return false; return left.val == right.val && isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left); } ``` 3. **构造二叉树** - **中序+后序构造**: 1. 后序末位为根节点值 2. 中序定位根节点,分割左右子树序列 3. 递归构建左右子树 ```java TreeNode build(int[] inorder, int[] postorder) { // 根据后序找到根,分割中序数组 TreeNode root = new TreeNode(postorder[postorder.length-1]); int idx = findIndex(inorder, root.val); // 递归构建子树 root.left = build(Arrays.copyOfRange(inorder,0,idx), Arrays.copyOfRange(postorder,0,idx)); root.right = build(Arrays.copyOfRange(inorder,idx+1,inorder.length), Arrays.copyOfRange(postorder,idx,postorder.length-1)); return root; } ``` --- ### 三、优化与避坑指南 1. **剪枝优化** - 提前终止无效递归(如路径和已超目标值时直接返回) - 示例:平衡二叉树判断中,若子树不平衡则直接返回-1 ```java int checkBalance(TreeNode root) { if (root == null) return 0; int left = checkBalance(root.left); if (left == -1) return -1; // 左子树不平衡,剪枝 int right = checkBalance(root.right); if (right == -1 || Math.abs(left-right)>1) return -1; return Math.max(left,right)+1; } ``` 2. **避免重复计算** - 使用哈希表缓存子树结果(如子树高度) - 路径总和III类问题通过前缀和减少重复遍历 3. **栈溢出预防** - 树深度过大时改用迭代法(如层序遍历用队列实现) - 尾递归优化(Java需编译器支持) --- ### 经典例题参考 | 问题类型 | 关键方法 | 力扣题号 | |------------------|------------------------------|----------| | 路径总和 | 回溯+后序遍历 | 112, 113 | | 二叉树翻转 | 前序遍历+节点交换 | 226 | | 对称二叉树 | 双递归参数比较 | 101 | | 中序+后序构造 | 递归分割序列 | 106 | | 平衡二叉树判断 | 后序遍历+剪枝 | 110 | > 完整代码实现参考原博客:[二叉树递归算法解题技巧总结](https://blog.csdn.net/FUNNYQian123/article/details/149479772)[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值