我感觉“树的遍历”中的题目与“二叉树的遍历”思路有许多相似之处,对比对照着学习可以加深印象
1.树的先根遍历
二叉树先序遍历是一种深度优先遍历方法,首先访问根节点,然后递归地访问左子树,最后递归地访问右子树。
核心代码是:
vector<int> pre; // 存储先序遍历结果
void preOrder(int root) {
if (root == -1) { // 如果当前节点为空,直接返回
return;
}pre.push_back(root); // 访问当前节点
preOrder(nodes[root].l); // 递归访问左子树
preOrder(nodes[root].r); // 递归访问右子树
}
本题中的数据结构是树,与二叉树有所不同,先序遍历需要使用深度优先搜索(DFS)来实现这一过程。DFS通过递归的方式,先访问当前根节点,然后依次访问其子节点,从而实现先根遍历,核心代码:
void preOrder(int root)
{
pre.push_back(root);//访问当前结点
for (int i = 0; i < nodes[root].children.size(); i++)
{
preOrder(nodes[root].children[i]);//递归访问子结点
}
}
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
using namespace std;
const int MAXN = 50;
struct Node
{
vector<int> children;
}nodes[MAXN];
vector<int> pre;
void preOrder(int root)
{
pre.push_back(root);//访问当前结点
for (int i = 0; i < nodes[root].children.size(); i++)
{
preOrder(nodes[root].children[i]);//递归访问子结点
}
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
preOrder(0);//从根节点开始先根遍历
for (int i = 0; i < pre.size(); i++)
{
printf("%d", pre[i]);
if (i < pre.size() - 1)
printf(" ");
}
return 0;
}
2.树的后根遍历
二叉树的后根遍历核心代码:
vector<int> post; // 存储后序遍历结果
void postOrder(int root) {
if (root == -1) { // 如果当前节点为空,直接返回
return;
}postOrder(nodes[root].l); // 递归访问左子树
postOrder(nodes[root].r); // 递归访问右子树
post.push_back(root); // 访问当前节点
}
对比二叉树先根和后根遍历的核心代码,可以对树的后根遍历代码顺序进行调整
核心代码:
void postOrder(int root)
{
for (int i = 0; i < nodes[root].children.size(); i++)
{
postOrder(nodes[root].children[i]);//递归访问子结点
}post.push_back(root);//访问当前结点
}
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
using namespace std;
const int MAXN = 50;
struct Node
{
vector<int> children;
}nodes[MAXN];
vector<int> post;
void postOrder(int root)
{
for (int i = 0; i < nodes[root].children.size(); i++)
{
postOrder(nodes[root].children[i]);//递归访问子结点
}
post.push_back(root);//访问当前结点
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
postOrder(0);//从根节点开始先根遍历
for (int i = 0; i < post.size(); i++)
{
printf("%d", post[i]);
if (i < post.size() - 1)
printf(" ");
}
return 0;
}
3.树的层序遍历
考虑使用BFS算法:
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 50;
struct Node
{
vector<int> children;
}nodes[MAXN];
vector<int> layer;
void layerOrder(int root)
{
queue<int> q;//创建队列用于BFS
q.push(root);//将根节点加入队列当中
while (!q.empty())
{
int front = q.front();
q.pop();
layer.push_back(front);
for (int i = 0; i < nodes[front].children.size(); i++)
{
q.push(nodes[front].children[i]);
}
}
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
layerOrder(0);//从根节点开始先根遍历
for (int i = 0; i < layer.size(); i++)
{
printf("%d", layer[i]);
if (i < layer.size() - 1)
printf(" ");
}
return 0;
}
4.树的高度
这道题答案的解法类似于 ↑ 中的第三种解法(当然↑中的 方法2 同样可以适用于这里):
有点类似于从定义出发。首先,树的高度指树中结点的最大高度
于是答案把目标转化成,树的高度= max(根左节点Height,根右节点Height)+1
核心代码:
int getHeight(int root) {
if (root == -1) { // 如果当前节点为空,返回0
return 0;
}
int leftHeight = getHeight(nodes[root].l); // 递归计算左子树高度
int rightHeight = getHeight(nodes[root].r); // 递归计算右子树高度
return max(leftHeight, rightHeight) + 1; // 返回左子树高度和右子树高度的最大值加1
}
但是这里不是二叉树,是树。所以要稍微调整思路,通用使用DFS递归思路,核心代码:
int getHeight(int root) {
int maxHeight = 0;
for (int i = 0; i < nodes[root].children.size(); i++)
{
// 递归计算每个子节点的高度
maxHeight = max(maxHeight, getHeight(nodes[root].children[i]));
}
return maxHeight + 1;// 当前节点的高度为子节点最大高度加1
}
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 50;
struct Node
{
vector<int> children;
}nodes[MAXN];
vector<int> layer;
// 递归计算节点高度
int getHeight(int root) {
int maxHeight = 0;
for (int i = 0; i < nodes[root].children.size(); i++)
{
// 递归计算每个子节点的高度
maxHeight = max(maxHeight, getHeight(nodes[root].children[i]));
}
return maxHeight + 1;// 当前节点的高度为子节点最大高度加1
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
printf("%d", getHeight(0));//计算并输出树的高度
return 0;
}
5.树的结点层号
这道题没什么好说的
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 50;
struct Node
{
vector<int> children;
}nodes[MAXN];
int layers[MAXN];
void layerOrder(int root)
{
queue<int> q;//创建队列用于BFS
q.push(root);//将根节点加入队列当中
int layer = 1;//初始层号为1
while (!q.empty())
{
int cnt = q.size();//当前层的节点数量
for (int i = 0; i < cnt; i++)
{
int front = q.front();
q.pop();
layers[front] = layer;//记录当前结点的层号
for (int i = 0; i < nodes[front].children.size(); i++)
{
q.push(nodes[front].children[i]);//将子结点加入队列
}
}
layer++;//层号加1
}
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
layerOrder(0);//从根节点开始进行层序遍历
for (int i = 0; i < n; i++)
{
printf("%d", layers[i]);
if (i < n - 1)
printf(" ");
}
return 0;
}
6.树的路径和
二叉树的核心代码:
int treePathSum = 0;
void getTreePathSum(int root, int nodePathSum)
{
if (root == -1) return; // 如果当前结点不存在,直接返回
nodePathSum += nodes[root].data;// 累加当前结点的权值到路径和
if (nodes[root].l == -1 && nodes[root].r == -1) // 如果当前结点是叶结点
{
treePathSum += nodePathSum; // 累加路径和到总路径和
}
else
{
getTreePathSum(nodes[root].l, nodePathSum);//递归遍历左子结点
getTreePathSum(nodes[root].r, nodePathSum);//递归遍历右子结点
}
}
树(本题)的核心代码:
int treePathSume = 0;
void getTreePathSum(int root, int nodePathSum)
{
//累加当前节点的权值到路径和
nodePathSum += nodes[root].data;if (nodes[root].children.empty())
{
// 如果是叶子节点,累加路径和到总路径和
treePathSume += nodePathSum;
}//如果不是叶子结点,则需要继续遍历
for (int i = 0; i < nodes[root].children.size(); i++)
{
getTreePathSum(nodes[root].children[i], nodePathSum);
}
}
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 50;
struct Node
{
int data;
vector<int> children;
}nodes[MAXN];
int treePathSume = 0;
void getTreePathSum(int root, int nodePathSum)
{
//累加当前节点的权值到路径和
nodePathSum += nodes[root].data;
if (nodes[root].children.empty())
{
// 如果是叶子节点,累加路径和到总路径和
treePathSume += nodePathSum;
}
//如果不是叶子结点,则需要继续遍历
for (int i = 0; i < nodes[root].children.size(); i++)
{
getTreePathSum(nodes[root].children[i], nodePathSum);
}
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &nodes[i].data);
}
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
getTreePathSum(0, 0);
printf("%d", treePathSume);
return 0;
}
7.树的带权路径长度
二叉树-核心代码:
//DFS函数,计算带权路径长度
void getTreeWeightedPathLength(int root, int nodePathLength)
{
if (root == -1)return;//如果结点不存在,返回
if (nodes[root].l == -1 && nodes[root].r == -1)// 如果是叶节点
{
treeWeightedPathLength += nodes[root].data * nodePathLength;//计算带权路径长度并累加
}
else
{
nodePathLength++;//路径长度加一
getTreeWeightedPathLength(nodes[root].l, nodePathLength);//递归访问左子结点
getTreeWeightedPathLength(nodes[root].r, nodePathLength);//递归访问右子结点
}
}
树-核心代码:
void getTreePathLength(int root, int edgeCount)
{
if (nodes[root].children.empty())
{
// 如果是叶子节点,累加路径和到总路径和
treePathLength += nodes[root].data*edgeCount;
}//如果不是叶子结点,则需要继续遍历
for (int i = 0; i < nodes[root].children.size(); i++)//遍历子结点
{
getTreePathLength(nodes[root].children[i], edgeCount+1);//递归调用
}
}
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 50;
struct Node
{
int data;
vector<int> children;
}nodes[MAXN];
int treePathLength = 0;
void getTreePathLength(int root, int edgeCount)
{
if (nodes[root].children.empty())
{
// 如果是叶子节点,累加路径和到总路径和
treePathLength += nodes[root].data*edgeCount;
}
//如果不是叶子结点,则需要继续遍历
for (int i = 0; i < nodes[root].children.size(); i++)//遍历子结点
{
getTreePathLength(nodes[root].children[i], edgeCount+1);//递归调用
}
}
int main()
{
int n, k, child;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &nodes[i].data);
}
for (int i = 0; i < n; i++)
{
scanf("%d", &k);
for (int j = 0; j < k; j++)
{
scanf("%d", &child);
nodes[i].children.push_back(child);
}
}
getTreePathLength(0, 0);
printf("%d", treePathLength);
return 0;
}