数据结构—树和二叉树

目录

完全二叉树的层序遍历

还原二叉树

树层次遍历

列出叶结点 

朋友圈

部落 

修理牧场

哈夫曼树 


 完全二叉树的层序遍历

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 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 a[31],n;
void f(int x){
    if(x>n)return ;
    f(2*x);
    f(2*x+1);
    scanf("%d",&a[x]);
}
int main(){
    //int n;
    scanf("%d",&n);
    f(1);
    printf("%d",a[1]);
    for(int i=2;i<=n;i++)
    {
        printf(" %d",a[i]);
    }
    return 0;
}

还原二叉树

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

输入格式:

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

输出格式:

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

输入样例:

9
ABDFGHIEC
FDHGIBEAC

输出样例:

5
#include<stdio.h>
#include<math.h>
int creat(char *a,char *b,int n){//传的是地址
    if(n<=0)return 0;
    int i;
    for(i=0;i<n;i++){
        if(a[0]==b[i])
            break;
    }
    int left=creat(&a[1],b,i);//(树在先序遍历中的位置,树在中序遍历中的位置,树的长度)
    int right=creat(&a[i+1],&b[i+1],n-1-i);
    return fmax(left,right)+1;//子树的最大高度+1
}
int main(){
    int i,n;
    scanf("%d",&n);
    char a[51],b[51];
    scanf("%s%s",a,b);
    int c=creat(a,b,n);
    printf("%d",c);
    return 0;
}

 树层次遍历

我们已知二叉树与其自然对应的树相比,二叉树中结点的左孩子对应树中结点的左孩子,二叉树中结点的右孩子对应树中结点的右兄弟。进而我们可以利用“基于带空指针信息的先根序列构建二叉树”的方法来构建其对应的树的左孩子-右兄弟存储结构。如8 5 1 0 6 0 2 0 0 3 4 0 0 7 0 0 0对应图1(a)所示的树,1 2 0 3 0 4 0 0 0对应如图1(b)所示的树。

tree.jpg

请编写程序用上述方法构建树,并给出树的层次遍历序列。

输入格式:

输入为一组用空格间隔的整数,个数不超过100个,表示带空指针信息的二叉树先根序列。其中空指针信息用0表示

输出格式:

输入为一组整数,每个整数后一个空格,表示该树的层次遍历序列。

输入样例:

1 2 0 3 0 4 0 0 0

输出样例:

1 2 3 4 
#include<bits/stdc++.h>
using namespace std;
int a[101];
vector<vector<int>> v(105);
void creat(){
    int i=0;
    stack<int >s;
    s.push(a[i++]);
    while(!s.empty()){
        if(a[i])s.push(a[i++]);//如果a[i]不为空,继续遍历
        else{
            int l=s.size();
            int t=s.top();
            s.pop();
            i++;
            v[l].push_back(t);
        }
    }
    return ;//
}
int main(){
    int c=0,y;
    while(cin>>y){
        if(y=='\n')break;
        a[c++]=y;
    }
    creat();
    for(int i=0;i<v.size();i++){
        for(int j=0;j<v[i].size();j++){
            cout<<v[i][j]<<' ';
        }
    }
    return 0;
}

列出叶结点 

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

输入格式:

首先第一行给出一个正整数 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 lchild,rchild;
}a[15];
int main(){
    queue<int>q;
    int n;
    int check[15]={0},i,s[15],j=0;
    cin>>n;
    for(i=0;i<n;i++){
        char l,r;
        cin>>l>>r;
        a[i].lchild=l!='-'?l-'0':12;
        a[i].rchild=r!='-'?r-'0':12;
        check[a[i].lchild]=1;
        check[a[i].rchild]=1;
    }
    //寻找根节点,只有根节点不是谁的左右节点,输入的数据没有根节点的值
    for(i=0;i<n;i++){
        if(!check[i])break;
    }
    q.push(i);
    while(!q.empty()){
        int d=q.front();
        q.pop();
        if(d==12)continue;
        if(a[d].lchild==12&&a[d].rchild==12)
            s[j++]=d;
        q.push(a[d].lchild);
        q.push(a[d].rchild);
    }
    cout<<s[0];
    for(i=1;i<j;i++){
        cout<<' '<<s[i];
    }
    return 0;
}

 朋友圈

某学校有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>
//#include<math.h>
int f[30001],n,m;
int fu(int x){
    if(x==f[x])return x;
    return f[x]=fu(f[x]);
}
int main(){
    int z[30001],i,k,x1,x2;
    scanf("%d %d",&n,&m);
    for(i=1;i<=n;i++){
        f[i]=i;
        z[i]=1;
    }
    while(m--){
        scanf("%d %d",&k,&x1);
        for(i=1;i<k;i++){
            scanf("%d",&x2);
            int l1=fu(x1);
            int l2=fu(x2);
            if(l1!=l2){//
                f[l1]=f[l2];
                z[l2]+=z[l1];
            }
            x1=x2;
        }
    }
    int max=0;
    for(i=1;i<=n;i++){
        if(max<z[i])
            max=z[i];
    }
    printf("%d",max);
    return 0;
}

部落 

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

输入格式:

输入在第一行给出一个正整数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;
int f[10005];//!数组的空间!
int fu(int x){
    if(x==f[x])return x;
    return f[x]=fu(f[x]);
}
int main(){
    int n,i,k,t=0,c=0,x1,x2,l1,l2,q;
    stack<int >s;
    cin>>n;
    while(n--){
        scanf("%d %d",&k,&x1);
        if(f[x1]==0){
            t++;
            f[x1]=x1;
            s.push(x1);
        }
        for(i=1;i<k;i++){
            scanf("%d",&x2);
            if(f[x2]==0){
                t++;
                f[x2]=x2;
                s.push(x2);
            }
            f[fu(x1)]=f[fu(x2)];
        }
    }
    while(s.size()){//任选其一
    //for(i=0;i<t;i++){
        int d=s.top();
        if(d==f[d])c++;
        s.pop();
    }
    printf("%d %d\n",t,c);
    scanf("%d",&q);
    while(q--){
        cin>>l1>>l2;
        if(fu(l1)==fu(l2))
            printf("Y\n");
        else{
            printf("N\n");
        }
    }
    return 0;
}

 修理牧场

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要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>
#define o 10000000
int n,a[10001];
int findmin(){
    int i,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(){
    int i,sum=0;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(i=0;i<n-1;i++){
        int x1=findmin();
        delete(x1);
        int x2=findmin();
        delete(x2);
        sum+=x1+x2;
        add(x1+x2);
    }
    printf("%d",sum);
    return 0;
}

哈夫曼树 

哈夫曼树,第一行输入一个数n,表示叶结点的个数。

需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出哈夫曼树的带权路径长度(WPL)。

输入格式:

第一行输入一个数n,第二行输入n个叶结点(叶结点权值不超过1000,2<=n<=1000)。

输出格式:

在一行中输出WPL值。

输入样例:

5
1 2 2 5 9

输出样例:

37
#include<stdio.h>
#define o 10000000
int n,a[10001];
int findmin(){
    int i,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(){
    int i,sum=0;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(i=0;i<n-1;i++){
        int x1=findmin();
        delete(x1);
        int x2=findmin();
        delete(x2);
        sum+=x1+x2;
        add(x1+x2);
    }
    printf("%d",sum);
    return 0;
}

以上作为笔记使用 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值