C++知识点总结(50):多叉树

C++知识点总结(50):多叉树由于国家的数量十分庞大 道路的建造方案有很多种 同时每种方案的修建费用难以用人工计算 国王们决定找人设计一个软件 对于给定的建造方案 计算出所需要的费用

大家好,欢迎来到IT知识分享网。

一、概念

1. 数据结构

一般情况下,我们会将数据结构分为逻辑结构和物理结构,其中逻辑结构是我们的逻辑下存储的结构,而物理结构是计算机的逻辑下存储的结构。数据结构的分类可以参见下表:

数据结构

逻辑结构

非线性结构

集合结构

同属一个集合别无其他关系

树状结构

一对多

图状结构

多对多

线性结构

一对一

物理结构

顺序结构

链式结构

单链表

双链表

循环链表

索引结构

CSP-J不涉及

散列结构

2. 树的基础知识

树是一种非线性的数据结构,每个数据都是一对多的关系,由结点和边组成。树是有 n n n n ≥ 0 n \ge 0 n0)个结点组成的具有分支和层次特性的数据集合。

树当中的数据就是 结点

结点的深度:设根结点的深度为 1 1 1(根据题目),其他根结点深度为其父节点深度加 1 1 1
结点的高度:设叶结点的高度为 1 1 1(根据题目),其他结点高度为其他子结点高度加 1 1 1

层次:从根开始,根为第 1 1 1 层,根的子结点为第 2 2 2 层,以此类推。
路径:对于树中两点不同的结点,如果从一个结点出发,自上而下沿着树中连着结点的线段能到达另一个结点,称为它们之间存在着一条路径。

一棵树中,结点最大的度就是 树的度
一个结点拥有子树的个数称为 结点的度

具有相同父结点的结点被称为 兄弟结点
某个结点的直接后继结点被称为该结点的 子结点
某个结点的直接前驱结点被称为该结点的 父结点
没有直接前驱,只有直接后继的结点为 根结点
一棵树中,度为 0 0 0 的结点称为 叶结点



n > 1 n>1 n>1 的时候,除根结点以外其余结点可以分为 m m m 个互不相交的有限集合,其中每个集合本身又是一棵树,这些集合称为这棵树的 子树
当有 m m m m ≥ 1 m\ge1 m1)个树的集合时,称呼其为 森林
n = 0 n=0 n=0 的时候,树为 空树

3. 树的相关概念

性质1: 树中的结点数等于所有结点的度之和加 1 1 1,即:
n = 1 + n 1 × 1 + n 2 × 2 + ⋯ n=1+n_1\times1+n_2\times2+\cdots n=1+n1×1+n2×2+

性质2: 树中的结点树等于所有结点个数总和,即:
n = n 0 + n 1 + n 2 + ⋯ n=n_0+n_1+n_2+\cdots n=n0+n1+n2+

性质3: n n n 个结点的树中有 n − 1 n-1 n1 条边。

4. 树的遍历

  • 先序(根)遍历
    先遍历根结点,然后遍历左子树和右子树
  • 中序(根)遍历
    先遍历左子树,再遍历根节点和右子树
  • 后序(根)遍历
    先遍历左子树,在遍历右子树和根结点
  • 层序(根)遍历
    一层一层地遍历每一层的所有结点

5. 多叉树

顾名思义,就是很多个分叉的树。后续也会称作 m m m 叉树。

性质1: 在多叉树中,第 k k k 层最多有 m k − 1 m^{k-1} mk1 个结点( k ≥ 1 k\ge1 k1)。

性质2: 多叉树的高度为 h h h,则整个 m m m 叉树最多有 m h − 1 m − 1 \frac{m^h-1}{m-1} m1mh1 个结点( h ≥ 1 h\ge1 h1)。

性质3: 根据性质2, m h − 1 m − 1 ≥ n \frac{m^h-1}{m-1} \ge n m1mh1n,那么 m h ≥ n ( m − 1 ) + 1 m^h \ge n(m-1)+1 mhn(m1)+1,因此 h ≥ log ⁡ m ( n ( m − 1 ) + 1 ) h \ge \log_m(n(m-1)+1) hlogm(n(m1)+1)

二、绘制树

1. 知先中得后

首先通过先序找到根 a,然后通过中序找到左子树(d g b)和右子树(e c h f)。

对于左子树(d g b),先序是(b d g),中序是(d g b)。通过先序找到根 b,然后通过中序找到左子树(d g)并且它没有右子树。

然后再看(d g),先序和中序都是(d g)。通过先序找到根 d,然后通过中序找到 d 的右孩子 g。

对于右子树(e c h f),先序确定根是 c,中序确定 c 的左孩子是 e,右子树是(h f),推出 h 是 f 的左孩子。

因此,后序遍历是 g d b e h f c a

2. 知中后得先

因此,先序遍历是 a b d g c e f h

3. 知先后猜结点数

【NOIP 2010 普及组 T17】 一颗二叉树的前序遍历是 ABCDEFG,后序遍历是 CBFEGDA,否则结点的左子树的结点个数可能是( A )。
A. 2
B. 3
C. 4
D. 5



我们可以直接用试的方法:

A

C

B

DEFG

4. 知中层得先

根据层序遍历得定义,那么层序得根结点,即 A 就是这棵树得根结点。根据中序,左子树是(DBE),右子树是(C)。

对于左子树,根据层序得到根结点 B,再根据中序推导出左孩子是 D,右孩子是 E。那么这棵树如下:

DBE

C

A

B

C

D

E

三、树的操作

1. 建树

首先,每个结点都可以当作是一个数组中的元素,它有三个信息:自己本身、父结点、左孩子、右孩子。所以我们可以考虑用 struct[] 来实现。

2. 转换

  1. 找根结点(先序、层序的头 / 后序的尾)
  2. 存储根结点
  3. 在中序找到左子树和右子树
  4. 在左子树重复步骤 1~4,直到碰到叶结点
  5. 在右子树重复步骤 1~4,直到碰到叶结点

根据上面的步骤,我们直到可以用递归的方法来实现。

四、例题

1. 知中层得先

#include <iostream> #include <string> using namespace std; int num[130]; // 下标: ASCII 元素: 下标 string InOd, LvOd; void dfs(string InOd) { 
    int len = InOd.length(); // 序列长度 if (len == 0) return; // 序列为空,表无子树 // 找根结点 int k; // 中序遍历中根结点的下标 char root; // 根结点 int minn = 1e8; // 最小值 for (int i = 0; i < len; i++) if (num[InOd[i]] < minn) { 
    k = i; // 更新根结点在的下标 root = InOd[i]; // 记录根结点 minn = num[InOd[i]]; // 记录最小值(找根结点核心) } // 输出先序遍历 cout << root; // 根结点 dfs(InOd.substr(0, k)); // 左子树 dfs(InOd.substr(k+1)); // 右子树 } int main() { 
    cin >> InOd >> LvOd; for (int i = 0; i < LvOd.length(); i++) num[LvOd[i]] = i; dfs(InOd); return 0; } 

2. 道路修改

题目描述

在 W 星球上有 n n n 个国家。为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通。但是每个国家的国王都很吝啬,他们只愿意修建恰好 n − 1 n−1 n1 条双向道路。
每条道路的修建都要付出一定的费用,这个费用等于道路长度乘以道路两端 的国家个数之差的绝对值。
由于国家的数量十分庞大,道路的建造方案有很多种,同时每种方案的修建费用难以用人工计算,国王们决定找人设计一个软件,对于给定的建造方案,计算出所需要的费用。请你帮助国王们设计一个这样的软件。

输入格式

输入的第一行包含一个整数 n n n,表示 W W W 星球上的国家的数量,国家从 1 1 1 n n n 编号。
接下来 n – 1 n–1 n–1 行描述道路建设情况,其中第 i i i 行包含三个整数 a i , b i a_i,b_i ai,bi c i c_i ci ,表示第 i i i 条双向道路修建在 a i a_i ai b i b_ i bi 两个国家之间,长度为 c i c_i ci

输出格式

输出一个整数,表示修建所有道路所需要的总费用。

输入样例#1

6 1 2 1 1 3 1 1 4 2 6 3 1 5 2 1 

输出样例#1

20 

数据规模与约定

对于 100 % 100\% 100% 的数据, 1 ≤ a i , b i ≤ n 1\le a_i,b_i\le n 1ai,bin 0 ≤ c ≤ 1 0 6 0\le c\le 10^6 0c106 2 ≤ n ≤ 1 0 5 2\le n\le 10^5 2n105

我们可以将题目换一种说法:求从第 1 1 1 个结点为根结点的总结点数。

#include <iostream> #include <vector> #include <cmath> using namespace std; int n; int a, b, c; int len[]; // 每个点到父结点的路径长度 int cnt[]; // 每个点为根的结点数 long long ans; struct Node { 
    vector<int> adj; // 邻结点数组 vector<int> w; // 和邻结点的长度差 } tree[]; // 计算以 id 为根子树的结点数 cnt[id] void dfs(int id, int father) { 
    cnt[id] = 1; // 自己本身 int len1 = tree[id].adj.size(); // 邻结点数组的长度 for (int i = 0; i < len1; i++) // 遍历 tree[id] 的所有邻结点 { 
    int son = tree[id].adj[i]; if (son == father) continue; // 碰到叶结点 len[son] = tree[id].w[i]; // 更新长度 dfs(son, id); cnt[id] += cnt[son]; // 增加结点数 } } int main() { 
    cin >> n; for (int i = 1; i < n; i++) { 
    cin >> a >> b >> c; tree[a].adj.push_back(b), tree[a].w.push_back(c); tree[b].adj.push_back(a), tree[b].w.push_back(c); } dfs(1, 0); for (int i = 2; i <= n; i++) ans += (long long)len[i]*abs(n-cnt[i]*2); cout << ans; return 0; } 

3. 最大子树和

题目描述

输入格式

第一行一个整数 N N N 1 ≤ N ≤ 16000 1≤N≤16000 1N16000)。表示原始的那株花卉上共 N N N 朵花。
第二行有 N N N 个整数,第III个整数表示第III朵花的美丽指数。
接下来 N − 1 N−1 N1 行每行两个整数 a , b a,b a,b,表示存在一条连接第 a a a 朵花和第 b b b 朵花的枝条。

输出格式

一个数,表示一系列“修剪”之后所能得到的”美丽指数”之和的最大值。保证绝对值不超过

输入样例1

7 -1 -1 -1 1 1 1 0 1 4 2 5 3 6 4 7 5 7 6 7 

输出样例1

3 

数据说明

对于 100 % 100\% 100% 的数据,有 N ≤ 16000 N≤16000 N16000

#include <iostream> #include <vector> using namespace std; int n; int ans = 0xc0c0c0c0; struct Node { 
    vector<int> adj; int w; int max_w; // 以当前结点为根的子树的最大美丽指数 } tree[]; void dfs(int id, int father) { 
    tree[id].max_w = tree[id].w; for (int son : tree[id].adj) { 
    if (son == father) continue; dfs(son, id); if (tree[son].max_w > 0) tree[id].max_w += tree[son].max_w; } } int main() { 
    cin >> n; for (int i = 1; i <= n; i++) cin >> tree[i].w; for (int i = 1, u, v; i < n; i++) { 
    cin >> u >> v; tree[u].adj.push_back(v); tree[v].adj.push_back(u); } dfs(1, 0); for (int i = 1; i <= n; i++) ans = max(ans, tree[i].max_w); cout << ans; return 0; } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118976.html

(0)
上一篇 2025-11-08 22:20
下一篇 2025-11-08 22:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信