一颗名叫哈夫曼的树

写在开头——这是一个耗时两周,几度中断,最终还是未完成的代码。
事情的源头是一次上机实验,这是一道选做题:

  设计一个哈夫曼编码、译码系统。对一个 ASCII 编码的文本文件中的字符进行哈夫曼编码,生成编码 文件; 反过来,可将编码文件译码还原为一个文本文件。       (1) 从文件中读入任意一篇英文短文(文件为 ASCII 编码扩展名为 txt) (2) 统计并输出不同字符在文章中出现的频率(空格、换行、标点等也按字符处理); (3) 根据字符频率构造哈夫曼树,并给出每个字符的哈夫曼编码; 

开始的时候我觉得这道题可以做啊,重点不就是哈夫曼树的建立吗,书上的代码白纸黑字。于是我就入坑了。。

从哪里入手呢?嗯,先写一个读写文件的函数吧! 突然我的脑子一片空白,对文件是怎么操作来着,我怎么毫无印象,才反应过来c语言的文件操作早已经忘得精光。

从柜底扒出来大一的红皮书,看了几眼,嗯,就这么回事,so easy。既然要挑战自己,那就不能守旧,同时我也很好奇c++对文件是怎么操作的。于是乎,我就怀着程序猿的使命就是创造世界的满腔热血来回谷歌,万千百度。
说起来惭愧,c++对文件的操作我是掌握了,却是用了一周的时间!期间我还发了我在csdn的第一个博客,就是那个c++对文件的操作。

对文件的读取用的方法取自前一篇博客。文件操作是解决了,可新问题又来了,统计字符。开始我就用两个数组data[ ],weight[ ] ,一个存字符,一个计数,不用想 死路一条。

于是,又专门创建一个类Data 来初步保存从文件读取的字符的种类以及权值。然后是把他们排个序,为下一步建立哈夫曼树做准备。

好了,现在原材料有了,可以开始写哈夫曼树了。可后来我哭了,我才明白算法思想了然于胸和用代码实现是天壤之别。翻开书,恭恭敬敬地看了好几遍代码,又加上我自己

的改造,算是基本完成。树已经建好了,接下来就是对各个字符编码了,没成想这一步是如此的艰难,再一次卡死。这是昨天下午的事了。

开始想用非递归实现加一个辅助栈,因为我一碰见递归就犯迷糊,可是二叉树就是为递归而生的,我只能老老实实的迷失在递归里。还好今天上午把他给解决了。

还剩最后两个问题没解决,把txt文件哈夫曼编码,把编码后的文件按照哈夫曼解码。写到这对于学渣的我已经是不容易了,以后继续努力吧。

也就是说我现在的代码可以把一个txt文件里的字符读取,建成一个哈夫曼树,并且给出各个字符对应的哈夫曼编码。

下面是长篇代码,写的比较简陋,也没能来得及优化。函数都写到类里面了。。。

#include<iostream>
#include<fstream>
#include<string.h>
#define MAX 80
using namespace std;

class Data
{
public:
    char data;
    int weight;
    Data(char d=0,int w=0):data(d),weight(w){}
};

/*----------------哈夫曼树的节点类----------*/
class NodeHuff
{
public:
    NodeHuff* left;
    NodeHuff* right;
    char code[MAX];    //code是哈夫曼编码后的01字符串
    int weight;
    char data;
    NodeHuff(NodeHuff* l=NULL,NodeHuff* r=NULL,int w=0,char c=0):left(l),right(r),weight(w),data(c){}
    ~NodeHuff(){}
};

/*-----------------哈夫曼树类-----------------*/
class Huffmantree
{
private:
    NodeHuff* root;
    int number=0;          //统计字符的种类数目
    char data[MAX];
    int weight[MAX];
public:
    Huffmantree(NodeHuff* r=NULL){root=r;}
    ~Huffmantree()
    {
        deletetree(root);
    }

    NodeHuff* Getroot(){return root;}
    void deletetree(NodeHuff* p)          //删除以p为根的整棵树
    {
        if(p==NULL) return;
        NodeHuff* l,*r;
            l=p->left;
            r=p->right;
        deletetree(l);
        deletetree(r);
        delete l;
        delete r;
    }

    /*--------------建立哈夫曼树---------------*/
    void CreatHuffman()
    {

        NodeHuff* H[MAX];
        for(int i=0;i<MAX;i++)
        {
            H[i]=new NodeHuff;
            H[i]->data=data[i];
            H[i]->weight=weight[i];

        }
        int j=0;
        NodeHuff* p1,*p2,*p,*t;
        for(int i=0;i<MAX;i++)
        {
            t=new NodeHuff;
            p1=H[i];
            p2=H[i+1];
            t->left=p1;
            t->right=p2;
            t->weight=p1->weight+p2->weight;
            p=t;
            j=i+2;
            while(j<MAX&&(p->weight>H[j]->weight))
            {
                H[j-1]=H[j];
                j++;
            }
            H[j-1]=p;
        }
        root=H[number-1];
    }

/*-------------------对文件中的字符计数并且按递增排序-------------------*/
    void countAndSort()
{
    Data cc[MAX];                   //cc[]初步保存从文件读取的字符,后来再对其排序
    char buffer[100];
    ifstream infile("example.txt");
    if(!infile.is_open())
    {
        cout<<"open error"<<endl;return;
    }
    char  q;
    while(infile.good()&&!infile.eof())
    {
        memset(buffer,0,100*sizeof(char));
        infile.getline(buffer,100);
        for(int i=0;i<100;i++)
        {
            q=buffer[i];
            if(q==0) ;
            else
            {
                int o;
                for(o=0;o<MAX;o++)
                {
                    if(cc[o].data==q)
                    {cc[o].weight++;break;}
                }
                if((o==MAX)&&(number!=MAX))
                    {
                        cc[number].data=q;cc[number].weight++;
                        number++;
                    }
            }
        }
    }
    for(int i=number;i<=MAX;i++)
    {
        cc[i].weight=999;
    }
    infile.close();

/*---------------对cc[]排序,将排好序的数据传给data[],weight[]--------------------*/
    int j=0;
    for(int k=0;k<number;k++)
    {
        for(int i=0;i<number;i++)
        {
            if(cc[j].weight>cc[i].weight)
                j=i;
        }
        data[k]=cc[j].data;weight[k]=cc[j].weight;
        cc[j].weight=999;
    }
    cout<<"---------各字符出现次数----------"<<endl<<endl;
    for(int i=0;i<number;i++)
    {
        cout<<data[i]<<"\t"<<weight[i]<<"\t";
    }
    for(int i=number;i<MAX;i++)
    {
        data[i]=0;weight[i]=999;
    }
}

/*---------按照哈夫曼树对字符编码------------*/
    void Encode(NodeHuff* p,char *encode)
    {
        if(!p) return;
         if(!(p->left)&&!(p->right))
        {
            for(int i=0;i<MAX;i++)
                p->code[i]=encode[i];
            cout<<p->data<<"\t"<<p->code<<endl;
            return;}

        NodeHuff*l,*r,*q;
        char lcode[MAX];
        char rcode[MAX];
        l=p->left;int i=0;

       while(encode[i]!='\0')
       {
           lcode[i]=encode[i];
           i++;
       };
      lcode[i]='0';lcode[i+1]='\0';
        r=p->right;i=0;
        while(encode[i]!='\0')
       {
           rcode[i]=encode[i];
           i++;
       };
        rcode[i]='1';rcode[i+1]='\0';

       Encode(l,lcode);
       Encode(r,rcode);
    }

};


int main()
{
    Huffmantree h;
    h.countAndSort();
    h.CreatHuffman();
    char en[MAX]={'\0'};
    cout<<"--------------------"<<endl<<endl;
    h.Encode(h.Getroot(),en);

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值