L2-035 完全二叉树的层序遍历(完全二叉树+后序推出层序)

文章介绍了如何通过后序遍历和完全二叉树的特性,使用DFS方法推导出层序遍历序列的过程。

本题链接:PTA | 程序设计类实验辅助教学平台

题目:

样例:

输入
8
91 71 2 34 10 15 55 18
输出
18 34 55 71 2 10 15 91

思路:

        根据题意,这是个完全二叉树 + 后序遍历,要求推出层序遍历。

        根据完全二叉树的特性: 

                        设当前结点为 n ,则该左节点 = 2 * n ,  右结点 = 2 * n + 1

        后序遍历特性:

                        对于任意节点,其左子树和右子树都会先被访问,然后才是该节点本身。

所以,对完全二叉树进行后序遍历,遍历顺序为先遍历左子树,再遍历右子树,最后访问根节点。

通过结合这两个特点,我们根据样例画个图。分析一下:

我们再根据题目要求的层序遍历,写个对应的层序数组。

结合: 完美二叉树图 + 后序数组 i 对应关系 + 层序数组 i 关系。

我们可以找到一些规律。

在这里,我们也应该吸取经验。以后遇到完美二叉树的时候,尝试将这些 图 以及对应的数组画出来,结合 完美二叉树的特点

从 后序数组 i 开始,结合 完美二叉树的特点,

                l = i << 1          等于向上查找 的 后序遍历的左结点,

                r = (i << 1) + 1    等于向上查找 的 后序遍历的右结点,

比如 :

后序遍历下标结合完美二叉树特点

i = 1,          l = 2,           r = 3
i = 2,          l = 4,           r = 5

i = 3,          l = 6,           r = 7
i = 4,          l = 8,           r = 9

i = 5,          l = 10,         r = 11

i = 6,          l = 12,         r = 13

i = 7,          l = 14,         r = 15
i = 8,          l = 16,         r = 17

通过上面的后序遍历下标结合完美二叉树特点,我们试着从 1 开始 DFS 递归向上查找:

DFS(1)

DFS(l)

DFS(r)

相应顺序

i = 1,          l = 2,           r = 3
i = 2,          l = 4,           r = 5
i = 4,          l = 8,           r = 9
i = 8,          l = 16,         r = 17
i = 5,          l = 10,         r = 11
i = 3,          l = 6,           r = 7
i = 6,          l = 12,         r = 13
i = 7,          l = 14,         r = 15

我们可以发现,每次向上查找到 根结点 i 之后,就是相应层序遍历tree的 第 i 个 对应的查找到第 n  次根节点的后序遍历的值

例如:

        到达根节点 i =  8 后:91 == a[1] = tree[8]        第 n = 1 次 查找到根节点

        到达根节点 i =  4 后:71 == a[2] = tree[4]        第 n = 2 次 查找到根节点

        到达根节点 i = 5 后:  2  == a[3] = tree[5]        第 n = 3 次 查找到根节点

        到达根节点 i = 2 后: 34 == a[4] = tree[2]        第 n = 4 次 查找到根节点

        到达根节点 i = 6 后: 10 == a[5] = tree[6]        第 n = 5 次 查找到根节点

        到达根节点 i = 7 后: 15 == a[6] = tree[7]        第 n = 6 次 查找到根节点

        到达根节点 i = 3 后: 55 == a[7] = tree[3]        第 n = 7 次 查找到根节点

        最后回到根节点 i = 1 后: 18 == a[8] = tree[1]        第 n = 8 次 查找到根节点

所以结合以上规律可以得到,完美二叉树 + 后序 推出层序规律:

      从后序数组的 1 的底结点开始向上递归查找,查找到的 第 n 个结点就是相应的下标 i 层序结点

最后代码详解如下:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#define endl '\n'
#define int long long
#define YES puts("YES")
#define NO puts("NO")
#define umap unordered_map
#define All(x) x.begin(),x.end()
#pragma GCC optimize(3,"Ofast","inline")
#define IOS std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
using namespace std;
const int N = 2e6 + 10;
inline void solve();

signed main()
{
//	freopen("a.txt", "r", stdin);
	IOS;
	int _t = 1;
//	cin >> _t;
	while (_t--)
	{
		solve();
	}
	return 0;
}
int n,t = 1,a[N],tree[N];
void DFS(int i)
{
	if(i > n) return ;//递归边界,以及找到相应的根节点了。
	
	int l = i << 1;	// 向上查找 L 左父结点
	int r = (i << 1) + 1;	// 向上查找 R 右父结点
	
	DFS(l);	// 开始向上 L 查找
	DFS(r);	// 开始向上 R 查找
	
	// 已经查找到 第 t 个结点,
	// 开始赋值相应层序遍历的 i 值为后序遍历的 a[t]值
	tree[i] = a[t++];	
}

inline void solve()
{
	cin >> n;
	for(int i = 1;i <= n;++i) cin >> a[i];
	
	DFS(1);	// 从低结点 1 开始查找
	
	// 输出答案
	for(int i = 1;i <= n;++i)
	{
		if(i != 1) cout << ' ';
		cout << tree[i];
	}
}

最后提交:​​​​​​​

<think>嗯,用户想了解完全二叉树层序遍历算法实现。首先,我需要回忆一下层序遍历的基本概念。层序遍历通常是使用队列来实现的,按照从上到下、从左到右的顺序访问每个节点。完全二叉树的结构比较特殊,除了最后一层外,其他层都是满的,并且最后一层的节点都靠左排列。不过,对于层序遍历来说,不管是不是完全二叉树,基本的算法应该是一样的,因为都是按层次遍历。 那用户提到的参考引用里提到了使用队列来实现层序遍历,所以可能用户需要具体的代码实现。不过完全二叉树有没有什么特别需要注意的地方呢?可能不需要,因为层序遍历本身不依赖于树的结构是否完全,只是按层次处理节点。不过,完全二叉树在存储时可能可以用数组来表示,比如堆结构通常用数组存储完全二叉树。这种情况下,层序遍历其实就是顺序遍历数组,但用户的问题可能还是基于节点指针形式的二叉树。 所以,我应该先解释层序遍历的一般方法,然后说明完全二叉树是否有特殊处理的地方。可能不需要,但可以提到完全二叉树层序遍历时的特点,比如当遇到第一个空节点后,后面的节点都应该是空的,否则就不是完全二叉树。不过用户的问题可能只是如何实现层序遍历,而不是验证是否是完全二叉树。 接下来,我需要给出具体的实现步骤。首先初始化队列,将根节点入队。然后循环处理队列,每次取出队首节点,访问它,然后将左右子节点入队。重复直到队列为空。这样就能按层序遍历所有节点。 然后,代码实现部分,用户给的示例是Python的快速排序,但用户可能需要用其他语言,比如C++,因为参考引用里提到了C++层序遍历。不过用户没有明确指定语言,可能需要用通用的伪代码或者Python示例。或者根据引用里的C++,可能更适合用C++代码。不过用户现在的问题可能不限制语言,所以可能需要同时给出。 不过,用户的问题是关于完全二叉树层序遍历,所以可能需要强调完全二叉树的结构特点是否影响算法。例如,在完全二叉树中,层序遍历时可以利用数组的索引特性来优化,比如父节点i的左子节点是2i+1,右子节点是2i+2。但如果是用节点指针结构实现的二叉树,可能无法直接利用这一点,所以常规的队列方法仍然适用。 因此,实现步骤应该和普通二叉树的层序遍历一样,使用队列。代码示例的话,可以选择用户提到的引用中的C++,或者Python。比如给出C++的代码,因为引用里提到了C++层序遍历。 不过用户的问题可能希望得到具体的实现,所以需要详细写出代码,并解释每一步的作用。例如: 1. 创建一个队列,将根节点入队。 2. 循环处理队列,直到队列为空。 3. 每次循环中,记录当前层的节点数量,处理该层所有节点。 4. 对于每个节点,访问其值,并将左右子节点入队。 这样可以确保按层次处理,每一层的节点被正确处理。对于完全二叉树来说,可能在处理到某一层时,节点数量不足,但算法本身不需要调整,依然可以处理。 然后,相关问题部分,可以生成关于层序遍历的应用、如何判断完全二叉树,或者层序遍历的不同实现方式等问题。 现在需要检查是否有遗漏的地方。例如,是否要处理空节点?在普通的层序遍历中,如果子节点为空,可能不会入队,但如果需要记录结构,比如在序列化时,可能需要处理空节点。不过用户的问题可能只是要求遍历存在的节点,因此不需要处理空子节点。但如果是验证完全二叉树的结构,则可能需要不同的处理方式。不过用户的问题只是层序遍历的实现,所以应该按常规方法处理。 总结,回答应该包括层序遍历的基本概念,算法步骤,代码示例(可能用C++或Python),并说明完全二叉树的结构不会影响算法的实现,因为算法本身是按层次处理,与树是否完全无关。同时,可能提到完全二叉树层序遍历中的特点,比如节点排列紧密等。</think>### 完全二叉树层序遍历实现 完全二叉树层序遍历与普通二叉树的实现方式一致,核心是通过队列逐层访问节点,步骤如下: 1. **初始化队列**:将根节点放入队列。 2. **循环处理队列**: - 记录当前层的节点数量(队列长度)。 - 依次取出当前层的所有节点并访问。 - 将每个节点的左、右子节点(若存在)加入队列。 3. **重复步骤2**,直到队列为空。 #### 代码实现(C++) ```cpp #include <queue> #include <vector> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> result; if (!root) return result; queue<TreeNode*> q; q.push(root); while (!q.empty()) { int levelSize = q.size(); vector<int> currentLevel; for (int i = 0; i < levelSize; i++) { TreeNode* node = q.front(); q.pop(); currentLevel.push_back(node->val); if (node->left) q.push(node->left); if (node->right) q.push(node->right); } result.push_back(currentLevel); } return result; } ``` #### 代码说明 - **队列的作用**:按先进先出的顺序保存待访问的节点,确保层级顺序。 - **完全二叉树的特点**:在层序遍历中,完全二叉树的非最后一层节点均需有两个子节点(最后一层左对齐),但算法无需特殊处理,仍按标准逻辑执行[^1]。 --- ### 相关问题 1. 如何判断一棵二叉树是否为完全二叉树2. 层序遍历的时间复杂度是多少?如何优化? 3. 完全二叉树在数组中的存储方式与层序遍历有何关联?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值