数据结构与算法A实验五树和二叉树(C语言参考代码)

7-1 还原二叉树 (25 分)
给定一棵二叉树的先序遍历序列和中序遍历序列,要求计算该二叉树的高度。

输入格式:

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

输出格式:

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

输入样例:

9
ABDFGHIEC
FDHGIBEAC

输出样例:

5

Code:

#include <stdio.h>
#include <stdlib.h>

char qian[55], zhong[55];

typedef struct Node
{
    char data;
    struct Node *left;
    struct Node *right;
} node;

node *create(int n, char qian[], char zhong[])
{
    node *root;
    if (n == 0)
        root = NULL;
    else
    {
        int i;
        root = (node *)malloc(sizeof(node));
        root->data = qian[0];
        for (i = 0; i < n; i++)
        {
            if (zhong[i] == qian[0])
                break;
        }
        root->left = create(i, qian + 1, zhong);
        root->right = create(n - i - 1, qian + i + 1, zhong + i + 1);
    }
    return root;
}

int max(int a, int b)
{
    return a >= b ? a : b;
}

int height(node *root)
{
    if (root == NULL)
        return 0;
    else
    {
        int hl = height(root->left);
        int hr = height(root->right);
        return max(hl, hr) + 1;
    }
}

int main()
{
    int n;
    node *root;
    scanf("%d %s %s", &n, qian, zhong);
    root = (node *)malloc(sizeof(node));
    root = create(n, qian, zhong);
    printf("%d\n", height(root));
    return 0;
}

7-2 朋友圈 (25 分)
某学校有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

Code:

#include <stdio.h>

#define MAX 30005

int fa[MAX], num[MAX], ans;

int Find(int x)
{
    if (x == fa[x])
        return x;
    else
    {
        fa[x] = Find(fa[x]);
        return fa[x];
    }
}

void Union(int x, int y)
{
    int X = Find(x);
    int Y = Find(y);
    if (X != Y)
    {
        fa[X] = Y;
        num[Y] = num[X] + num[Y];
        if (num[Y] >= ans)
            ans = num[Y];
    }
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        fa[i] = i;
        num[i] = 1;
    }
    while (m--)
    {
        int k;
        scanf("%d", &k);
        int tmp[1005];
        int cnt = 0;
        while (k--)
            scanf("%d", &tmp[cnt++]);
        for (int i = 0; i < cnt - 1; i++)
            Union(tmp[i], tmp[i + 1]);
    }
    if (ans == 0)
        ans++;
    printf("%d\n", ans);
    return 0;
}

7-3 修理牧场 (25 分)
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要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

Code:

#include <stdio.h>

#define INF 0x3f3f3f3f

int a[10005], n;

int findMin()
{
    int min = INF;
    for (int i = 0; i < n; i++)
        if (min > a[i])
            min = a[i];
    return min;
}

void delete (int x)
{
    for (int i = 0; i < n; i++)
    {
        if (a[i] == x)
        {
            a[i] = INF;
            return;
        }
    }
}

void add(int x)
{
    for (int i = 0; i < n; i++)
    {
        if (a[i] == INF)
        {
            a[i] = x;
            return;
        }
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    int sum = 0;
    for (int 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;
}

参考:https://blog.csdn.net/VistorsYan/article/details/103437448

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

输入格式:

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

Code:

#include <stdio.h>
#include <stdlib.h>

int zhong[35], hou[35];

typedef struct Node
{
    int data;
    struct Node *left;
    struct Node *right;
} node;

node *create(int n, int zhong[], int hou[])
{
    node *root;
    if (n == 0)
        root = NULL;
    else
    {
        int i;
        root = (node *)malloc(sizeof(node));
        root->data = hou[n - 1];
        for (i = 0; i < n; i++)
        {
            if (zhong[i] == hou[n - 1])
                break;
        }
        root->left = create(i, zhong, hou);
        root->right = create(n - i - 1, zhong + i + 1, hou + i);
    }
    return root;
}

void order(node *root)
{
    if (root)
    {
        node *q[35];
        int front = -1, rear = -1, cnt = 0;
        q[++rear] = root;
        while (rear > front)
        {
            node *t = q[++front];
            if (cnt == 0)
                printf("%d", t->data);
            else
                printf(" %d", t->data);
            cnt++;
            if (t->left)
                q[++rear] = t->left;
            if (t->right)
                q[++rear] = t->right;
        }
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &hou[i]);
    for (int i = 0; i < n; i++)
        scanf("%d", &zhong[i]);
    node *root;
    root = (node *)malloc(sizeof(node));
    root = create(n, zhong, hou);
    order(root);
    return 0;
}

7-5 部落 (25 分)
在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。

输入格式:

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

Code:

#include <stdio.h>
#include <stdbool.h>

#define MAX 10005

int fa[MAX];
bool vis[MAX];

int Find(int x)
{
    if (x == fa[x])
        return x;
    else
    {
        fa[x] = Find(fa[x]);
        return fa[x];
    }
}

void Union(int x, int y)
{
    fa[Find(x)] = Find(y);
}

int main()
{
    int n;
    int cnt = 0, number = 0;
    scanf("%d", &n);
    for (int i = 1; i <= 10000; i++)
        fa[i] = i;
    while (n--)
    {
        int k;
        scanf("%d", &k);
        int tmp[MAX];
        int t = 0;
        while (k--)
        {
            int x;
            scanf("%d", &x);
            tmp[t++] = x;
            if (!vis[x])
            {
                number++;
                vis[x] = true;
            }
        }
        for (int i = 0; i < t - 1; i++)
            Union(tmp[i], tmp[i + 1]);
    }
    for (int i = 1; i <= number; i++)
    {
        if (fa[i] == i)
            cnt++;
    }
    printf("%d %d\n", number, cnt);
    int m;
    scanf("%d", &m);
    while (m--)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        if (Find(x) == Find(y))
            printf("Y\n");
        else
            printf("N\n");
    }
    return 0;
}

7-6 交换二叉树中每个结点的左孩子和右孩子 (20 分)
以二叉链表作为二叉树的存储结构,交换二叉树中每个结点的左孩子和右孩子。

输入格式:

输入二叉树的先序序列。

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

输出格式:

输出有两行:

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

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

输入样例:

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

输出样例:

CBEGDFA
AFDGEBC

Code:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    char data;
    struct Node *left;
    struct Node *right;
} node;

char s[55], ans[55];
int x, k;

node *create()
{
    node *root;
    char c = s[x++];
    if (c == '#')
        return NULL;
    else
    {
        root = (node *)malloc(sizeof(node));
        root->data = c;
        root->left = create();
        root->right = create();
    }
    return root;
}

void mid(node *root)
{
    if (root)
    {
        mid(root->left);
        ans[k++] = root->data;
        mid(root->right);
    }
}

int main()
{
    scanf("%s", s);
    node *root;
    root = (node *)malloc(sizeof(node));
    root = create();
    mid(root);
    for (int i = 0; i < k; i++)
        printf("%c", ans[i]);
    printf("\n");
    for (int i = k - 1; i >= 0; i--)
        printf("%c", ans[i]);
    return 0;
}

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

输入格式:

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

输出格式:

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

输入样例:

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

输出样例:

4 1 5

Code:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct Node
{
    int left;
    int right;
} node, s[15];

bool vis[15];
int ans[15], k;

void order(int root)
{
    int q[15];
    int front = -1, rear = -1;
    q[++rear] = root;
    while (rear > front)
    {
        int t = q[++front];
        if (s[t].left == -1 && s[t].right == -1)
            ans[k++] = t;
        if (s[t].left != -1)
            q[++rear] = s[t].left;
        if (s[t].right != -1)
            q[++rear] = s[t].right;
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    getchar();
    for (int i = 0; i < n; i++)
    {
        char a, b;
        scanf("%c %c", &a, &b);
        getchar();
        if (a != '-')
        {
            s[i].left = a - '0';
            vis[a - '0'] = true;
        }
        else
            s[i].left = -1;
        if (b != '-')
        {
            s[i].right = b - '0';
            vis[b - '0'] = true;
        }
        else
            s[i].right = -1;
    }
    int root;
    for (int i = 0; i < n; i++)
    {
        if (!vis[i])
        {
            root = i;
            break;
        }
    }
    order(root);
    for (int i = 0; i < k; i++)
    {
        printf("%d", ans[i]);
        if (i != k - 1)
            printf(" ");
    }
    return 0;
}

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

输入格式:

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

输出格式:

中序遍历结果

输入样例:

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

输出样例:

CBEGDFA

Code:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    char data;
    struct Node *left;
    struct Node *right;
} node;

char s[55];
int x;

node *create()
{
    node *root;
    char c = s[x++];
    if (c == '#')
        return NULL;
    else
    {
        root = (node *)malloc(sizeof(node));
        root->data = c;
        root->left = create();
        root->right = create();
    }
    return root;
}

void mid(node *root)
{
    if (root)
    {
        mid(root->left);
        printf("%c", root->data);
        mid(root->right);
    }
}

int main()
{
    scanf("%s", s);
    node *root;
    root = (node *)malloc(sizeof(node));
    root = create();
    mid(root);
    return 0;
}

7-9 完全二叉树的层序遍历 (25 分)
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 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

Code:

#include <stdio.h>
#include <stdlib.h>

int n;
int a[105];

void create(int i)
{
    if (i > n)
        return;
    create(2 * i);
    create(2 * i + 1);
    scanf("%d", &a[i]);
}

int main()
{
    scanf("%d", &n);
    create(1);
    for (int i = 1; i <= n; i++)
    {
        printf("%d", a[i]);
        if (i != n)
            printf(" ");
    }
    return 0;
}
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值