一颗名叫哈夫曼的树
来源:互联网 发布:mac qq和pc qq同时登录 编辑:程序博客网 时间:2024/04/28 04:42
写在开头——这是一个耗时两周,几度中断,最终还是未完成的代码。
事情的源头是一次上机实验,这是一道选做题:
设计一个哈夫曼编码、译码系统。对一个 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 80using 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;}
- 一颗名叫哈夫曼的树
- 一只名叫鲍勃的流浪猫
- 又一个名叫Google的小孩
- 十年,岁月的名叫恍若隔世
- 编写一个名叫max_list的函数
- 一个名叫草泥马的项目:thefuck
- 昨天刮到一首动听的歌曲----我名叫伊莲
- 曾记得吗,你的祖先名叫炎黄
- 最近和一个名叫iKinect的哥们叫板起来了
- Google酝酿中名叫Fuchsia的神秘新系统
- 有个名叫史太滩的珠宝商带着块鸡蛋大的宝石乘船过江
- 又是一个名叫草泥马的项目:thefuck--修复错误的命令行扩展
- 测试第一个,昨天看见的文章。有一种女人名叫精致 谢谢
- 一款移动应用名叫Hailo-改变人们预订出租车的方式
- 荒岛余生Cast Away——那个名叫威尔森的人
- 有一个女孩 名叫花木兰
- 有一个异人,名叫杜蒂耶尔
- 前端需求中有一类名叫活动
- SysManagerServiceImpl
- hdoj4325Flowers【线段树+离散化】
- lightOJ 1082 - Array Queries 【线段树(求最小值)】
- GreenPlum操作
- hdoj 1420 Prepared for New Acmer 【快速幂】
- 一颗名叫哈夫曼的树
- 1034. Head of a Gang (30)
- 如何在单文档程序中实现TAB键功能
- 翻译作品js
- leetcode之数组指定位置间的数之和
- JavaScript变量命名规则:匈牙利命名法
- 将字符串转化为指定长度的字符串
- Xilinx Vivado & ISE License creating and modification
- 操作系统常考知识总结