当前位置:   article > 正文

PTA 21级数据结构与算法实验5——树和二叉树_本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果

本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果

7-1 还原二叉树

给定一棵二叉树的先序遍历序列和中序遍历序列,要求计算该二叉树的高度。

输入格式:

输入首先给出正整数N(≤50),为树中结点总数。下面两行先后给出先序和中序遍历序列,均是长度为N的不包含重复英文字母(区别大小写)的字符串。

输出格式:

输出为一个整数,即该二叉树的高度。

输入样例:

  1. 9
  2. ABDFGHIEC
  3. FDHGIBEAC

输出样例:

5
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. typedef struct tree
  4. {
  5. char data;
  6. struct tree *left,*right;
  7. }tree;
  8. int treeheight(tree *root)//求树的高度
  9. {
  10. if(root==NULL)
  11. return 0;
  12. else
  13. {
  14. int len1=treeheight(root->left);
  15. int len2=treeheight(root->right);
  16. return len1>len2?len1+1:len2+1;
  17. }
  18. }
  19. tree* createtree(char *pre,char *in,int n)//建立树,pre是先序输入的,in是中序输入
  20. {
  21. tree *root;
  22. root=(tree *)malloc(sizeof(struct tree));
  23. if(n==0)
  24. return NULL;
  25. int i;
  26. root->data=pre[0];
  27. for(i=0;i<n;i++)
  28. if(in[i]==root->data)
  29. break;
  30. root->left=createtree(pre+1,in,i);
  31. root->right=createtree(pre+i+1,in+i+1,n-i-1);
  32. return root;
  33. }
  34. int main()
  35. {
  36. int n;
  37. scanf("%d",&n);
  38. char str1[n];
  39. char str2[n];
  40. scanf("%s%s",str1,str2);
  41. char *pre=str1;
  42. char *in=str2;
  43. tree *root=createtree(pre,in,n);
  44. printf("%d",treeheight(root));
  45. return 0;
  46. }

7-2 朋友圈

某学校有N个学生,形成M个俱乐部。每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈。一个学生可以同时属于若干个不同的俱乐部。根据“我的朋友的朋友也是我的朋友”这个推论可以得出,如果A和B是朋友,且B和C是朋友,则A和C也是朋友。请编写程序计算最大朋友圈中有多少人。

输入格式:

输入的第一行包含两个正整数N(≤30000)和M(≤1000),分别代表学校的学生总数和俱乐部的个数。后面的M行每行按以下格式给出1个俱乐部的信息,其中学生从1~N编号:

第i个俱乐部的人数Mi(空格)学生1(空格)学生2 … 学生Mi

输出格式:

输出给出一个整数,表示在最大朋友圈中有多少人。

输入样例:

  1. 7 4
  2. 3 1 2 3
  3. 2 1 4
  4. 3 5 6 7
  5. 1 6

输出样例:

4
  1. #include<bits/stdc++.h>
  2. #define N 30003
  3. using namespace std;
  4. int family[N];//朋友数组
  5. int find(int x)//查找函数
  6. {
  7. if(x==family[x])
  8. return x;
  9. return family[x]=find(family[x]);
  10. }
  11. void merg(int x,int y)//并集
  12. {
  13. family[find(y)] = family[x] ;
  14. }
  15. int main()
  16. {
  17. int i,j,n,m,kn;
  18. scanf("%d %d",&n,&m);
  19. for(i=1;i<=n;i++)
  20. family[i]=i;//记录所有学生的编号
  21. for(i=0;i<m;i++)
  22. {
  23. scanf("%d",&kn);
  24. int tmp1,tmp2;
  25. if(kn!=0);
  26. scanf("%d",&tmp1);
  27. for(j=1;j<kn;j++)
  28. {
  29. scanf("%d",&tmp2);
  30. if(find(tmp1) != find(tmp2)) // 这句判断不能少 否则错误
  31. merg(tmp1,tmp2);//查找并集
  32. }
  33. }
  34. int maxx=0 ;
  35. map<int,int>mp;
  36. for(i = 1;i <= n ; i++)
  37. {
  38. mp[find(i)] ++ ;
  39. if(mp[find(i)] > maxx)
  40. {
  41. maxx = mp[find(i)];
  42. }
  43. }
  44. printf("%d\n",maxx);
  45. return 0 ;
  46. }

 7-3 修理牧场

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li​个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li​的总和。

但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。

请编写程序帮助农夫计算将木头锯成N块的最少花费。

输入格式:

输入首先给出正整数N(≤104),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。

输出格式:

输出一个整数,即将木头锯成N块的最少花费。

输入样例:

  1. 8
  2. 4 5 1 2 1 3 1 1

输出样例:

49
  1. //哈夫曼树
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. int main(){
  5. priority_queue <int,vector<int>,greater<int> > q;//优先队列 按照由小到大顺序
  6. int N,i,j,k,a[10000],d[10000],sum=0;
  7. scanf("%d",&N);
  8. for(i=0;i<N;i++)
  9. {
  10. scanf("%d",&a[i]);
  11. }
  12. for(i=0;i<N;i++)
  13. {
  14. q.push(a[i]);//将a[i]放入q队列中
  15. }
  16. while(!q.empty()&&q.size()!=1)//q队列不为空切长度不为1
  17. {
  18. int temp1= q.top();//先访问 再弹出
  19. q.pop();
  20. int temp2= q.top();
  21. q.pop();
  22. int temp=temp1+temp2;
  23. sum+=temp;
  24. q.push(temp);
  25. }
  26. printf("%d",sum);
  27. }

7-4 玩转二叉树

给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

  1. 7
  2. 1 2 3 4 5 6 7
  3. 4 1 3 2 6 5 7

输出样例:

4 6 1 7 5 3 2
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 50;
  4. int in[N],pre[N],level[100000];
  5. int cnt = 0;
  6. int n;
  7. void dfs(int root, int start, int end, int index)
  8. {
  9. if(start > end) return;
  10. int i = start;
  11. while(i < end && in[i] != pre[root]) i++;
  12. level[index] = pre[root];
  13. dfs(root + 1, start, i - 1, 2 * index + 2);//这里将结点换位置,将左边和右边结点换位置。
  14. dfs(root + (i - start + 1), i + 1, end, 2 * index + 1);
  15. }
  16. int main()
  17. {
  18. scanf("%d",&n);
  19. memset(level, -1, sizeof level);
  20. for(int i=0;i<n;i++) scanf("%d",&in[i]);
  21. for(int i=0;i<n;i++) scanf("%d",&pre[i]);
  22. dfs(0,0,n-1,0);
  23. for(int i=0;i<10000;i++)
  24. {
  25. if(level[i] != -1 && cnt != n - 1)
  26. {
  27. printf("%d ",level[i]);
  28. cnt++;
  29. }
  30. else if(level[i] != -1)
  31. {
  32. printf("%d",level[i]);
  33. break;
  34. }
  35. }
  36. return 0;
  37. }

7-5 根据后序和中序遍历输出先序遍历

本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。

输入格式:

第一行给出正整数N(≤30),是树中结点的个数。随后两行,每行给出N个整数,分别对应后序遍历和中序遍历结果,数字间以空格分隔。题目保证输入正确对应一棵二叉树。

输出格式:

在一行中输出Preorder: 以及该树的先序遍历结果。数字间有1个空格,行末不得有多余空格。

输入样例:

  1. 7
  2. 2 3 1 5 7 6 4
  3. 1 2 3 4 5 6 7

输出样例:

Preorder: 4 1 3 2 6 5 7
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int p[30+5];
  4. int q[30+5];
  5. int hash_temp[30+5];
  6. int k,num[30+5];
  7. int temp;
  8. void fun(int lenth, int top_p, int top_q) {
  9. if(lenth < 1) return ;
  10. num[k++] = p[top_p + lenth - 1];
  11. temp = p[top_p + lenth - 1];
  12. int len = hash_temp[temp]-top_q;
  13. fun(len, top_p, top_q);
  14. fun(lenth - len - 1, top_p + len, top_q + len + 1);
  15. }
  16. int main()
  17. {
  18. int len;
  19. cin>>len;
  20. k=0;
  21. for(int i = 0; i < len; i++)
  22. {
  23. cin>>p[i];
  24. }
  25. for(int i = 0; i < len; i++)
  26. {
  27. cin>>q[i];
  28. hash_temp[q[i]] = i;
  29. }
  30. fun(len, 0, 0);
  31. cout<<"Preorder: ";
  32. for(int i = 0; i < len - 1; i++)
  33. {
  34. cout<<num[i]<<' ';
  35. }
  36. cout<<num[len-1];
  37. return 0;
  38. }

 7-6 完全二叉树的层序遍历

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树

给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。

输入格式:

输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。

输出格式:

在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

  1. 8
  2. 91 71 2 34 10 15 55 18

输出样例:

18 34 55 71 2 10 15 91
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ENDL '\n'
  4. const int maxn = 1e6 + 10;
  5. int n, cur;
  6. int a[maxn], ans[maxn];
  7. void dfs(int i) {
  8. if (i > n) return;
  9. dfs(i * 2); //先填左子树
  10. dfs(i * 2 + 1);
  11. ans[i] = a[cur++];
  12. }
  13. int main() {
  14. cin >> n;
  15. for (int i = 1; i <= n; i++) cin >> a[i];
  16. cur = 1;
  17. dfs(1);
  18. cout << ans[1];
  19. for (int i = 2; i <= n; i++) cout << " " << ans[i];
  20. cout << ENDL;
  21. return 0;
  22. }

7-7 列出叶结点

对于给定的二叉树,本题要求你按从上到下、从左到右的顺序输出其所有叶节点。

输入格式:

首先第一行给出一个正整数 N(≤10),为树中结点总数。树中的结点从 0 到 N−1 编号。随后 N 行,每行给出一个对应结点左右孩子的编号。如果某个孩子不存在,则在对应位置给出 "-"。编号间以 1 个空格分隔。

输出格式:

在一行中按规定顺序输出叶节点的编号。编号间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

  1. 8
  2. 1 -
  3. - -
  4. 0 -
  5. 2 7
  6. - -
  7. - -
  8. 5 -
  9. 4 6

输出样例:

4 1 5
  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4. struct Node
  5. {
  6. int data;
  7. int left;
  8. int right;
  9. };
  10. int main()
  11. {
  12. int n;
  13. cin >> n;
  14. getchar(); //getchar(),吞掉回车
  15. Node tree[15]; //因为这个数组的下标就是data,所以我不需要额外的data域
  16. int checked[15] = {}; //检查根节点的
  17. for(int i = 0;i < n;i++)
  18. {
  19. char l,r;
  20. scanf("%c %c",&l,&r);
  21. getchar();
  22. if(l == '-')tree[i].left = -1;
  23. else
  24. {
  25. tree[i].left = (l - '0');
  26. checked[l - '0'] = 1;
  27. }
  28. if(r == '-')tree[i].right = -1;
  29. else
  30. {
  31. tree[i].right = (r - '0');
  32. checked[r - '0'] = 1;
  33. }
  34. }
  35. int ans[15] = {};
  36. for(int i = 0;i < n;i++)
  37. {
  38. if(checked[i] == 0)
  39. {
  40. ans[0] = i; //在这里找到了根节点,存进队列去了
  41. break;
  42. }
  43. }
  44. int k = 1; //注意一下,k是从 1 开始的
  45. for(int i = 0;i < n;i++)
  46. {
  47. if(tree[ans[i]].left != -1)ans[k++] = tree[ans[i]].left;
  48. if(tree[ans[i]].right != -1)ans[k++] = tree[ans[i]].right;
  49. }
  50. int flag = 0;
  51. for(int i = 0;i < n;i++)
  52. {
  53. if(tree[ans[i]].left == -1 && tree[ans[i]].right == -1)
  54. {
  55. if(flag)cout << " ";
  56. flag = 1;
  57. cout << ans[i];
  58. }
  59. }
  60. return 0;
  61. }

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

输入样例:

  1. 4
  2. 3 10 1 2
  3. 2 3 4
  4. 4 1 5 7 8
  5. 3 9 6 4
  6. 2
  7. 10 5
  8. 3 7

输出样例:

  1. 10 2
  2. Y
  3. N
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 1e4 + 10;
  4. int father[maxn];
  5. int find(int x) {
  6. if(x == father[x]) return x;
  7. else {
  8. father[x] = find(father[x]);
  9. return father[x];
  10. }
  11. }
  12. void merge(int x, int y) {
  13. int fx = find(x);
  14. int fy = find(y);
  15. father[fy] = fx;
  16. }
  17. int main() {
  18. int n;
  19. cin >> n;
  20. set<int>s;
  21. int data, sum, fir, ans1 = 0, ans2 = 0;
  22. for(int i = 0; i < maxn; i++) father[i] = i;
  23. for(int i = 1; i <= n; i++) {
  24. cin >> sum ;
  25. if(sum > 0) cin >> fir, s.insert(fir);
  26. for(int i = 1; i < sum; i++) {
  27. cin >> data;
  28. s.insert(data);
  29. merge(fir, data);
  30. }
  31. }
  32. ans1 = s.size();
  33. for(int i = 1; i <= ans1; i++) if(father[i] == i) ans2++;
  34. cin >> n;
  35. int x, y;
  36. cout << ans1 << " " << ans2 << endl;
  37. for(int i = 1; i <= n; i++) {
  38. cin >> x >> y;
  39. if(find(x) == find(y)) cout << 'Y' << endl;
  40. else cout << 'N' << endl;
  41. }
  42. return 0;
  43. }

7-9 建立与遍历二叉树

以字符串的形式定义一棵二叉树的先序序列,若字符是‘#’, 表示该二叉树是空树,否则该字符是相应结点的数据元素。读入相应先序序列,建立二叉链式存储结构的二叉树,然后中序遍历该二叉树并输出结点数据。

输入格式:

字符串形式的先序序列(即结点的数据类型为单个字符)

输出格式:

中序遍历结果

输入样例:

在这里给出一组输入。例如:

ABC##DE#G##F###

输出样例:

在这里给出相应的输出。例如:

CBEGDFA
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<malloc.h>
  4. typedef struct tree
  5. {
  6. char data;
  7. struct tree *left;
  8. struct tree *right;
  9. }tree;
  10. char ch[10005];
  11. int i=0;
  12. tree *creat()
  13. {
  14. char op=ch[i++];
  15. if(op=='#')
  16. return NULL;
  17. tree *root;
  18. root=(tree*)malloc(sizeof(tree));
  19. root->data=op;
  20. root->left=creat();
  21. root->right=creat();
  22. return root;
  23. }
  24. void InorderTraversal(tree *root)//中序遍历,先遍历左子树,再输出根节点,再遍历右子树
  25. {//(左子树->根->右子树)
  26. if(root==NULL)
  27. {
  28. return ;
  29. }
  30. InorderTraversal(root->left);
  31. printf("%c",root->data);
  32. InorderTraversal(root->right);
  33. }//中序可以记为:空返回空,左递归,输出,右递归;
  34. int main()
  35. {
  36. scanf("%s",ch);
  37. tree *root;
  38. root=creat();
  39. InorderTraversal(root);
  40. return 0;
  41. }

7-10 交换二叉树中每个结点的左孩子和右孩子

以二叉链表作为二叉树的存储结构,交换二叉树中每个结点的左孩子和右孩子。

输入格式:

输入二叉树的先序序列。

提示:一棵二叉树的先序序列是一个字符串,若字符是‘#’,表示该二叉树是空树,否则该字符是相应结点的数据元素。

输出格式:

输出有两行:

第一行是原二叉树的中序遍历序列;

第二行是交换后的二叉树的中序遍历序列。

输入样例:

ABC##DE#G##F###

输出样例:

CBEGDFA

AFDGEBC

  1. #include <iostream>
  2. using namespace std;
  3. typedef struct Node {
  4. char data;
  5. struct Node *left, *right;
  6. } Node, *Tree;
  7. Tree create() {
  8. char ch;
  9. Tree tree = NULL;
  10. if (scanf("%c", &ch)) {//当有输入时
  11. if (ch != '#') {
  12. tree = (Tree)malloc(sizeof(Node));
  13. tree->data = ch;
  14. tree->left = create();
  15. tree->right = create();
  16. } else {
  17. tree = NULL;
  18. }
  19. }
  20. return tree;
  21. }
  22. void order(Tree tree) {
  23. if (!tree)
  24. return;
  25. order(tree->left);
  26. printf("%c", tree->data);
  27. order(tree->right);
  28. }
  29. void swap(Tree tree) {
  30. if (!tree)
  31. return;
  32. if (!tree->left && !tree->right)
  33. return;
  34. Tree tmp = tree->left;
  35. tree->left = tree->right;
  36. tree->right = tmp;
  37. swap(tree->left);
  38. swap(tree->right);
  39. }
  40. int main() {
  41. Tree tree = create();
  42. order(tree);
  43. cout << endl;
  44. swap(tree);
  45. order(tree);
  46. return 0;
  47. }

7-11 树的遍历

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

  1. 7
  2. 2 3 1 5 7 6 4
  3. 1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2
  1. #include <stdio.h>
  2. int s[31],c[31],l,i,M[31];
  3. //第一步:如果数组大小为零的话,说明是空了
  4. //第二步:如果数组不为空,那么找后序数组最后一个元素
  5. //第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
  6. //第四步:切割中序数组,切成中序左数组和中序右数组
  7. //第五步:切割后序数组,切成后序左数组和后序右数组
  8. //第六步:递归处理左区间和右区间
  9. void la(int l,int r,int st,int ed,int f)
  10. {
  11. if(l<=r&&st<=ed)
  12. {
  13. M[f]=c[ed];
  14. for(int i=l; i<=r; i++)
  15. if(c[ed]==s[i])
  16. {
  17. la(l,i-1,st,st+i-1-l,2*f+1),la(i+1,r,st+i-l,ed-1,2*f+2);
  18. return ;
  19. }
  20. }
  21. }
  22. int main()
  23. {
  24. scanf("%d",&l);
  25. for(i=0;i<l;i++)
  26. scanf("%d",&c[i]);
  27. for(i=0;i<l;i++)
  28. scanf("%d",&s[i]);
  29. la(0,l-1,0,l-1,0);
  30. int f=0;
  31. for(auto X:M)
  32. {
  33. if(f)
  34. printf(" ");
  35. printf("%d",X.second);
  36. f+1;
  37. }
  38. return 0;
  39. }

 c语言战士的落幕

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/663451
推荐阅读
相关标签
  

闽ICP备14008679号