树和二叉树|数据结构-C语言

目录

1、 还原二叉树

 2、 朋友圈

 3、 修理牧场

4、 玩转二叉树

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

 6、 完全二叉树的层序遍历

 7、 列出叶结点

8、 部落

9、 建立与遍历二叉树

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

11、 树的遍历


1、 还原二叉树

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

输入格式:

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

输出格式:

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

输入样例:

9
ABDFGHIEC
FDHGIBEAC

输出样例:

5

#include<stdio.h>
#include<string.h>
typedef struct node{
    char data;
    struct node *lchild,*rchild;
}Tree;
Tree* CreatTree(char before[],char middle[],int n)
{
    if(n==0)
        return NULL;
    int i;
    Tree *tree=(Tree*)malloc(sizeof(Tree));
    tree->data=before[0];
    for(i=0;i<n;i++)
        if(middle[i]==before[0])
            break;
    tree->lchild=CreatTree(before+1,middle,i);
    tree->rchild=CreatTree(before+i+1,middle+i+1,n-i-1);
    return tree;
}
int CountTree(Tree* tree)
{
    if(tree==NULL)
        return 0;
    int l,r,max;
        l=CountTree(tree->lchild);
        r=CountTree(tree->rchild);
        if(l>r)
            return l+1;
    return r+1;
}
int main()
{
    int n,i,j;
    char before[101],middle[101];
    scanf("%d",&n);
    getchar();
    for(i=0;i<n;i++)
        scanf("%c",&before[i]);
    getchar();
    for(i=0;i<n;i++)
        scanf("%c",&middle[i]);
    Tree* tree=CreatTree(before,middle,n);
    int max=CountTree(tree);
    printf("%d",max);
}

 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

输出样例:

4
#include<stdio.h>
int pre[50000];
int find(int x)//查找x的根节点-路径压缩(优化find函数)
{
    if(x==pre[x])
        return pre[x];
    return find(pre[x]);//将所有的节点的前驱变为根节点
}
void join(int x,int y)
{
    int fx=find(x),fy=find(y);//寻找x和y的根节点
    if(fy!=fx)//若两个元素的根节点不同,则进行合并
        pre[fy]=fx;
}
int main()
{
    int n,m,i,j,k,t,first,num[300002];
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        pre[i]=i;
    while(m--)
    {
        scanf("%d%d",&k,&first);
        for(i=1;i<k;i++)
        {
            scanf("%d",&t);
            join(first,t);
        }
    }
    for(i=1;i<=n;i++)
        num[pre[find(i)]]++;
     int max = num[1];
    for(i = 1;i<=n;i++)
    {
        if(num[i]>max)
        {
            max = num[i];
        }
    }
    printf("%d",max);
}

 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块的最少花费。

输入样例:

8
4 5 1 2 1 3 1 1

输出样例:

49

#include<stdio.h>
void swap(int *a,int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
void Sort(int data[],int n)
{
    int i;
    for(i=1;i<n;i++)
    {
        if(data[i]<data[i+1])
            swap(&data[i],&data[i+1]);
    }
    for(i=1;i<n-1;i++)
    {
        if(data[i]<data[i+1])
            swap(&data[i],&data[i+1]);
    }
}
int main()
{
    int n,data[300001],i,sum=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&data[i]);
    while(n>=2)
    {
        Sort(data,n);
        data[n-1]=data[n-1]+data[n];
        sum=sum+data[n-1];
        n--;
    }
    printf("%d",sum);
}

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<stdio.h>
int pre[1000000],in[1000000],n,level[1000000]={0};
void dfs(int pre[],int in[],int n,int index)
{
    if(n==0)
        return;
    level[index]=pre[0];
    int i;
    for(i=0;i<n;i++)
        if(pre[0]==in[i])
            break;
    dfs(pre+1,in,i,index*2+2);
    dfs(pre+i+1,in+i+1,n-1-i,index*2+1);
}
int main()
{
    int num=0,i;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    scanf("%d",&in[i]);
    for(i=0;i<n;i++)
    scanf("%d",&pre[i]);
    dfs(pre,in,n,0);
    for(i=0;i<1000000;i++)
    {
        if(num!=n-1&&level[i]!=0)
        {
            printf("%d ",level[i]);
            num++;
        }
        else if(level[i]!=0)
        {
            printf("%d",level[i]);
            break;
        }
    }
}

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<stdio.h>
typedef struct node{
    int data;
    struct node *lchild,*rchild;
}Tree;
Tree* CreatTree(int in[],int post[],int n)
{
    if(n==0)
        return NULL;
    int i;
    Tree *tree=(Tree*)malloc(sizeof(Tree));
    tree->data=post[n-1];
    for(i=0;i<n;i++)
        if(post[n-1]==in[i])
            break;
    tree->lchild=CreatTree(in,post,i);
    tree->rchild=CreatTree(in+i+1,post+i,n-i-1);
    return tree;
}
void CountTree(Tree* tree)
{
    if(tree!=NULL)
    {
          printf(" %d",tree->data);
          CountTree(tree->lchild);
          CountTree(tree->rchild);
    }
    
}
int main()
{
    int n,i,j;
    int post[100001],in[100001];
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&post[i]);
    for(i=0;i<n;i++)
        scanf("%d",&in[i]);
    Tree* tree=CreatTree(in,post,n);
    printf("Preorder:");
    CountTree(tree);
}

 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<stdio.h>
int n,tree[100001];
void CreatTree(int i)
{
    if(i>n)
        return;
    CreatTree(2*i);
    CreatTree(2*i+1);
    scanf("%d",&tree[i]);
}
int main()
{
    int i;
    scanf("%d",&n);
    CreatTree(1);
    for(i=1;i<n;i++)
    {
            printf("%d ",tree[i]);
    }
    printf("%d",tree[n]);
}

 7、 列出叶结点

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

输入格式:

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

输出格式:

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

输入样例:

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

输出样例:

4 1 5

#include<stdio.h>
#include<string.h>
struct node{
    int lchild,rchild;
}t[20];
int main()
{
    int n,i,j,check[11]={0};
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        char l,r;
        getchar();
        scanf("%c %c",&l,&r);
        if(l=='-')
            t[i].lchild=-1;
        else {
            t[i].lchild=l-'0';
            check[t[i].lchild]=1;
        }
        if(r=='-')
            t[i].rchild=-1;
        else {
            t[i].rchild=r-'0';
            check[t[i].rchild]=1;
        }
    }
    int a[20];
    j=0;
    for(i=0;i<n;i++)
    {
        //只要不是根节点,就一定会是某个节点的孩子,该值一定会是1
        if(check[i]==0)
        {
            a[j++]=i;//a[0]=根节点的值
            break;
        }
    }
    i=0;
    while(i<n-1)//层次遍历树存入数组a中
    {
        if(t[a[i]].lchild!=-1)
            a[j++]=t[a[i]].lchild;
        if(t[a[i]].rchild!=-1)
            a[j++]=t[a[i]].rchild;
        i++;
    }
    int flag=0;
    for(i=0;i<n;i++)
    {
        //若左右孩子值均为-1,则不存在左右孩子,改节点为叶子节点
        if(t[a[i]].rchild==-1&&t[a[i]].lchild==-1)
        {
            if(flag==0)
                printf("%d",a[i]);
            else printf(" %d",a[i]);
            flag=1;
        }
    }
}

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<stdio.h>
#define N 100001
int pre[N];
int find(int x)
{
    if(x==pre[x])
        return x;
    else return pre[x]=find(pre[x]);
}
void join(int x,int y)
{
    int a=find(x),b=find(y);
    if(a!=b)
        pre[b]=a;
}
int main()
{
    int n,m,k,a,b,sum=0,num[N]={0},i,j;
    scanf("%d",&n);
    for(i=1;i<N;i++)
        pre[i]=i;
    for(j=0;j<n;j++)
    {
        scanf("%d",&k);
        scanf("%d",&a);
        if(num[a]==0)
        {
            num[a]=1;
            sum++;
        }
        for(i=1;i<k;i++)
        {
            scanf("%d",&b);
            if(num[b]==0)
            {
                num[b]=1;
                sum++;
            }
            join(a,b);
        }
    }
    int t=0;
    for(i=1;i<N;i++)
    {
        if(i==find(i)&&num[i])
            t++;
    }
    printf("%d %d\n",sum,t);
    scanf("%d",&m);
    int x,y;
    while(m--)
    {
        scanf("%d%d",&x,&y);
        if(find(x)==find(y))
            printf("Y\n");
        else printf("N\n");
    }
}

9、 建立与遍历二叉树

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

输入格式:

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

输出格式:

中序遍历结果

输入样例:

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

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

输出样例:

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

CBEGDFA
#include<stdio.h>
typedef struct node{
char data;
    struct node *lchild,*rchild;
}Tree;
Tree* CreatTree()
{
    Tree* tree=(Tree*)malloc(sizeof(Tree));
    char n;
    scanf("%c",&n);
    if(n!='#')
    {
        tree->data=n;
        tree->lchild=CreatTree();
        tree->rchild=CreatTree();
    }
    else tree=NULL;
    return tree;
}
void PrintTree(Tree* tree)
{
    if(tree==NULL)
        return;
    PrintTree(tree->lchild);
    printf("%c",tree->data);
    PrintTree(tree->rchild);
}
int main()
{
    Tree* tree=(Tree*)malloc(sizeof(Tree));
    tree=CreatTree();
    PrintTree(tree);
}

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

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

输入格式:

输入二叉树的先序序列。

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

输出格式:

输出有两行:

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

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

输入样例:

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

输出样例:

CBEGDFA

AFDGEBC

#include<stdio.h>
typedef struct node{
char data;
    struct node *lchild,*rchild;
}Tree;
Tree* CreatTree()
{
    Tree* tree=(Tree*)malloc(sizeof(Tree));
    char n;
    scanf("%c",&n);
    if(n!='#')
    {
        tree->data=n;
        tree->lchild=CreatTree();
        tree->rchild=CreatTree();
    }
    else tree=NULL;
    return tree;
}
void PrintTree(Tree* tree)
{
    if(tree==NULL)
        return;
    PrintTree(tree->lchild);
    printf("%c",tree->data);
    PrintTree(tree->rchild);
}
void SwapTree(Tree* tree)
{
    if(tree==NULL)
        return;
    Tree *t=tree->lchild;
    tree->lchild=tree->rchild;
    tree->rchild=t;
    SwapTree(tree->lchild);
    SwapTree(tree->rchild);
}
int main()
{
    Tree* tree=(Tree*)malloc(sizeof(Tree));
    Tree* swaptree=(Tree*)malloc(sizeof(Tree));
    tree=CreatTree();
    swaptree=tree;
    PrintTree(swaptree);
    printf("\n");
    SwapTree(tree);
    PrintTree(tree);
}

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 <stdio.h>
#include <stdlib.h>
typedef struct node
{
    int data;
    struct node *lchild,*rchild;
}Tree;
Tree *queue[100];

Tree* CreatTree(int in[], int post[], int n)
{
    if(!n) return NULL;
    Tree *T = (Tree*) malloc(sizeof(Tree));
    T->data = post[n-1]; //后序遍历的最后一个节点就是树的根节点
    //从中序遍历中找到根节点的位置
    int i;
    for(i=0; i<n; i++)
    {
        if(in[i] == post[n-1]) break;
    }
    T->lchild = CreatTree(in, post, i);
    T->rchild = CreatTree(in+i+1, post+i, n-i-1);
    return T;
}

void PrintTree(Tree *T)
{
    if(T)
    {
        int l = 0, r = 0;
        queue[r++] = T;
        while (l < r)
        {
            Tree *bt = queue[l++];
            if(bt == T) printf("%d", bt->data); //为根节点时,无空格输出
            else printf(" %d", bt->data);

            if(bt->lchild) queue[r++] = bt->lchild;
            if(bt->rchild) queue[r++] = bt->rchild;
        }
    }
}

int main()
{
    int in[100]; //中序遍历
    int post[100]; //后序遍历
    int n;
    scanf("%d", &n);
    for(int i=0; i<n; i++)
        scanf("%d", &post[i]);
    for(int i=0; i<n; i++)
        scanf("%d", &in[i]);
    Tree *T =(Tree*)malloc(sizeof(Tree));
    T=CreatTree(in, post, n);
    PrintTree(T);
    return 0;
}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值