21级数据结构与算法实验5——树和二叉树(参考答案)

目录

7-1 还原二叉树

7-2 朋友圈

7-3 修理牧场

7-4 玩转二叉树

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

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

7-7 列出叶结点

7-8 部落

7-9 建立与遍历二叉树

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

7-11 树的遍历


7-1 还原二叉树

作者 DS课程组

单位 浙江大学

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

输入格式:

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

输出格式:

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

输入样例:

9

ABDFGHIEC

FDHGIBEAC

输出样例:

5

参考代码:C(gcc)

#include<stdio.h>
#include<math.h>
int dfs(char *x,char *z,int n){//传的是地址
    if(n==0)return 0;
    int i;
    for(i=0;i<n;i++)
    if(z[i]==x[0])break;//先序的第一个为根,找中序位置确定左右子树
    int left=dfs(&x[1],z,i);
    int right=dfs(&x[i+1],&z[i+1],n-1-i);
    return fmax(left,right)+1;//回溯思想左右子树最大高度+根
}
int main(){
    int n;
    scanf("%d",&n);
    char x[n+1],z[n+1];//a是先序b是中序
    scanf("%s%s",x,z);
    printf("%d\n",dfs(x,z,n));//dfs(Depth First Search)深度优先搜索算法
    return 0;
}

7-2 朋友圈

作者 DS课程组

单位 浙江大学

某学校有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

输出样例:

4

参考代码:C(gcc)

#include<stdio.h>
#include<math.h>
int f[30001],z[30001];
int find(int x){    //寻找x的根集
    if(x==f[x]) return x;
    return f[x]=find(f[x]);
}
int main(){
    int i,j,n,m,t=0,k,a,b;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
     f[i]=i;        //初始化
     z[i]=1;    //z统计朋友圈点集的个数
    }
    while(m--){    //利用树的并查集
        scanf("%d%d",&k,&a);
        for(j=1;j<k;j++){
            scanf("%d",&b);
            int x=find(a),y=find(b);
            if(x!=y)f[x]=y,z[y]+=z[x];
            a=b;
        }
    }
    for(i=1;i<=n;i++)
    t=fmax(t,z[i]);
    printf("%d",t);
    return 0;
}

7-3 修理牧场

作者 DS课程组

单位 浙江大学

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要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块的最少花费。

输入样例:

8

4 5 1 2 1 3 1 1

输出样例:

49

参考代码:C(gcc)

#include <stdio.h>
#define o 10000000//o作为无穷大
int a[10001],n;
int findmin(){
    int i,t,min=o;
    for(i=0;i<n;i++)
    if(min>a[i])min=a[i];
    return min;
}
void delete(int x)
{
    int i;
    for(i=0;i<n;i++)
    if(a[i]==x){a[i]=o;break;}
}
void add(int x){
    int i;
    for(i=0;i<n;i++)
    if(a[i]==o){a[i]=x;break;}
}
int main(){
    scanf("%d",&n);
    int i,sum=0;
    for(i=0;i<n;i++)
    scanf("%d",&a[i]);
    for(i=0;i<n-1;i++){
        int x=findmin();delete(x);
        int y=findmin();delete(y);
        sum+=x+y;
        add(x+y);
    }
    printf("%d",sum);
    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

参考代码C++(g++)

#include<stdio.h>
#include<map>
using namespace std;
int a[30],b[30],c[30]={0},con=0;
map<int,int> map1;//映射会使问题简单
void fund(int al,int ar,int bl,int br,int p){
	int i=bl;
	if(al>ar||bl>br)return;
	while(b[i]!=a[al])i++;
	map1[p]=con;
	c[con++]=b[i];
	fund(al+1,ar-(br-i)+1,bl,i-1,2*p+2);
	fund(al+(i-bl)+1,ar,i+1,br,2*p+1);
}
int main(){
	int i,n;
	scanf("%d",&n);
	for(i=0;i<n;i++)
      scanf("%d",&b[i]);
	for(i=0;i<n;i++)
      scanf("%d",&a[i]);
	fund(0,n-1,0,n-1,0);
   map<int,int>::iterator j;//迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型
	for(j=map1.begin();j!=map1.end();j++){
		if(j!=map1.begin())printf(" ");
		printf("%d",c[j->second]);		
	}
	return 0;
}

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

作者 DS课程组

单位 浙江大学

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

输入格式:

第一行给出正整数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

参考代码C(gcc)

#include<stdio.h>
#include<stdlib.h>
int a[31],b[31];
typedef struct BiNode{
	int data;
	struct BiNode *left,*right;
}BiNode,*BiTree;
BiTree find(int z1, int x1, int x2){//寻找根节点
	int i;
	BiTree head=(BiTree)malloc(sizeof(BiNode));
  head->left=head->right=NULL;
	head->data=a[z1];
	for(i=x1;i<=x2;i++){
		if(a[z1]==b[i]){
			if(i!=x1)head->left=find(z1-(x2-i)-1,x1,i-1);//有左支树
			if(i!=x2)head->right=find(z1-1,i+1,x2);//有右支树
		}
	}
	return head;
}
void OutPre(BiTree head){
	if(head){
		printf(" %d",head->data);
		OutPre(head->left);
		OutPre(head->right);
	}
}
int main()
{
	int i,n;
   scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	for(i=0;i<n;i++)
		scanf("%d",&b[i]);
	BiTree head=find(n-1,0,n-1);
  printf("Preorder:");
  OutPre(head);
	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

参考代码C(gcc)

#include<stdio.h>
struct{
	int data,l,r;
}BiTree[31];
void create(int x){//后序建树
	if(BiTree[x].l)create(BiTree[x].l);
	if(BiTree[x].r)create(BiTree[x].r);
	scanf("%d",&BiTree[x].data);
}
int main(){
    int i,n;
    scanf("%d",&n);
    for(i=1;i<=n;i++){//二叉树性质五
    	if(2*i<=n)BiTree[i].l=2*i;
    	if(2*i+1<=n)BiTree[i].r=2*i+1;
	}
	create(1);//造完后遍历
	printf("%d",BiTree[1].data);
	for(i=2;i<=n;i++)
    printf(" %d",BiTree[i].data);
	return 0;
}

7-7 列出叶结点

作者 陈越

单位 浙江大学

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

输入格式:

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

输出格式:

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

输入样例:

8

1 -

- -

0 -

2 7

- -

- -

5 -

4 6

输出样例:

4 1 5

参考代码C++(g++)

#include<bits/stdc++.h>
using namespace std;
struct tree{
	int left,right;
}a[15];
int main(){
	int n,check[15] = {0},head,p[10],j = 0;
	queue<int> q;
	cin>>n;
	for (int i = 0; i < n; i++) {
		char l,r;
		cin>>l>>r;
		a[i].left = l != '-' ? l-'0' : 12;//12表示空
		a[i].right = r != '-' ? r-'0' : 12;
		check[a[i].left] = 1;
		check[a[i].right] = 1;
	}
	for (head = 0; head < n;head++)
		if (!check[head]) break;
	q.push(head);
	while(!q.empty()) {
		int i = q.front();
		q.pop();
		if(i == 12) continue;
		if(a[i].left == 12 && a[i].right == 12)
			p[j++] = i;
		q.push(a[i].left);
		q.push(a[i].right);
	}
	cout<<p[0];
	for (int i = 1; i < j; i++)
		cout<<' '<<p[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

参考代码C++(g++)

#include<stdio.h>
#include<stack>
using namespace std;
int a[10005];
int find(int x){
    if(a[x]!=x)a[x]=find(a[x]);
    return a[x];
}//并查集
int main(){
    int n,q,k,x,y,t=0,z=0,b,c,d;
    stack<int>s;
    scanf("%d",&n);
    while(n--){
        scanf("%d",&k);
        if(k--){
        scanf("%d",&b);
        if(a[b]==0){
            a[b]=b;
            t++;
            s.push(a[b]);
           }
        }
        while(k--){
            scanf("%d",&c);
             if(a[c]==0){
             a[c]=c;
             t++;
             s.push(a[c]);
             }
        a[find(b)]=find(c);
        }
    }
    while(s.size()){
        d=s.top();
        if(a[d]==d)z++;
        s.pop();
    }
    printf("%d %d\n",t,z);
    scanf("%d",&q);
    while(q--){
        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

参考答案C(gcc)

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
  char data;
  struct node *left,*right;
}node,*tree;
int x;
char s[55];
tree create(){
  tree root;
  char a=s[x++];//从0开始,每次存储一个
  if(a=='#')return NULL;
  else {
    root=(tree)malloc(sizeof(struct node));
    root->data=a;
    root->left=create();
    root->right=create();
}
return root;
}
void outmid(tree root){
    if(root){
    outmid(root->left);
    printf("%c",root->data);
    outmid(root->right);
    }
}
int main(){
scanf("%s",s);
tree head;
head=(tree)malloc(sizeof(struct node));
head=create();
outmid(head);
return 0;
}

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

作者 陈晓梅

单位 广东外语外贸大学

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

输入格式:

输入二叉树的先序序列。

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

输出格式:

输出有两行:

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

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

输入样例:

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

输出样例:

CBEGDFA

AFDGEBC

参考答案C(gcc)

#include<stdio.h>
#include<stdlib.h>
typedef struct node{
	char data;
	struct node *lchild,*rchild;
}node,*tree;
void zxu(tree root)
{
	if(root!=NULL)
	{
		zxu(root->lchild);
		printf("%c",root->data);
		zxu(root->rchild);
	}
}
void swap(tree root)
{
	if(root!=NULL)
	{
		tree *t=root->lchild;
		root->lchild=root->rchild;
		root->rchild=t;
		swap(root->lchild);
		swap(root->rchild);
	}
}
void create(tree *root)
{
	char s;
	scanf("%c",&s);
	if(s=='#')*root=NULL;
	else{
		*root=(tree)malloc(sizeof(node));
		(*root)->data=s;
		create(&(*root)->lchild);
		create(&(*root)->rchild);
	}
}
int main()
{
	tree root;
	create(&root);
	zxu(root);
	swap(root);
	printf("\n");
	zxu(root);
	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

参考代码C(gcc)

#include<stdio.h>
#include<stdlib.h>
typedef struct node{
	int data;
	struct node *l,*r;
}node,*tree;
tree create(int *a,int *b,int n)
{
	tree T;
	T=(tree)malloc(sizeof(struct node));
	if(n<=0)
	return NULL;
	int i;
	T->data=a[n-1];
	for(i=0;i<n;i++)
	if(b[i]==a[n-1])break;
	T->l=create(a,b,i);
	T->r=create(a+i,b+i+1,n-i-1);
	return T;
}
int flag=1;
void out(tree T)
{
	struct node *p[1001];
	int start=0,end=0;
	p[start++]=T;
	while(start>end){
		if(p[end]!=0){
			if(flag){
				printf("%d",p[end]->data);
				flag=0;
			}
        else printf(" %d",p[end]->data);
		p[start++]=p[end]->l;
		p[start++]=p[end]->r;
		}
		end++;
	}
}
int main()
{
	int n,i;
	int a[50],b[50];
	tree T;
	T=(tree)malloc(sizeof(struct node));
	scanf("%d",&n);
	for(i=0;i<n;i++)
	scanf("%d",&a[i]);
	for(i=0;i<n;i++)
    scanf("%d",&b[i]);
	T=create(a,b,n);
	out(T);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

救救孩子√

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值