果子合并 哈夫曼编码

实验三  线性表的基本操作及其应用

一、   实验目的

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

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

二、   实验内容和要求

【问题描述】

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

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

【标准输入】

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

【标准输出】

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

【输入样例】:

2   6

7, 5, 2, 4

5,6,2,9,7

【输出样例】:

35

65

三、   算法设计

1.本题使用的是哈夫曼编码的方法,使得果子数量越小的越早被合并。但每次都要找出数量最小的堆,每次都要遍历一遍时间复杂度比较高,所以使用了最小堆。

2.下面介绍最小堆和哈夫曼编码的过程:

样例:7、5、2、4

首先将这四个数字放入最小堆,数据存放如下:

  

   7      5     5        2          2          2               额,这部分本来是有连线和圈圈的

5      7     7    2   7   5     7    5    4    5

                                4          7

把数据在最小堆中存放好,然后就可以进行哈夫曼编码,过程如下;

从最小堆中拿出一个数据,然后再拿出一个,两者生成一棵树,树的根节点的权值为两者之和,这两个数据分别为左右两个叶节点。不断重复上述过程,当堆中没有数据时则完成了哈夫曼编码:

提出2  :      7         4

        4    5    7    5

提出4  :    5

        7

   将2和4组成一棵树,生成新的根节点,权值为两者之和6。

将6放入最小堆:    5

            7     6

提出5  :        6

         7

提出6  :        7

   将5和6组成一棵树,生成新的根节点,权值为两者之和11。

将11放入最小堆:    7

            11

提出7 :      11

提出11:      空

  将7和11组成一棵树,生成新的根节点,权值为两者之和18。

因为对已经为空,所以结束操作,算出WPL。

                    18

            7      11

                5      6

                    2      4

                WPL=18+11+6=35

四、   调试分析

很庆幸在整个过程中并没有出下过太严重的错误,可能是在一开始的设计上比较正确的原因,虽然完成的很顺利但是那个堆类并不能应用于所有的情境下,且成员函数比较少。

五、   实验结果

六、   总结

  理解和实现中间有很大的差距,因此要多动手,多实现。

七、   源程序(带注释)

#include <iostream>

 

using namespace std;

 

typedef int elemtype;

 

struct node           //定义一个树节点结构体

{

   elemtype date;    //  数据存放

   node *r,*l,*p;    //  分别是右儿子指针,左儿子指针,双亲指针

};

 

class minheap         // 定义一个最小堆,用于排序,时间复杂度较低

{

public:

   minheap()

    {

       length=0;

       capcity=10;

       p=new node[11];

    }

   ~minheap()

    {

       delete []p;

    }

   void putin(node a)

    {

       if(length==capcity)

       {

           capcity=2*capcity;

           node *s=new node[capcity+1];

           for(int i=1;i<=length;i++)

                s[i]=p[i];

           delete []p;

           p=s;

       }

       else

       {

           p[length+1]=a;

           length++;

           int k=length;

           while(k/2>=1)

           {

                if(p[k/2].date<=p[k].date)

                    break;

                else

                {

                    node s1=p[k];

                    p[k]=p[k/2];

                    p[k/2]=s1;

                }

                k=k/2;

           }

       }

 

    }

   node putout()

    {

       node a=p[1];

       p[1]=p[length];

       length--;

       int k=1;

       node s1=p[1];

       while((2*k<=length&&p[2*k].date<p[k].date)||(2*k+1<=length&&p[2*k+1].date<p[k].date))

       {

           if(2*k+1<=length)

           {

               if(p[2*k].date<p[2*k+1].date)

               {

                   if(p[2*k].date<p[k].date)

                   {

                       p[k]=p[2*k];

                       p[2*k]=s1;

                       k=2*k;

                   }

                   else

                    break;

               }

               else

               {

                   if(p[2*k+1].date<p[k].date)

                   {

                       p[k]=p[2*k+1];

                       p[2*k+1]=s1;

                       k=2*k+1;

                   }

                   else

                    break;

               }

 

           }

           else

           {

                if(p[2*k].date<p[k].date)

                {

                    p[k]=p[2*k];

                    p[2*k]=s1;

                    k=2*k;

                }

                else

                    break;

           }

       }

     return a;

    }

   int getlength()

    {

       return length;

    }

private:

   int length;

   int capcity;

   node *p;

};

 

void haha(node *a)      //后序遍历式的进行释放内存

{

   if(a->l!=NULL)

       haha(a->l);

   if(a->r!=NULL)

       haha(a->r);

   //cout<<a->date<<endl;

   delete a;

}

int main()

{

   int m,n;

   cin>>m>>n;

   while(m)

    {

       node a,*head=NULL;    //head指向哈夫曼树的根节点

       minheap hp;

       int sum=0;

       for(int i=0;i<n;i++)

       {

           cin>>a.date;

           if(a.date==0)

                break;

           a.l=NULL;

           a.r=NULL;

           a.p=NULL;

           hp.putin(a);

       }

       if(hp.getlength()==0)

           cout<<"wrong!"<<endl;

       else if(hp.getlength()==1)

           cout<<hp.putout().date<<endl;

       else

       {

           node *p1=NULL,*p2=NULL,*p3=NULL;

           while(hp.getlength())

           {

               p1=new node;

               p2=new node;

               p3=new node;

               *p1=hp.putout();

               *p2=hp.putout();

              p3->date=p1->date+p2->date;

               p1->p=p3;

               p2->p=p3;

               p3->l=p1;

               p3->r=p2;

               sum=sum+p3->date;

               if(hp.getlength()==0)

                {

                    head=p3;

                    break;

                }

               hp.putin(*p3);

           }

           cout<<sum<<endl;

       }

       haha(head);

       m--;

    }

   return 0;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值