数据结构实验报告:二叉树的基本操作及应用

版权声明:转载请留言 https://blog.csdn.net/qq_40744093 https://blog.csdn.net/qq_40744093/article/details/86706379

                       二叉树的基本操作实现&&果子合并

一、实验目的

1、使学生熟练掌握二叉树的逻辑结构和存储结构。

2、熟练掌握二叉树的各种遍历算法。

3、使学生熟练掌握哈夫曼树的生成算法。

4、熟练掌握哈夫曼编码的方法。

二、实验内容

本次实验提供4个题目,难度不等,学生可以根据自己的情况选做,其中题目一是必做题,其它选作!

题目一:二叉树的基本操作实现 (* 必做题)

题目哈夫曼树和哈夫曼编码**

题目寻求最佳判断(***

题目果子合并(***

三、实验前的准备工作

1、掌握树的逻辑结构。

2、掌握二叉树的存储及遍历算法。

3、掌握哈夫曼树的定义及生成算法。

4、掌握哈夫曼编码的方法。

四、实验过程

                             题目一:二叉树的基本操作实现 (* 必做题)

[问题描述]

建立一棵二叉树,试编程实现二叉树的如下基本操作:
1. 按先序序列构造一棵二叉链表表示的二叉树T;
2. 对这棵二叉树进行遍历:先序、中序、后序以及层次遍历,分别输出结点的遍历序列;
3. 求二叉树的深度/结点数目/叶结点数目;(选做)
4. 将二叉树每个结点的左右子树交换位置。(选做)

 [基本要求]

从键盘接受输入(先序),以二叉链表作为存储结构,建立二叉树(以先序来建立)

[输入]

ABCффDEфGффFффф

[输出]

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

[源代码及注释]

#include<iostream>
using namespace std;
typedef struct tree{
    char data;
    struct tree *lchild;
    struct tree *rchild;
}BiTNode,*BiTree;                  //二叉树的结构组成
void CreateBiTree(BiTree &T);      //先序序列构造一棵二叉树
void DLR(BiTree &T);               //先序遍历
void LDR(BiTree &T);               //中序遍历
void LRD(BiTree &T);               //后序遍历
void floor(BiTree &T);             //层次遍历
int Depth(BiTree &T);              //二叉树的深度
int NodeCount(BiTree &T);          //二叉树的结点个数
void Exchange(BiTree &T);          //二叉树每个结点的左右子树交换位置
int main()
{
    BiTree T;
    CreateBiTree(T);
    cout<<"先序遍历,即DLR:";
    DLR(T);
    cout<<endl;
    cout<<"中序遍历,即LDR:";
    LDR(T);
    cout<<endl;
    cout<<"后序遍历,即LRD:";
    LRD(T);
    cout<<endl;
    cout<<"层次遍历:";
    floor(T);
    cout<<endl;
    cout<<"二叉树树的深度:";
    cout<<Depth(T)<<endl;
    cout<<"二叉树的结点数目:";
    cout<<NodeCount(T)<<endl;
    cout<<"---------------------------"<<endl;
    cout<<"交换左右子树结点后"<<endl;
    cout<<"---------------------------"<<endl;
    Exchange(T);
    cout<<"先序遍历,即DLR:";
    DLR(T);
    cout<<endl;
    cout<<"中序遍历,即LDR:";
    LDR(T);
    cout<<endl;
    cout<<"后序遍历,即LRD:";
    LRD(T);
    cout<<endl;
    cout<<"层次遍历:";
    floor(T);
    cout<<endl;
    cout<<"二叉树树的深度:";
    cout<<Depth(T)<<endl;
    cout<<"二叉树的结点数目:";
    cout<<NodeCount(T)<<endl;
    return 0;
}
void CreateBiTree(BiTree &T)
{
    char ch;
    ch=getchar();
    if(ch==' ')
        T=NULL;
    else
    {
        T=new BiTNode;
        T->data=ch;
        CreateBiTree(T->lchild);
        CreateBiTree(T->rchild);
    }
}                                  //递归创建二叉树的结点
void DLR(BiTree &T)
{
    if(T)
    {
        cout<<T->data;
        DLR(T->lchild);
        DLR(T->rchild);
    }
}                                  //递归先序遍历
void LDR(BiTree &T)
{
    if(T)
    {
        LDR(T->lchild);
        cout<<T->data;
        LDR(T->rchild);
    }
}                                  //递归中序遍历
void LRD(BiTree &T)
{
    if(T)
    {
        LRD(T->lchild);
        LRD(T->rchild);
        cout<<T->data;
    }
}                                  //递归后序遍历
void floor(BiTree &T)
{
    if(T)
    {
        cout<<T->data;
        floor(T->lchild);
        floor(T->rchild);
    }
}                                  //递归层次遍历
int Depth(BiTree &T)
{
    if(T==NULL)
        return 0;
    int m=Depth(T->lchild);
    int n=Depth(T->rchild);
    return m>n?m+1:n+1;
}                                   //求二叉树的深度
int NodeCount(BiTree &T)
{
    if(!T)
        return 0;
    return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}                                   //统计二叉树的结点数量
void Exchange(BiTree &T)
{
    if(!T)
        return;
    BiTree temp=T->lchild;
    T->lchild=T->rchild;
    T->rchild=temp;
    Exchange(T->lchild);
    Exchange(T->rchild);
}                                   //二叉树每个结点的左右子树交换位置

[运行结果]

                

                                            题目果子合并(***

[问题描述]

      n堆果子, 每堆果子数量任意,试设计一种最佳方案,将这n堆果子合并为一堆,使得合并工作量最小。

      注:规定合并两堆果子的工作量是这两堆果子的数量之和。

[标准输入]

      M,N 

M表示M组测试数据,N表示每组测试数据数量不超过N个,每堆果子数量不超过10000。随后的M行是测试数据。

[标准输出]

        M行数据表示对应果子的合并工作量

[输入样例]

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

[输出样例]

35
65

[源代码及注释]

#include<iostream>
using namespace std;
typedef struct{
    int weight;                                           //结点的权值
    int parent,lchild,rchild;                             //结点的双亲、左孩子、右孩子的下表
}HTNode,*HuffmanTree;                                     //动态分配数组储存哈夫曼树
void SelectMinNode(HuffmanTree &HT,int k,int &s1,int &s2);//选择两个权值最小结点
void CreatHuffmanTree(HuffmanTree &HT,int n,int w[]);     //哈夫曼树的创建
int CombineWorkload(HuffmanTree &HT);                     //合并工作量
void SelectMinNode(HuffmanTree &HT,int k,int &s1,int &s2)
{
    int Min=1e9;                                          //初始化当前最小权值
    for(int i=1;i<=k;++i)
        if(!HT[i].parent)
        {
            if(HT[i].weight<=Min)
            {
                Min=HT[i].weight;
                s1=i;
            }
        }                                                 //不断更新Min
//从前k个结点找出最小结点
    Min=1e9;                                              //重置权值
    for(int i=1;i<=k;++i)
        if(!HT[i].parent&&i!=s1)
        {
            if(HT[i].weight<=Min)
            {
                Min=HT[i].weight;
                s2=i;
            }
        }                                                 //不断更新Min
//从前k个结点除s1外找出最小结点
}
void CreatHuffmanTree(HuffmanTree &HT,int n,int w[])
{
    if(n<=1)
        return;
    int m=2*n-1;
    HT=new HTNode[m+1];                                   //0号单元未使用
    for(int i=1;i<=n;++i)
    {
        HT[i].weight=w[i];                                //初始化前n个结点
        HT[i].lchild=HT[i].rchild=HT[i].parent=0;
    }
    for(int i=n+1;i<=m;++i)
        HT[i].weight=HT[i].parent=HT[i].rchild=HT[i].lchild=0;
                                                          //初始化从n+1到m的结点
    for(int i=n+1;i<=m;++i)                               //n-次的选择删除合并来创建哈夫曼树
    {
        int s1,s2;
        SelectMinNode(HT,i-1,s1,s2);                      //将最小两个结点的下标赋予s1,s2;
        HT[s1].parent=i;                                  //s1双亲亲赋予i第i编号
        HT[s2].parent=i;                                  //s2双亲亲赋予i第i编号
        HT[i].lchild=s1;                                  //s1成为编号为i的左孩子
        HT[i].rchild=s2;                                  //s2成为编号为i的右孩子
        HT[i].weight=HT[s1].weight+HT[s2].weight;         //合并左右孩子权值
    }
}
int CombineWorkload(HuffmanTree &HT,int n)
{
    int ans=0;
    for(int i=n+1;i<=2*n-1;++i)
        ans+=HT[i].weight;                                //合并从n+1到2*n-1结点的
//所有权值之和
    return ans;                                           //返回最终的权值和
}
int main()
{
    int M,N;
    cin>>M>>N;                                            //M表示M组测试数据
//N表示每组测试数据数量不超过N个
    while(M--)
    {
        int n=1,w[10001];                                 //真实输入的n堆果子
//w数组储存每堆果实的数量
        while(n<=N)
        {
            cin>>w[n];
            char ch=getchar();
            if(ch=='\n')
                break;
            ++n;
        }                                                 //控制输入的格式,得到有效果子数量n
        HuffmanTree HT;
        CreatHuffmanTree(HT,n,w);
        cout<<CombineWorkload(HT,n)<<endl;
    }
    return 0;
}

[运行结果]

                

 

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_40744093/article/details/86706379