PTA 21级数据结构与算法实验5—树和二叉树
7-1 还原二叉树
给定一棵二叉树的先序遍历序列和中序遍历序列,要求计算该二叉树的高度。
输入格式:
输入首先给出正整数N(≤50),为树中结点总数。下面两行先后给出先序和中序遍历序列,均是长度为N的不包含重复英文字母(区别大小写)的字符串。
输出格式:
输出为一个整数,即该二叉树的高度。
输入样例:
9
ABDFGHIEC
FDHGIBEAC
输出样例:
5
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct node {
char data;
node *l, *r;
};
char pre[N], mid[N];
node *buildTree(char pre[], char mid[], int len) {
if (len == 0) return NULL;
int k;
for (int i = 0; i < len; i++) {
if (pre[0] == mid[i]) {
k = i;
break;
}
}
node *root = new node;
root -> data = pre[0];
root -> l = buildTree(pre + 1, mid, k);
root -> r = buildTree(pre + 1 + k, mid + 1 + k, len - 1 - k);
return root;
}
int high(node *root) {
int h = 0;
if (root) h = max(high(root -> l), high(root -> r)) + 1;
return h;
}
int main() {
int n;
cin >> n;
cin >> pre >> mid;
node *root = buildTree(pre, mid, n);
cout << high(root) << endl;
return 0;
}
7-2 朋友圈
某学校有N个学生,形成M个俱乐部。每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈。一个学生可以同时属于若干个不同的俱乐部。根据“我的朋友的朋友也是我的朋友”这个推论可以得出,如果A和B是朋友,且B和C是朋友,则A和C也是朋友。请编写程序计算最大朋友圈中有多少人。
输入格式:
输入的第一行包含两个正整数N(≤30000)和M(≤1000),分别代表学校的学生总数和俱乐部的个数。后面的M行每行按以下格式给出1个俱乐部的信息,其中学生从1~N编号:
第i个俱乐部的人数Mi(空格)学生1(空格)学生2 … 学生Mi
输出格式:
输出给出一个整数,表示在最大朋友圈中有多少人。
输入样例:
7 4
3 1 2 3
2 1 4
3 5 6 7
1 6
思路 : 并查集
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3e4 + 10;
int f[N], s[N];
int Find(int x) {
while (f[x] != x) x = f[x];
return x;
}
void F(int x, int y) {
int xx = Find(x), yy = Find(y);
if (xx != yy) {
if (s[xx] > s[yy]) swap(xx, yy);
f[xx] = yy;
s[yy] += s[xx];
}
}
int main() {
int n, m;
cin >> n >> m;
fill(s + 1, s + n + 1, 1);
for (int i = 1; i <= n; i++) f[i] = i;
int x, y, len;
while (m--) {
cin >> len;
cin >> x;
for (int i = 1; i < len; i++) {
cin >> y;
F(x, y);
}
}
int Max = -1;
for (int i = 1; i <= n; i++)
Max = max(Max, s[i]);
cout << Max << endl;
return 0;
}
7-3 修理牧场
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L**i个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是L**i的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。
请编写程序帮助农夫计算将木头锯成N块的最少花费。
输入格式:
输入首先给出正整数N(≤104),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。
输出格式:
输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
代码
#include<bits/stdc++.h>
using namespace std;
// C++ STL库, 优先队列
priority_queue<int, vector<int>, greater<int>> Q;
int main() {
int n, x;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
Q.push(x);
}
int y;
int sum = 0;
while (!Q.empty() && Q.size() != 1) {
x = Q.top();
Q.pop();
y = Q.top();
Q.pop();
sum += x + y;
Q.push(x + y);
}
cout << sum << endl;
return 0;
}
7-4 玩转二叉树
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N
(≤30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
1 2 3 4 5 6 7
4 1 3 2 6 5 7
输出样例:
4 6 1 7 5 3 2
代码
#include<bits/stdc++.h>
using namespace std;
int pre[111], mid[111];
int ans[111];
int cnt = 0;
struct node {
int data;
node *l, *r;
};
node *buildTree(int pre[], int mid[], int len) {
if (len == 0) return NULL;
int k;
for (int i = 0; i < len; i++) {
if (pre[0] == mid[i]) {
k = i;
break;
}
}
node *root = new node;
root -> data = pre[0];
root -> l = buildTree(pre + 1, mid, k);
root -> r = buildTree(pre + 1 + k, mid + 1 + k, len - 1 - k);
return root;
}
void change(node *root) {
if (root) {
if (!(!root -> l && !root -> r)) swap(root -> l, root -> r);
change(root -> l);
change(root -> r);
}
}
void levorder(node *root) {
queue<node *> Q;
if (root) Q.push(root);
while (!Q.empty()) {
ans[cnt++] = Q.front() -> data;
if (Q.front()->l) Q.push(Q.front()->l);
if (Q.front()->r) Q.push(Q.front()->r);
Q.pop();
}
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> mid[i];
for (int i = 0; i < n; i++) cin >> pre[i];
node *root = buildTree(pre, mid, n);
change(root);
levorder(root);
for (int i = 0; i < cnt; i++) {
if (i == 0) cout << ans[i];
else cout << " " << ans[i];
}
return 0;
}
7-5 根据后序和中序遍历输出先序遍历
本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。
输入格式:
第一行给出正整数N(≤30),是树中结点的个数。随后两行,每行给出N个整数,分别对应后序遍历和中序遍历结果,数字间以空格分隔。题目保证输入正确对应一棵二叉树。
输出格式:
在一行中输出Preorder:
以及该树的先序遍历结果。数字间有1个空格,行末不得有多余空格。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
Preorder: 4 1 3 2 6 5 7
代码
#include<bits/stdc++.h>
using namespace std;
int mid[111], pos[111];
struct node {
int data;
node *l, *r;
};
node *buildTree(int pos[], int mid[], int len) {
if (len == 0) return NULL;
int k;
for (int i = 0; i < len; i++) {
if (mid[i] == pos[len - 1]) {
k = i;
break;
}
}
node *root = new node;
root -> data = mid[k];
root -> l = buildTree(pos, mid, k);
root -> r = buildTree(pos + k, mid + 1 + k, len - 1 - k);
return root;
}
void preorder(node *root) {
if (root) {
cout << " " << root -> data;
preorder(root->l);
preorder(root->r);
}
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> pos[i];
for (int i = 0; i < n; i++) cin >> mid[i];
node *root = buildTree(pos, mid, n);
cout << "Preorder:";
preorder(root);
return 0;
}
7-6 完全二叉树的层序遍历
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树。
给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。
输入格式:
输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。
输出格式:
在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8
91 71 2 34 10 15 55 18
输出样例:
18 34 55 71 2 10 15 91
代码
#include<bits/stdc++.h>
using namespace std;
int a[111], b[111];
int n;
int cnt = 0;
void f(int x) {
if (x <= n) {
f(x * 2);
f(x * 2 + 1);
b[x] = a[cnt++];
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
f(1);
for (int i = 1; i <= n; i++) {
if (i == 1) cout << b[i];
else cout << " " << b[i];
}
return 0;
}
7-7 列出叶结点
对于给定的二叉树,本题要求你按从上到下、从左到右的顺序输出其所有叶节点。
输入格式:
首先第一行给出一个正整数 N(≤10),为树中结点总数。树中的结点从 0 到 N−1 编号。随后 N 行,每行给出一个对应结点左右孩子的编号。如果某个孩子不存在,则在对应位置给出 "-"。编号间以 1 个空格分隔。
输出格式:
在一行中按规定顺序输出叶节点的编号。编号间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6
输出样例:
4 1 5
代码
#include<bits/stdc++.h>
using namespace std;
struct node {
int l, r;
}p[111];
vector<int> ans;
bool vis[111];
void levorder(int root) {
queue<int> Q;
if (root != -1) Q.push(root);
while (!Q.empty()) {
int x = Q.front();
if (p[x].l == -1 && p[x].r == -1) ans.push_back(x);
else {
if (p[x].l != -1) Q.push(p[x].l);
if (p[x].r != -1) Q.push(p[x].r);
}
Q.pop();
}
}
int main() {
int n;
cin >> n;
memset(p, -1, sizeof p);
char x, y;
getchar();
for (int i = 0; i < n; i++) {
scanf("%c %c", &x, &y);
if (x != '-') p[i].l = x - '0', vis[p[i].l] = 1;
if (y != '-') p[i].r = y - '0', vis[p[i].r] = 1;
getchar();
}
int root = -1;
for (int i = 0; i < n; i++) {
if (!vis[i]) {
root = i;
break;
}
}
levorder(root);
for (int i = 0; i < ans.size(); i++) {
if (i == 0) cout << ans[i];
else cout << " " << ans[i];
}
return 0;
}
7-8 部落
在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
输入格式:
输入在第一行给出一个正整数N(≤104),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:
K P[1] P[2] ⋯ P[K]
其中K是小圈子里的人数,P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过104。
之后一行给出一个非负整数Q(≤104),是查询次数。随后Q行,每行给出一对被查询的人的编号。
输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y
,否则输出N
。
输入样例:
4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
输出样例:
10 2
Y
N
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int f[N];
bool v[N];
int Find(int x) {
while (f[x] != x) x = f[x];
return x;
}
void F(int x, int y) {
int xx = Find(x), yy = Find(y);
if (xx != yy) f[xx] = yy;
}
int main() {
int n;
cin >> n;
memset(v, 0, sizeof(v));
for (int i = 1; i <= N - 10; i++) f[i] = i;
int cnt = 0;
int t, x, y;
while (n--) {
scanf("%d %d", &t, &x);
if (!v[x]) v[x] = 1, cnt++;
for (int i = 1; i < t; i++) {
scanf("%d", &y);
if (!v[y]) v[y] = 1, cnt++;
F(x, y);
}
}
int num = 0;
for (int i = 1; i <= N - 10; i++) {
if (v[i] && f[i] == i) num++;
}
cout << cnt << " " << num << endl;
int m;
cin >> m;
while (m--) {
scanf("%d %d", &x, &y);
if (Find(x) == Find(y)) printf("Y\n");
else printf("N\n");
}
return 0;
}
7-9 建立与遍历二叉树
以字符串的形式定义一棵二叉树的先序序列,若字符是‘#’, 表示该二叉树是空树,否则该字符是相应结点的数据元素。读入相应先序序列,建立二叉链式存储结构的二叉树,然后中序遍历该二叉树并输出结点数据。
输入格式:
字符串形式的先序序列(即结点的数据类型为单个字符)
输出格式:
中序遍历结果
输入样例:
ABC##DE#G##F###
输出样例:
CBEGDFA
代码
#include<bits/stdc++.h>
using namespace std;
struct node {
char data;
node *l, *r;
};
char st[100010];
int cnt = 0;
node *buildTree(node *root) {
if (st[cnt] == '#') {
root = NULL;
cnt++;
}
else {
root = new node;
root->data = st[cnt++];
root->l = buildTree(root->l);
root->r = buildTree(root->r);
}
return root;
}
void midorder(node *root) {
if (root) {
midorder(root->l);
cout << root->data;
midorder(root->r);
}
}
int main() {
cin >> st;
node *root;
root = buildTree(root);
midorder(root);
return 0;
}
7-10 交换二叉树中每个结点的左孩子和右孩子
以二叉链表作为二叉树的存储结构,交换二叉树中每个结点的左孩子和右孩子。
输入格式:
输入二叉树的先序序列。
提示:一棵二叉树的先序序列是一个字符串,若字符是‘#’,表示该二叉树是空树,否则该字符是相应结点的数据元素。
输出格式:
输出有两行:
第一行是原二叉树的中序遍历序列;
第二行是交换后的二叉树的中序遍历序列。
输入样例:
ABC##DE#G##F###
输出样例:
CBEGDFA
AFDGEBC
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct node {
char data;
node *l, *r;
};
int cnt = 0;
char st[N];
node *buildTree(node *root) {
if (st[cnt] == '#') {
root = NULL;
cnt++;
} else {
root = new node;
root -> data = st[cnt++];
root -> l = buildTree(root -> l);
root -> r = buildTree(root -> r);
}
return root;
}
void change(node *root) {
if (root) {
swap(root -> l, root -> r);
change(root -> l);
change(root -> r);
}
}
void midorder(node *root) {
if (root) {
midorder(root -> l);
cout << root -> data;
midorder(root -> r);
}
}
int main() {
cin >> st;
node *root;
root = buildTree(root);
midorder(root);
cout << endl;
change(root);
midorder(root);
cout << endl;
return 0;
}
7-11 树的遍历
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
代码
#include <bits/stdc++.h>
using namespace std;
int mid[111], pos[111];
vector<int> ans;
struct node {
int data;
node *l, *r;
};
node *buildTree(int pos[], int mid[], int len) {
if (len == 0) return NULL;
int k;
for (int i = 0; i < len; i++) {
if (mid[i] == pos[len - 1]) {
k = i;
break;
}
}
node *root = new node;
root->data = mid[k];
root->l = buildTree(pos, mid, k);
root->r = buildTree(pos + k, mid + 1 + k, len - 1 - k);
return root;
}
void levorder(node *root) {
queue<node *> Q;
if (root) Q.push(root);
while (!Q.empty()) {
ans.push_back(Q.front() -> data);
if (Q.front()->l) Q.push(Q.front()->l);
if (Q.front()->r) Q.push(Q.front()->r);
Q.pop();
}
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> pos[i];
for (int i = 0; i < n; i++) cin >> mid[i];
node *root;
root = buildTree(pos, mid, n);
levorder(root);
for (int i = 0; i < ans.size(); i++) {
if (i == 0) cout << ans[i];
else cout << " " << ans[i];
}
return 0;
}
PTA 21级数据结构与算法实验5—树和二叉树的更多相关文章
- 【数据结构与算法】002—树与二叉树(Python)
概念 树 树是一类重要的非线性数据结构,是以分支关系定义的层次结构 定义: 树(tree)是n(n>0)个结点的有限集T,其中: 有且仅有一个特定的结点,称为树的根(root) 当n>1时 ...
- 数据结构与算法实验题 6.1 s_sin’s bonus
数据结构与算法实验题 6.1 s_sin's bonus ★实验任务 正如你所知道的 s_sin 是一个非常贪玩的人 QAQ(如果你非常讨厌他请直接从第二段开 始看),并且令人感到非常遗憾的是,他是一 ...
- 数据结构与算法实验题 9.1 K 歌 DFS+剪枝
数据结构与算法实验题 K 歌 ★实验任务 3* n 个人(标号1~ 3 * n )分成 n 组 K 歌.有 m 个 3 人组合,每个组合都对应一个分数,你能算出最大能够得到的总分数么? ★数据输入 输 ...
- 数据结构与算法实验题 4.2 Who is the strongest
数据结构与算法实验题 4.2 Who is the strongest ★实验任务 在神奇的魔法世界,召唤师召唤了一群的魁偶.这些魁偶排成一排,每个魁偶都有一个 战斗值.现在该召唤师有一个技能,该技能 ...
- HDU 3791 二叉搜索树 (数据结构与算法实验题 10.2 小明) BST
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3791 中文题不说题意. 建立完二叉搜索树后进行前序遍历或者后序遍历判断是否一样就可以了. 跟这次的作业第 ...
- 【数据结构和算法】Trie树简介及应用详解
作者:京东物流 马瑞 1 什么是Trie树 1.1 Trie树的概念 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经 ...
- Java数据结构和算法(十):二叉树
一.简介 二叉树是树这种数据结构的一员,后面我们还会介绍红黑树,2-3-4树等数据结构.那么为什么要使用树?它有什么优点? 前面我们介绍数组的数据结构,我们知道对于有序数组,查找很快,并介绍可以通过二 ...
- Java数据结构和算法(七)--AVL树
在上篇博客中,学习了二分搜索树:Java数据结构和算法(六)--二叉树,但是二分搜索树本身存在一个问题: 如果现在插入的数据为1,2,3,4,5,6,这样有序的数据,或者是逆序 这种情况下的二分搜索树 ...
- 数据结构与算法实验题6.1 s_sin’s bonus byFZuer
玩家从n 个点n-1 条边的图,从节点1 丢下一个小球,小球将由于重力作用向下落,而从小球所在点延伸出的每一条边有一个值pi 为小球通过该条边的概率(注意从同一个节点向下延伸的所有边的pi 的和可以小 ...
- 数据结构与算法实验题7.1 M 商人的求救
问题描述:A 国正面临着一场残酷的战争,城市被支持不同领导的两股势力占据,作为一个商人,M先生并不太关心政治,但是他知道局势很严重,他希望你能救他出去.M 先生说:“为了安全起见,我们的路线最多只能包 ...
随机推荐
- TypeScript 学习笔记 — 数组常见的类型转换操作记录(十四)
获取长度 length type LengthOfTuple<T extends any[]> = T["length"]; type A = LengthOfTupl ...
- JavaFx 生成二维码工具类封装
原文地址: JavaFx 生成二维码工具类封装 - Stars-One的杂货小窝 之前星之音乐下载器有需要生成二维码功能,当时用的是一个开源库来实现的,但是没过多久,发现那个库依赖太多,有个http- ...
- Sementic Kernel 案例之网梯科技在线教育
2023年4月25日,微软公布了2023年第一季度财报,营收528亿美元, 微软CEO纳德称,「世界上最先进的AI模型与世界上最通用的用户界面--自然语言--相结合,开创了一个新的计算时代.」该公司有 ...
- FFmpeg开发笔记(二)搭建Windows系统的开发环境
由于Linux系统比较专业,个人电脑很少安装Linux,反而大都安装Windows系统,因此提高了FFmpeg的学习门槛,毕竟在Windows系统搭建FFmpeg的开发环境还是比较麻烦的.不过若有已经 ...
- iframe分栏拖拽伸缩例子
这个标题有些绕口,鄙人愚笨,实在找不到一个比较准确的说法,总之就是: 一个页面内显示多个iframe,一个变宽,另一个就变窄,一个变高,另一个就变矮的这种可自由伸缩的效果.它们之间有一个可多拽的分隔条 ...
- 【Xpath】 xpath语法总结
节点选取 表达式 描述 用法 说明 nodename 选取此节点的所有子节点 div 选取div下的所有标签 // 从全局节点中选择节点,任意位置均可 //div 选取整个HTML页面的所有div标签 ...
- 2023-05-11:给你一个 m x n 的二进制矩阵 grid, 每个格子要么为 0 (空)要么为 1 (被占据), 给你邮票的尺寸为 stampHeight x stampWidth。 我们想将
2023-05-11:给你一个 m x n 的二进制矩阵 grid, 每个格子要么为 0 (空)要么为 1 (被占据), 给你邮票的尺寸为 stampHeight x stampWidth. 我们想将 ...
- 2022-10-30:给你一个长度为 n 的整数数组 rolls 和一个整数 k 。 你扔一个 k 面的骰子 n 次,骰子的每个面分别是 1 到 k , 其中第 i 次扔得到的数字是 rolls[i]
2022-10-30:给你一个长度为 n 的整数数组 rolls 和一个整数 k . 你扔一个 k 面的骰子 n 次,骰子的每个面分别是 1 到 k , 其中第 i 次扔得到的数字是 rolls[i] ...
- 2020-11-04:java里,总体说一下集合框架。
福哥答案2020-11-04: 福哥口诀法:收马李色坤(Collection.Map.List.Set.Queue).李矢数链写(List:Vector矢量.ArrayList数组.LinkedLis ...
- 2022-07-24:以下go语言代码输出什么?A:[]int{};B:[]int(nil);C:panic;D:编译错误。 package main import ( “fmt“ ) f
2022-07-24:以下go语言代码输出什么?A:[]int{}:B:[]int(nil):C:panic:D:编译错误. package main import ( "fmt" ...