关于树的遍历

我感觉“树的遍历”中的题目与“二叉树的遍历”思路有许多相似之处,对比对照着学习可以加深印象

 

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.树的高度

3.二叉树的高度 的三种解法

这道题答案的解法类似于 ↑ 中的第三种解法(当然↑中的 方法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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值