二叉树的基本操作及应用

二叉树的基本操作实现

[问题描述]
建立一棵二叉树,试编程实现二叉树的如下基本操作:

  1. 按先序序列构造一棵二叉链表表示的二叉树T;
  2. 对这棵二叉树进行遍历:先序、中序、后序以及层次遍历,分别输出结点的遍历序列;
  3. 求二叉树的深度/结点数目/叶结点数目;(选做)
  4. 将二叉树每个结点的左右子树交换位置。(选做)
    [基本要求]
    从键盘接受输入(先序),以二叉链表作为存储结构,建立二叉树(以先序来建立),
    [测试数据]
    如输入:ABCффDEфGффFффф(其中ф表示空格字符)
ABC  DE G  F   

则输出结果为

先序:ABCDEGF
中序:CBEGDFA
后序:CGEFDBA
层序:ABCDEFG

[选作内容]
采用非递归算法实现二叉树遍历。
CODE:

#include <iostream>
#include <cstdio>
using namespace std;
typedef struct TNode
{
    char data;
    struct TNode *l,*r;
} TNode,*Tree;
void CreatBiTree(Tree &t)
{
    char ch;
    ch=getchar();  //注意字符可能是空格所以不能用cin
    if(ch==' ')
        t=NULL;
    else
    {
        t=new TNode;
        t->data=ch;
        CreatBiTree(t->l);
        CreatBiTree(t->r);
    }
    return;
}
void Preordering(Tree t)
{
    if(t!=NULL)
    {
        cout<<t->data;
        Preordering(t->l);
        Preordering(t->r);
    }
}
void Middleorder(Tree t)
{
    if(t!=NULL)
    {
        Middleorder(t->l);
        cout<<t->data;
        Middleorder(t->r);
    }
}
void Postorder(Tree t)
{
    if(t!=NULL)
    {
        Postorder(t->l);
        Postorder(t->r);
        cout<<t->data;
    }
}
typedef struct QNode
{
    Tree base;
    struct QNode *next;
} QNode,*QueuePtr;
typedef struct
{
    QueuePtr f,r;
} LinkQueue;
void InitQueue(LinkQueue &q)
{
    q.f=q.r=new QNode;
    q.f->next=NULL;
    return;
}
void Qpush(LinkQueue &q,Tree t)
{
    QueuePtr p;
    p=new QNode;
    p->base=t;
    p->next=NULL;
    q.r->next=p;
    q.r=p;
    return;
}
bool Empty(LinkQueue q)
{
    return q.f==q.r;
}
void arrangement(Tree t)
{
    LinkQueue q;
    InitQueue(q);
    if(t)
        Qpush(q,t);
    while(!Empty(q))
    {
        q.f=q.f->next;
        Tree k;
        k=new TNode;
        k=q.f->base;
        cout<<k->data;
        if(k->l)
            Qpush(q,k->l);
        if(k->r)
            Qpush(q,k->r);
    }
    cout<<endl;
    return;
}
int Deap(Tree t)
{
    if(!t)
        return 0;
    int m,n;
    m=Deap(t->l);
    n=Deap(t->r);
    return m>n?m+1:n+1;
}
int Node(Tree t)
{
    if(!t)
        return 0;
    else
        return Node(t->l)+Node(t->r)+1;
}
int Leaf(Tree t)
{
    if(!t)
        return 0;
    else{
        if(!t->l&&!t->r)
            return 1;
        else
            return Leaf(t->l)+Leaf(t->r);
    }
}
void Swap(Tree &t)
{
    Tree root;
    root=t->l;
    t->l=t->r;
    t->r=root;
    if(t->l)
        Swap(t->l);
    if(t->r)
        Swap(t->r);
}
int main()
{
    Tree t;
    CreatBiTree(t);
    cout<<"先序:";
    Preordering(t);
    cout<<endl;
    cout<<"中序:";
    Middleorder(t);
    cout<<endl;
    cout<<"后序:";
    Postorder(t);
    cout<<endl;
    cout<<"层次:";
    arrangement(t);
    cout<<"树的深度:";
    cout<<Deap(t)<<endl;
    cout<<"结点数目:";
    cout<<Node(t)<<endl;
    cout<<"叶结点数目:";
    cout<<Leaf(t)<<endl;
    cout<<"左右子树交换位置后:"<<endl;
    Swap(t);
    cout<<"先序:";
    Preordering(t);
    cout<<endl;
    cout<<"中序:";
    Middleorder(t);
    cout<<endl;
    cout<<"后序:";
    Postorder(t);
    cout<<endl;
    cout<<"层次:";
    arrangement(t);
    return 0;
}

哈夫曼树和哈夫曼编码

[问题描述]
 一电文,有若干个不同字符,要求从终端输入这些不同字符及其出现的频率,然后对这些字符进行哈夫曼编码,并输出。
[测试数据]
利用教材P.139 例5.2中的数据调试程序 (可自己设定测试数据)。
[选作内容]
1、打印出该哈夫曼树
2、若从终端输入任意一段电文(假设仅为26个大小写英文字母),试编程高效地求出该段电文的哈夫曼编码。
提示:如何快速统计不同字符的出现频率
3、译码:将上述1的编码结果还原成电文。
样例输入:

aabbcdeffff

样例输出:

各个字母出现的次数为:
a:2     b:2     c:1     d:1     e:1     f:4

1 a 2 0 0 0
2 b 2 0 0 0
3 c 1 0 0 0
4 d 1 0 0 0
5 e 1 0 0 0
6 f 4 0 0 0
每次连接的结点:
3 4 7
5 1 8
2 7 9
8 6 10
9 10 11

1 a 2 8 0 0
2 b 2 9 0 0
3 c 1 7 0 0
4 d 1 7 0 0
5 e 1 8 0 0
6 f 4 10 0 0
7   2 9 3 4
8   3 10 5 1
9   4 11 2 7
10   7 11 8 6
11   11 0 9 10

Huffman Code:
a:101
b:00
c:010
d:011
e:100
f:11
String Huffman Code:
101101000001001110011111111
写一串由上面Huffman Code组成的编码,输入#结束:
1110001010101100
fecadb
1111
ff
#

CODE:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
struct Huffman
{
    char data;
    int s,w,p,l,r;
};
Huffman h[60];
int b[1000];
void CreatHuffman(int e)
{
    int i,j;
    Huffman m1,m2,m;
    for(j=e; j<=2*e-3; j++)  //一共e个节点,所以要遍历e-1遍
    {
        m1.w=0;
        m2.w=0;
        for(i=1; i<j; i++)  //每次遍历选出两个权值最小的进行建立二叉树
        {
            if(h[i].p==0)
            {
                if(m1.w==0)  //先对m1进行赋值
                {
                    m1=h[i];
                }
                else if(m2.w==0)  //在对m2进行赋值
                {
                    m2=h[i];
                    if(m1.w>m2.w)  //保证m1的权重小于m2的权重。
                    {
                        m=m1;
                        m1=m2;
                        m2=m;
                    }
                }
                else
                {
                    if(m1.w>h[i].w)  //保证m1是最小的
                    {
                        m2=m1;
                        m1=h[i];
                    }
                    else if(m2.w>h[i].w)  //如果不判断,到最后可能m1是最小的,但是m2不一定是次小的
                        m2=h[i];
                }
            }
        }
        cout<<m1.s<<" "<<m2.s<<" "<<j<<endl;  //输出两个最小的结点
        h[j].w=m1.w+m2.w;  //建立新的结点作为两个结点的双亲结点
        h[j].s=j;
        h[j].l=m1.s;
        h[j].r=m2.s;
        h[m1.s].p=j;  //对孩子节点的双亲节赋值
        h[m2.s].p=j;
    }
}
int out(int t,int k)
{
    if(h[t].p==0)  //双亲结点为0则为哈夫曼树的根节点,返回搜索的长度,即字符的哈夫曼编码的长度
        return k;
    if(h[h[t].p].l==t)  //是左孩子就输出0,再看双亲
    {
        b[k]=0;
        out(h[t].p,++k);
    }
    else if(h[h[t].p].r==t)  //是右孩子就输出1,再看双亲
    {
        b[k]=1;
        out(h[t].p,++k);
    }
}
int pop(int i,int n,int t)
{
    while(h[t].l!=0||h[t].r!=0)  //左右孩子都为0那么证明到了叶子节点,输出叶子节点代表的字符
    {
        if(b[i]==0)
        {
            t=h[t].l;
            i++;
        }
        else if(b[i]==1)
        {
            t=h[t].r;
            i++;
        }
    }
    cout<<h[t].data;
    return i;
}
int main()
{
    int a[60];
    string str;
    while(cin>>str)
    {
        memset(a,0,sizeof(a));
        memset(h,0,sizeof(h));
        int i,j;
        for(i=0; i<str.length(); i++)   //将输入的字符串统计各个字符出现的,区分大小写。用一个数组存储,前26个存储小写字母,后26个存储大写字母
        {
            if(str[i]<='z'&&str[i]>='a')
                a[str[i]-'a']++;
            else if(str[i]<='Z'&&str[i]>='A')
                a[str[i]-'A'+26]++;
        }
        int e=1;
        cout<<"各个字母出现的次数为:"<<endl;
        for(i=0; i<26; i++)   //将各个字母出现的次数输出,出现的次数为0就不需要输出了,同时记录次数不为0的字母的个数。将字母出现的次数作为该字母的权重。
        {
            if(a[i]!=0)
            {
                cout<<(char)('a'+i)<<":"<<a[i]<<"\t";
                h[e].w=a[i];
                h[e].s=e;
                h[e++].data=(char)('a'+i);
            }
        }
        cout<<endl;
        for(i=26; i<52; i++)
        {
            if(a[i]!=0)
            {
                cout<<(char)('A'+i-26)<<":"<<a[i]<<"\t";
                h[e].w=a[i];
                h[e].s=e;
                h[e++].data=(char)('A'+i-26);
            }
        }
        cout<<endl;
        for(i=1; i<e; i++)  //输出HT初态,包括节点、字符、权重、双亲节点、左右孩子节点
            cout<<h[i].s<<" "<<h[i].data<<" "<<h[i].w<<" "<<h[i].p<<" "<<h[i].l<<" "<<h[i].r<<endl;
        cout<<"每次连接的结点:"<<endl;  //建立哈夫曼树
        CreatHuffman(e);
        cout<<endl;
        for(i=1; i<=2*e-3; i++)  //输出HT的终态,包括节点、字符、权重、双亲节点、左右孩子节点
            cout<<h[i].s<<" "<<h[i].data<<" "<<h[i].w<<" "<<h[i].p<<" "<<h[i].l<<" "<<h[i].r<<endl;
        cout<<endl;
        cout<<"Huffman Code:"<<endl;  //输出各个字符的哈夫曼编码
        for(i=1; i<e; i++)
        {
            cout<<h[i].data<<":";
            for(int k=out(i,0); k>0; k--)  //通过调用out()函数来获取编码长度,以及对数组赋值
                cout<<b[k-1];
            cout<<endl;
        }
        cout<<"String Huffman Code:"<<endl;  //输出字符串的哈夫曼编码
        for(i=0; i<str.length(); i++)
        {
            for(j=1; j<e; j++)
            {
                if(h[j].data==str[i])  //查找到字符所在位置
                {
                    memset(b,-1,sizeof(b));
                    for(int k=out(j,0); k>0; k--)
                        cout<<b[k-1];
                    break;
                }
            }
        }
        cout<<endl;
        cout<<"写一串由上面Huffman Code组成的编码,输入#结束:"<<endl;  //可以通过输入哈夫曼编码来翻译成字符串
        while(cin>>str)
        {
            if(str[0]=='#')
                break;
            for(i=0; i<str.length(); i++)  //字符数组转成整型数组
            {
                b[i]=str[i]-'0';
            }
            int t;
            for(i=1; i<=2*e-3; i++)  //寻找根节点
            {
                if(h[i].p==0)
                {
                    t=h[i].s;
                    break;
                }
            }
            for(i=0; i<str.length();)  //
            {
                i=pop(i,str.length(),t);
            }
            cout<<endl;
        }
    }
    return 0;
}


寻求最佳判断

[问题描述]
试设计一个算法,用最少的比较,尽快地将N个随机的百分制成绩转换成五级分制.
0~59 ———————————————————— bad
60~69 ———————————————————— pass
70~79 ———————————————————— general
80~89 ———————————————————— good
90~100 ———————————————————— excellent
[设计要求]
输入n个任意的百分制分数,要求输出对应的等级

非标准正确答案
CODE:

#include <iostream>
#include <string>
using namespace std;
struct grade
{
    double data;
    int node,score;
    string str;
};
grade a[1100];
int e;
void per()
{
    cout<<"90~100:";
    cin>>a[e].data;
    a[e].node=e;
    a[e].score=90;
    a[e].str="excellent";
    e++;
    cout<<"80~89:";
    cin>>a[e].data;
    a[e].score=80;
    a[e].str="good";
    e++;
    cout<<"70~79:";
    cin>>a[e].data;
    a[e].score=70;
    a[e].str="general";
    e++;
    cout<<"60~69:";
    cin>>a[e].data;
    a[e].score=60;
    a[e].str="pass";
    e++;
    cout<<"0~59:";
    cin>>a[e].data;
    a[e].score=0;
    a[e].str="bad";
    e++;
}
int main()
{
    cout<<"输入各分数段的百分制:"<<endl;
    e=1;
    per();
    double sum=0;
    int i,t,n;
    for(i=1; i<e; i++)
    {
        sum+=a[i].data;
        if(sum>=0.5)
            break;
    }
    cout<<"以"<<a[i].score<<"为根";
    cout<<"输入任意的百分制分数,输入其他结束:"<<endl;
    while(cin>>n)
    {
        t=i;
        if(n<0||n>100)
            break;
        if(n>a[t].score)
        {
            int j=1;
            while(j<=t)
            {
                if(a[j].score<=n)
                {
                    cout<<a[j].str<<endl;
                    break;
                }
                else
                {
                    j++;
                }
            }
        }
        else
        {
            while(t<=5)
            {
                if(a[t].score<=n)
                {
                    cout<<a[t].str<<endl;
                    break;
                }
                else
                {
                    t++;
                }
            }

        }
    }
    return 0;
}

果子合并

[问题描述]
n堆果子, 每堆果子数量任意,试设计一种最佳方案,将这n堆果子合并为一堆,使得合并工作量最小。
注:规定合并两堆果子的工作量是这两堆果子的数量之和。
[标准输入]
M,N M表示M组测试数据,N表示每组测试数据数量不超过N个,每堆果子数量不超过10000。随后的M行是测试数据。
[标准输出]
M行数据表示对应果子的合并工作量

[输入样例]:

2   6
7, 5, 2, 4
5,6,2,9,7

【输出样例】:

 35
 65

CODE:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct fruit
{
    int w,s;
};
int main()
{
    int n,m;
    while(cin>>m>>n)
    {
        while(m--)
        {
            fruit a[11000];
            memset(a,0,sizeof(a));
            int e=1,i,j;
            char ch=',';
            while(ch==',')
            {
                a[e].s=e;
                cin>>a[e++].w;
                ch=getchar();
            }
            int sum=0;
            fruit m1,m2,m3;
            for(i=e; i<2*e-2; i++)
            {
                cout<<i<<',';
                m1.w=m2.w=-1;
                for(j=1; j<i; j++)
                {
                    if(a[j].s!=-1)
                    {
                        if(m1.w==-1)
                        {
                            m1=a[j];
                        }
                        else if(m2.w==-1)
                        {
                            m2=a[j];
                            if(m1.w>m2.w)
                            {
                                m3=m1;
                                m1=m2;
                                m2=m3;
                            }
                        }
                        else
                        {
                            if(m1.w>=a[j].w)
                            {
                                m2=m1;
                                m1=a[j];
                            }
                            else if(m2.w>=a[j].w)
                                m2=a[j];
                        }
                    }
                }
                a[m1.s].s=-1;
                a[m2.s].s=-1;
                a[i].w=m1.w+m2.w;
                a[i].s=i;
                sum+=a[i].w;
            }
            cout<<sum<<endl;
        }
    }
    return 0;
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

为君倾此杯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值